shape ops work in progress
M Intersection/DataTypes.cpp M Intersection/QuadraticIntersection_Test.cpp M Intersection/EdgeWalker.cpp M Intersection/LineQuadraticIntersection_Test.cpp M Intersection/LineIntersection_Test.cpp M Intersection/LineIntersection.cpp D Intersection/edge.xcodeproj M Intersection/SimplifyFindTop_Test.cpp M Intersection/DataTypes.h A Intersection/SimplifyRect4x4_Test.cpp M Intersection/CubicIntersection_Test.cpp M Intersection/QuadraticUtilities.h M Intersection/LineCubicIntersection_Test.cpp A Intersection/CurveUtilities.h M Intersection/QuadraticBezierClip.cpp M Intersection/QuadraticBounds.cpp M Intersection/LineUtilities.h M Intersection/Intersection_Tests.cpp M Intersection/Simplify.cpp M Intersection/EdgeWalker_TestUtility.cpp M Intersection/QuadraticUtilities.cpp M Intersection/thingsToDo.txt M Intersection/LineUtilities.cpp M Intersection/CubicUtilities.h M Intersection/SimplifyFindNext_Test.cpp M Intersection/Intersection_Tests.h M Intersection/CubicBezierClip.cpp M Intersection/ActiveEdge_Test.cpp M Intersection/CubicBounds.cpp M Intersection/Simplify.h M Intersection/SimplifyNew_Test.cpp M Intersection/EdgeWalker_Test.h M Intersection/CubicUtilities.cpp M Intersection/op.htm M Intersection/ConvexHull.cpp D Intersection/RectUtilities.cpp M Intersection/SimplifyAddIntersectingTs_Test.cpp git-svn-id: http://skia.googlecode.com/svn/trunk@4429 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
0985c558fc
commit
8dcf114db9
@ -1,12 +1,4 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "Intersections.h"
|
||||
#include "LineIntersection.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "ShapeOps.h"
|
||||
#include "TSearch.h"
|
||||
#include "Simplify.h"
|
||||
|
||||
namespace UnitTest {
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "IntersectionUtilities.h"
|
||||
|
||||
/* Given a cubic, find the convex hull described by the end and control points.
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "LineParameters.h"
|
||||
#include <algorithm> // used for std::swap
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Extrema.h"
|
||||
|
||||
static int isBoundedByEndPoints(double a, double b, double c, double d)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "CubicIntersection_TestData.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "Intersections.h"
|
||||
|
@ -74,3 +74,75 @@ int cubicRoots(double A, double B, double C, double D, double t[3]) {
|
||||
}
|
||||
return (int)(roots - t);
|
||||
}
|
||||
|
||||
// from http://www.cs.sunysb.edu/~qin/courses/geometry/4.pdf
|
||||
// c(t) = a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3
|
||||
// c'(t) = -3a(1-t)^2 + 3b((1-t)^2 - 2t(1-t)) + 3c(2t(1-t) - t^2) + 3dt^2
|
||||
// = 3(b-a)(1-t)^2 + 6(c-b)t(1-t) + 3(d-c)t^2
|
||||
double derivativeAtT(const double* cubic, double t) {
|
||||
double one_t = 1 - t;
|
||||
double a = cubic[0];
|
||||
double b = cubic[2];
|
||||
double c = cubic[4];
|
||||
double d = cubic[6];
|
||||
return (b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t;
|
||||
}
|
||||
|
||||
// same as derivativeAtT
|
||||
// which is more accurate? which is faster?
|
||||
double derivativeAtT_2(const double* cubic, double t) {
|
||||
double a = cubic[2] - cubic[0];
|
||||
double b = cubic[4] - 2 * cubic[2] + cubic[0];
|
||||
double c = cubic[6] + 3 * (cubic[2] - cubic[4]) - cubic[0];
|
||||
return c * c * t * t + 2 * b * t + a;
|
||||
}
|
||||
|
||||
void dxdy_at_t(const Cubic& cubic, double t, double& dx, double& dy) {
|
||||
if (&dx) {
|
||||
dx = derivativeAtT(&cubic[0].x, t);
|
||||
}
|
||||
if (&dy) {
|
||||
dy = derivativeAtT(&cubic[0].y, t);
|
||||
}
|
||||
}
|
||||
|
||||
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath) {
|
||||
double dy = cubic[index].y - cubic[zero].y;
|
||||
double dx = cubic[index].x - cubic[zero].x;
|
||||
if (approximately_equal(dy, 0)) {
|
||||
if (approximately_equal(dx, 0)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(rotPath, cubic, sizeof(Cubic));
|
||||
return true;
|
||||
}
|
||||
for (int index = 0; index < 4; ++index) {
|
||||
rotPath[index].x = cubic[index].x * dx + cubic[index].y * dy;
|
||||
rotPath[index].y = cubic[index].y * dx - cubic[index].x * dy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double secondDerivativeAtT(const double* cubic, double t) {
|
||||
double a = cubic[0];
|
||||
double b = cubic[2];
|
||||
double c = cubic[4];
|
||||
double d = cubic[6];
|
||||
return (c - 2 * b + a) * (1 - t) + (d - 2 * c + b) * t;
|
||||
}
|
||||
|
||||
void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
double one_t2 = one_t * one_t;
|
||||
double a = one_t2 * one_t;
|
||||
double b = 3 * one_t2 * t;
|
||||
double t2 = t * t;
|
||||
double c = 3 * one_t * t2;
|
||||
double d = t2 * t;
|
||||
if (&x) {
|
||||
x = a * cubic[0].x + b * cubic[1].x + c * cubic[2].x + d * cubic[3].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = a * cubic[0].y + b * cubic[1].y + c * cubic[2].y + d * cubic[3].y;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,12 @@
|
||||
#include "DataTypes.h"
|
||||
|
||||
double cube_root(double x);
|
||||
void coefficients(const double* cubic, double& A, double& B, double& C, double& D);
|
||||
int cubicRoots(double A, double B, double C, double D, double t[3]);
|
||||
double derivativeAtT(const double* cubic, double t);
|
||||
// competing version that should produce same results
|
||||
double derivativeAtT_2(const double* cubic, double t);
|
||||
void dxdy_at_t(const Cubic& , double t, double& x, double& y);
|
||||
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath);
|
||||
double secondDerivativeAtT(const double* cubic, double t);
|
||||
void xy_at_t(const Cubic& , double t, double& x, double& y);
|
||||
|
15
experimental/Intersection/CurveUtilities.h
Normal file
15
experimental/Intersection/CurveUtilities.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef CurveUtilities_DEFINE
|
||||
#define CurveUtilities_DEFINE
|
||||
|
||||
#include "CubicUtilities.h"
|
||||
#include "LineUtilities.h"
|
||||
#include "QuadraticUtilities.h"
|
||||
|
||||
#endif
|
@ -21,115 +21,6 @@ const double SquaredEpsilon = PointEpsilon * PointEpsilon;
|
||||
|
||||
const int UlpsEpsilon = 16;
|
||||
|
||||
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath) {
|
||||
double dy = cubic[index].y - cubic[zero].y;
|
||||
double dx = cubic[index].x - cubic[zero].x;
|
||||
if (approximately_equal(dy, 0)) {
|
||||
if (approximately_equal(dx, 0)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(rotPath, cubic, sizeof(Cubic));
|
||||
return true;
|
||||
}
|
||||
for (int index = 0; index < 4; ++index) {
|
||||
rotPath[index].x = cubic[index].x * dx + cubic[index].y * dy;
|
||||
rotPath[index].y = cubic[index].y * dx - cubic[index].x * dy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double t_at(const _Line& line, const _Point& pt) {
|
||||
double dx = line[1].x - line[0].x;
|
||||
double dy = line[1].y - line[0].y;
|
||||
if (fabs(dx) > fabs(dy)) {
|
||||
if (approximately_zero(dx)) {
|
||||
return 0;
|
||||
}
|
||||
return (pt.x - line[0].x) / dx;
|
||||
}
|
||||
if (approximately_zero(dy)) {
|
||||
return 0;
|
||||
}
|
||||
return (pt.y - line[0].y) / dy;
|
||||
}
|
||||
|
||||
static void setMinMax(double x, int flags, double& minX, double& maxX) {
|
||||
if (minX > x && (flags & (kFindTopMin | kFindBottomMin))) {
|
||||
minX = x;
|
||||
}
|
||||
if (maxX < x && (flags & (kFindTopMax | kFindBottomMax))) {
|
||||
maxX = x;
|
||||
}
|
||||
}
|
||||
|
||||
void x_at(const _Point& p1, const _Point& p2, double top, double bottom,
|
||||
int flags, double& minX, double& maxX) {
|
||||
if (approximately_equal(p1.y, p2.y)) {
|
||||
// It should be OK to bail early in this case. There's another edge
|
||||
// which shares this end point which can intersect without failing to
|
||||
// have a slope ... maybe
|
||||
return;
|
||||
}
|
||||
|
||||
// p2.x is always greater than p1.x -- the part of points (p1, p2) are
|
||||
// moving from the start of the cubic towards its end.
|
||||
// if p1.y < p2.y, minX can be affected
|
||||
// if p1.y > p2.y, maxX can be affected
|
||||
double slope = (p2.x - p1.x) / (p2.y - p1.y);
|
||||
int topFlags = flags & (kFindTopMin | kFindTopMax);
|
||||
if (topFlags && (top <= p1.y && top >= p2.y
|
||||
|| top >= p1.y && top <= p2.y)) {
|
||||
double x = p1.x + (top - p1.y) * slope;
|
||||
setMinMax(x, topFlags, minX, maxX);
|
||||
}
|
||||
int bottomFlags = flags & (kFindBottomMin | kFindBottomMax);
|
||||
if (bottomFlags && (bottom <= p1.y && bottom >= p2.y
|
||||
|| bottom >= p1.y && bottom <= p2.y)) {
|
||||
double x = p1.x + (bottom - p1.y) * slope;
|
||||
setMinMax(x, bottomFlags, minX, maxX);
|
||||
}
|
||||
}
|
||||
|
||||
void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
double one_t2 = one_t * one_t;
|
||||
double a = one_t2 * one_t;
|
||||
double b = 3 * one_t2 * t;
|
||||
double t2 = t * t;
|
||||
double c = 3 * one_t * t2;
|
||||
double d = t2 * t;
|
||||
if (&x) {
|
||||
x = a * cubic[0].x + b * cubic[1].x + c * cubic[2].x + d * cubic[3].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = a * cubic[0].y + b * cubic[1].y + c * cubic[2].y + d * cubic[3].y;
|
||||
}
|
||||
}
|
||||
|
||||
void xy_at_t(const _Line& line, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
if (&x) {
|
||||
x = one_t * line[0].x + t * line[1].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = one_t * line[0].y + t * line[1].y;
|
||||
}
|
||||
}
|
||||
|
||||
void xy_at_t(const Quadratic& quad, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
double a = one_t * one_t;
|
||||
double b = 2 * one_t * t;
|
||||
double c = t * t;
|
||||
if (&x) {
|
||||
x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
|
||||
union Float_t
|
||||
{
|
||||
|
@ -168,20 +168,4 @@ struct QuadraticPair {
|
||||
_Point pts[5];
|
||||
};
|
||||
|
||||
enum x_at_flags {
|
||||
kFindTopMin = 1,
|
||||
kFindTopMax = 2,
|
||||
kFindBottomMin = 4,
|
||||
kFindBottomMax = 8
|
||||
};
|
||||
|
||||
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath);
|
||||
double t_at(const _Line&, const _Point& );
|
||||
void x_at(const _Point& p1, const _Point& p2, double minY, double maxY,
|
||||
int flags, double& tMin, double& tMax);
|
||||
void xy_at_t(const Cubic& , double t, double& x, double& y);
|
||||
void xy_at_t(const _Line& , double t, double& x, double& y);
|
||||
void xy_at_t(const Quadratic& , double t, double& x, double& y);
|
||||
|
||||
|
||||
#endif // __DataTypes_h__
|
||||
|
@ -5,15 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "CurveIntersection.h"
|
||||
#include "Intersections.h"
|
||||
#include "LineIntersection.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "ShapeOps.h"
|
||||
#include "TSearch.h"
|
||||
#include "Simplify.h"
|
||||
|
||||
#undef SkASSERT
|
||||
#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
|
||||
|
@ -15,6 +15,9 @@ extern bool drawAsciiPaths(const SkPath& one, const SkPath& two,
|
||||
extern void showPath(const SkPath& path, const char* str = NULL);
|
||||
extern bool testSimplify(const SkPath& path, bool fill, SkPath& out,
|
||||
SkBitmap& bitmap, SkCanvas* canvas = 0);
|
||||
extern bool testSimplifyx(const SkPath& path, SkPath& out,
|
||||
SkBitmap& bitmap, SkCanvas* canvas = 0);
|
||||
extern bool testSimplifyx(const SkPath& path);
|
||||
|
||||
struct State4 {
|
||||
State4();
|
||||
|
@ -60,7 +60,7 @@ static int pathsDrawTheSame(const SkPath& one, const SkPath& two,
|
||||
int bitWidth = SkScalarCeil(larger.width()) + 2;
|
||||
int bitHeight = SkScalarCeil(larger.height()) + 2;
|
||||
if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) {
|
||||
if (bits.width() >= 200) {
|
||||
if (bits.width() >= 200 && false) {
|
||||
SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight);
|
||||
}
|
||||
bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
|
||||
@ -192,10 +192,10 @@ int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
|
||||
const SkRect& bounds2 = two.getBounds();
|
||||
SkRect larger = bounds1;
|
||||
larger.join(bounds2);
|
||||
SkScalar xScale = std::max(80.0f / larger.width(), 1.0f);
|
||||
SkScalar yScale = std::max(60.0f / larger.height(), 1.0f);
|
||||
SkScalar xScale = std::max(32.0f / larger.width(), 1.0f);
|
||||
SkScalar yScale = std::max(24.0f / larger.height(), 1.0f);
|
||||
errors = scaledDrawTheSame(one, two, xScale, yScale, false, bitmap, canvas);
|
||||
if (errors > 50) {
|
||||
if (errors > 5) {
|
||||
scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas);
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
|
||||
SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
|
||||
max = errors;
|
||||
}
|
||||
const int MAX_ERRORS = 100;
|
||||
const int MAX_ERRORS = 20;
|
||||
if (errors > MAX_ERRORS) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
|
||||
if (errors > MAX_ERRORS && gComparePathsAssert) {
|
||||
showPath(one);
|
||||
@ -256,6 +256,31 @@ bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap,
|
||||
return comparePaths(path, out, bitmap, canvas) == 0;
|
||||
}
|
||||
|
||||
bool testSimplifyx(const SkPath& path, SkPath& out, SkBitmap& bitmap,
|
||||
SkCanvas* canvas) {
|
||||
if (gShowPath) {
|
||||
showPath(path);
|
||||
}
|
||||
simplifyx(path, out);
|
||||
if (!gComparePaths) {
|
||||
return true;
|
||||
}
|
||||
return comparePaths(path, out, bitmap, canvas) == 0;
|
||||
}
|
||||
|
||||
bool testSimplifyx(const SkPath& path) {
|
||||
if (false) {
|
||||
showPath(path);
|
||||
}
|
||||
SkPath out;
|
||||
simplifyx(path, out);
|
||||
if (false) {
|
||||
return true;
|
||||
}
|
||||
SkBitmap bitmap;
|
||||
return comparePaths(path, out, bitmap, 0) == 0;
|
||||
}
|
||||
|
||||
State4::State4() {
|
||||
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100);
|
||||
bitmap.allocPixels();
|
||||
|
@ -2,12 +2,12 @@
|
||||
#include "Intersection_Tests.h"
|
||||
|
||||
void cubecode_test(int test);
|
||||
void testSimplify();
|
||||
|
||||
#define TEST_QUADS_FIRST 0
|
||||
|
||||
void Intersection_Tests() {
|
||||
SimplifyNew_Test();
|
||||
Simplify4x4RectsThreaded_Test();
|
||||
SimplifyFindNext_Test();
|
||||
SimplifyFindTop_Test();
|
||||
SimplifyAngle_Test();
|
||||
|
@ -28,6 +28,7 @@ void SimplifyQuadralateralPaths_Test();
|
||||
void SimplifyQuadraticPaths_Test();
|
||||
void Simplify4x4QuadralateralsThreaded_Test();
|
||||
void Simplify4x4QuadraticsThreaded_Test();
|
||||
void Simplify4x4RectsThreaded_Test();
|
||||
void SimplifyRectangularPaths_Test();
|
||||
void QuadraticBezierClip_Test();
|
||||
void QuadraticCoincidence_Test();
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "Intersections.h"
|
||||
#include "LineUtilities.h"
|
||||
#include "TestUtilities.h"
|
||||
|
||||
struct lineCubic {
|
||||
|
@ -39,6 +39,7 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
|
||||
aPtr = &a[0].y;
|
||||
bPtr = &b[0].y;
|
||||
}
|
||||
#if 0 // sorting edges fails to preserve original direction
|
||||
double aMin = aPtr[0];
|
||||
double aMax = aPtr[2];
|
||||
double bMin = bPtr[0];
|
||||
@ -62,6 +63,27 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
|
||||
bRange[!bIn] = aMax >= bMax ? 1 : (aMax - bMin) / (bMax - bMin);
|
||||
}
|
||||
return 1 + ((aRange[0] != aRange[1]) || (bRange[0] != bRange[1]));
|
||||
#else
|
||||
assert(aRange);
|
||||
assert(bRange);
|
||||
double a0 = aPtr[0];
|
||||
double a1 = aPtr[2];
|
||||
double b0 = bPtr[0];
|
||||
double b1 = bPtr[2];
|
||||
double at0 = (a0 - b0) / (a0 - a1);
|
||||
double at1 = (a0 - b1) / (a0 - a1);
|
||||
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
|
||||
return 0;
|
||||
}
|
||||
aRange[0] = std::max(std::min(at0, 1.0), 0.0);
|
||||
aRange[1] = std::max(std::min(at1, 1.0), 0.0);
|
||||
int bIn = (a0 - a1) * (b0 - b1) < 0;
|
||||
bRange[bIn] = std::max(std::min((b0 - a0) / (b0 - b1), 1.0), 0.0);
|
||||
bRange[!bIn] = std::max(std::min((b0 - a1) / (b0 - b1), 1.0), 0.0);
|
||||
bool second = fabs(aRange[0] - aRange[1]) > FLT_EPSILON;
|
||||
assert((fabs(bRange[0] - bRange[1]) <= FLT_EPSILON) ^ second);
|
||||
return 1 + second;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
double ab0y = a[0].y - b[0].y;
|
||||
@ -140,6 +162,7 @@ int horizontalIntersect(const _Line& line, double left, double right,
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
#if 0 // sorting edges fails to preserve original direction
|
||||
double lineL = line[0].x;
|
||||
double lineR = line[1].x;
|
||||
if (lineL > lineR) {
|
||||
@ -159,6 +182,30 @@ int horizontalIntersect(const _Line& line, double left, double right,
|
||||
intersections.fT[0][1] = (overlapR - line[0].x) / (line[1].x - line[0].x);
|
||||
intersections.fT[1][1] = (overlapR - left) / (right - left);
|
||||
}
|
||||
#else
|
||||
double a0 = line[0].x;
|
||||
double a1 = line[1].x;
|
||||
double b0 = flipped ? right : left;
|
||||
double b1 = flipped ? left : right;
|
||||
// FIXME: share common code below
|
||||
double at0 = (a0 - b0) / (a0 - a1);
|
||||
double at1 = (a0 - b1) / (a0 - a1);
|
||||
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
|
||||
return 0;
|
||||
}
|
||||
intersections.fT[0][0] = std::max(std::min(at0, 1.0), 0.0);
|
||||
intersections.fT[0][1] = std::max(std::min(at1, 1.0), 0.0);
|
||||
int bIn = (a0 - a1) * (b0 - b1) < 0;
|
||||
intersections.fT[1][bIn] = std::max(std::min((b0 - a0) / (b0 - b1),
|
||||
1.0), 0.0);
|
||||
intersections.fT[1][!bIn] = std::max(std::min((b0 - a1) / (b0 - b1),
|
||||
1.0), 0.0);
|
||||
bool second = fabs(intersections.fT[0][0] - intersections.fT[0][1])
|
||||
> FLT_EPSILON;
|
||||
assert((fabs(intersections.fT[1][0] - intersections.fT[1][1])
|
||||
<= FLT_EPSILON) ^ second);
|
||||
return 1 + second;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (flipped) {
|
||||
@ -204,6 +251,7 @@ int verticalIntersect(const _Line& line, double top, double bottom,
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
#if 0 // sorting edges fails to preserve original direction
|
||||
double lineT = line[0].y;
|
||||
double lineB = line[1].y;
|
||||
if (lineT > lineB) {
|
||||
@ -223,6 +271,30 @@ int verticalIntersect(const _Line& line, double top, double bottom,
|
||||
intersections.fT[0][1] = (overlapB - line[0].y) / (line[1].y - line[0].y);
|
||||
intersections.fT[1][1] = (overlapB - top) / (bottom - top);
|
||||
}
|
||||
#else
|
||||
double a0 = line[0].y;
|
||||
double a1 = line[1].y;
|
||||
double b0 = flipped ? bottom : top;
|
||||
double b1 = flipped ? top : bottom;
|
||||
// FIXME: share common code above
|
||||
double at0 = (a0 - b0) / (a0 - a1);
|
||||
double at1 = (a0 - b1) / (a0 - a1);
|
||||
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
|
||||
return 0;
|
||||
}
|
||||
intersections.fT[0][0] = std::max(std::min(at0, 1.0), 0.0);
|
||||
intersections.fT[0][1] = std::max(std::min(at1, 1.0), 0.0);
|
||||
int bIn = (a0 - a1) * (b0 - b1) < 0;
|
||||
intersections.fT[1][bIn] = std::max(std::min((b0 - a0) / (b0 - b1),
|
||||
1.0), 0.0);
|
||||
intersections.fT[1][!bIn] = std::max(std::min((b0 - a1) / (b0 - b1),
|
||||
1.0), 0.0);
|
||||
bool second = fabs(intersections.fT[0][0] - intersections.fT[0][1])
|
||||
> FLT_EPSILON;
|
||||
assert((fabs(intersections.fT[1][0] - intersections.fT[1][1])
|
||||
<= FLT_EPSILON) ^ second);
|
||||
return 1 + second;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (flipped) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "CurveUtilities.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "LineIntersection.h"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "Intersections.h"
|
||||
#include "LineUtilities.h"
|
||||
#include "TestUtilities.h"
|
||||
|
||||
struct lineQuad {
|
||||
|
@ -58,3 +58,64 @@ float isLeft( _Point P0, _Point P1, _Point P2 )
|
||||
}
|
||||
#endif
|
||||
|
||||
double t_at(const _Line& line, const _Point& pt) {
|
||||
double dx = line[1].x - line[0].x;
|
||||
double dy = line[1].y - line[0].y;
|
||||
if (fabs(dx) > fabs(dy)) {
|
||||
if (approximately_zero(dx)) {
|
||||
return 0;
|
||||
}
|
||||
return (pt.x - line[0].x) / dx;
|
||||
}
|
||||
if (approximately_zero(dy)) {
|
||||
return 0;
|
||||
}
|
||||
return (pt.y - line[0].y) / dy;
|
||||
}
|
||||
|
||||
static void setMinMax(double x, int flags, double& minX, double& maxX) {
|
||||
if (minX > x && (flags & (kFindTopMin | kFindBottomMin))) {
|
||||
minX = x;
|
||||
}
|
||||
if (maxX < x && (flags & (kFindTopMax | kFindBottomMax))) {
|
||||
maxX = x;
|
||||
}
|
||||
}
|
||||
|
||||
void x_at(const _Point& p1, const _Point& p2, double top, double bottom,
|
||||
int flags, double& minX, double& maxX) {
|
||||
if (approximately_equal(p1.y, p2.y)) {
|
||||
// It should be OK to bail early in this case. There's another edge
|
||||
// which shares this end point which can intersect without failing to
|
||||
// have a slope ... maybe
|
||||
return;
|
||||
}
|
||||
|
||||
// p2.x is always greater than p1.x -- the part of points (p1, p2) are
|
||||
// moving from the start of the cubic towards its end.
|
||||
// if p1.y < p2.y, minX can be affected
|
||||
// if p1.y > p2.y, maxX can be affected
|
||||
double slope = (p2.x - p1.x) / (p2.y - p1.y);
|
||||
int topFlags = flags & (kFindTopMin | kFindTopMax);
|
||||
if (topFlags && (top <= p1.y && top >= p2.y
|
||||
|| top >= p1.y && top <= p2.y)) {
|
||||
double x = p1.x + (top - p1.y) * slope;
|
||||
setMinMax(x, topFlags, minX, maxX);
|
||||
}
|
||||
int bottomFlags = flags & (kFindBottomMin | kFindBottomMax);
|
||||
if (bottomFlags && (bottom <= p1.y && bottom >= p2.y
|
||||
|| bottom >= p1.y && bottom <= p2.y)) {
|
||||
double x = p1.x + (bottom - p1.y) * slope;
|
||||
setMinMax(x, bottomFlags, minX, maxX);
|
||||
}
|
||||
}
|
||||
|
||||
void xy_at_t(const _Line& line, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
if (&x) {
|
||||
x = one_t * line[0].x + t * line[1].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = one_t * line[0].y + t * line[1].y;
|
||||
}
|
||||
}
|
||||
|
@ -2,3 +2,17 @@
|
||||
|
||||
bool implicitLine(const _Line& line, double& slope, double& axisIntercept);
|
||||
int reduceOrder(const _Line& line, _Line& reduced);
|
||||
|
||||
double t_at(const _Line&, const _Point& );
|
||||
void xy_at_t(const _Line& , double t, double& x, double& y);
|
||||
|
||||
enum x_at_flags {
|
||||
kFindTopMin = 1,
|
||||
kFindTopMax = 2,
|
||||
kFindBottomMin = 4,
|
||||
kFindBottomMax = 8
|
||||
};
|
||||
|
||||
void x_at(const _Point& p1, const _Point& p2, double minY, double maxY,
|
||||
int flags, double& tMin, double& tMax);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "LineParameters.h"
|
||||
#include <algorithm> // used for std::swap
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Extrema.h"
|
||||
|
||||
static int isBoundedByEndPoints(double a, double b, double c)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "Intersections.h"
|
||||
#include "QuadraticIntersection_TestData.h"
|
||||
|
@ -25,3 +25,28 @@ int quadraticRoots(double A, double B, double C, double t[2]) {
|
||||
}
|
||||
return foundRoots;
|
||||
}
|
||||
|
||||
void dxdy_at_t(const Quadratic& quad, double t, double& x, double& y) {
|
||||
double a = t - 1;
|
||||
double b = 1 - 2 * t;
|
||||
double c = t;
|
||||
if (&x) {
|
||||
x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
|
||||
}
|
||||
}
|
||||
|
||||
void xy_at_t(const Quadratic& quad, double t, double& x, double& y) {
|
||||
double one_t = 1 - t;
|
||||
double a = one_t * one_t;
|
||||
double b = 2 * one_t * t;
|
||||
double c = t * t;
|
||||
if (&x) {
|
||||
x = a * quad[0].x + b * quad[1].x + c * quad[2].x;
|
||||
}
|
||||
if (&y) {
|
||||
y = a * quad[0].y + b * quad[1].y + c * quad[2].y;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
#include "DataTypes.h"
|
||||
|
||||
void dxdy_at_t(const Quadratic& , double t, double& x, double& y);
|
||||
|
||||
/* Parameterization form, given A*t*t + 2*B*t*(1-t) + C*(1-t)*(1-t)
|
||||
*
|
||||
* a = A - 2*B + C
|
||||
@ -14,3 +18,5 @@ inline void set_abc(const double* quad, double& a, double& b, double& c) {
|
||||
}
|
||||
|
||||
int quadraticRoots(double A, double B, double C, double t[2]);
|
||||
|
||||
void xy_at_t(const Quadratic& , double t, double& x, double& y);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "CurveIntersection.h"
|
||||
#include "CurveUtilities.h"
|
||||
#include "Intersections.h"
|
||||
#include "LineIntersection.h"
|
||||
#include "LineParameters.h"
|
||||
|
@ -87,7 +87,7 @@ static void testPath(const SkPath& path, const SkPoint* pts1, SkPath::Verb c1Typ
|
||||
SimplifyAddIntersectingTsTest::Contour& c1 = contour[0];
|
||||
SimplifyAddIntersectingTsTest::Contour& c2 = contour[1];
|
||||
addIntersectTs(&c1, &c2);
|
||||
bool c1Intersected = c1.fSegments[0].intersected();
|
||||
bool c1Intersected = c1.segments()[0].intersected();
|
||||
// bool c2Intersected = c2.fSegments[0].intersected();
|
||||
#if DEBUG_DUMP
|
||||
SkDebugf("%s %s (%1.9g,%1.9g %1.9g,%1.9g) %s %s (%1.9g,%1.9g %1.9g,%1.9g)\n",
|
||||
|
@ -5,6 +5,8 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#define DEBUG_TEST 1
|
||||
|
||||
#include "Simplify.h"
|
||||
|
||||
namespace SimplifyFindNextTest {
|
||||
@ -27,12 +29,12 @@ static const SimplifyFindNextTest::Segment* testCommon(
|
||||
addIntersectTs(contourList[1], contourList[1]);
|
||||
}
|
||||
fixOtherTIndex(contourList);
|
||||
SimplifyFindNextTest::Segment& segment = contours[0].fSegments[0];
|
||||
SimplifyFindNextTest::Segment& segment = contours[0].debugSegments()[0];
|
||||
SkPoint pts[2];
|
||||
pts[0] = segment.xyAtT(&segment.span(endIndex));
|
||||
int nextStart, nextEnd;
|
||||
SimplifyFindNextTest::Segment* next = segment.findNext(winding,
|
||||
startIndex, endIndex, nextStart, nextEnd);
|
||||
startIndex, endIndex, nextStart, nextEnd, true);
|
||||
pts[1] = next->xyAtT(&next->span(nextStart));
|
||||
SkASSERT(pts[0] == pts[1]);
|
||||
return next;
|
||||
|
@ -27,8 +27,8 @@ static const SimplifyFindTopTest::Segment* testCommon(
|
||||
addIntersectTs(contourList[1], contourList[1]);
|
||||
}
|
||||
fixOtherTIndex(contourList);
|
||||
SimplifyFindTopTest::Segment* topStart = findTopContour(contourList,
|
||||
contourList.count());
|
||||
SimplifyFindTopTest::Contour* top;
|
||||
SimplifyFindTopTest::Segment* topStart = findTopContour(contourList, top);
|
||||
const SimplifyFindTopTest::Segment* topSegment = topStart->findTop(index,
|
||||
end);
|
||||
return topSegment;
|
||||
|
@ -5,29 +5,9 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Simplify.h"
|
||||
|
||||
namespace SimplifyNewTest {
|
||||
|
||||
#include "Simplify.cpp"
|
||||
|
||||
} // end of SimplifyNewTest namespace
|
||||
|
||||
#include "EdgeWalker_Test.h"
|
||||
#include "Intersection_Tests.h"
|
||||
|
||||
static bool testSimplifyx(const SkPath& path) {
|
||||
if (false) {
|
||||
showPath(path);
|
||||
}
|
||||
SkPath out;
|
||||
simplifyx(path, out);
|
||||
if (false) {
|
||||
return true;
|
||||
}
|
||||
SkBitmap bitmap;
|
||||
return comparePaths(path, out, bitmap, 0) == 0;
|
||||
}
|
||||
#include "ShapeOps.h"
|
||||
|
||||
static void testLine1() {
|
||||
SkPath path, simple;
|
||||
@ -146,17 +126,228 @@ static void testLine9() {
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine10() {
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(4,4);
|
||||
path.lineTo(2,2);
|
||||
path.close();
|
||||
path.moveTo(2,1);
|
||||
path.lineTo(3,4);
|
||||
path.lineTo(6,1);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void (*tests[])() = {
|
||||
testLine1,
|
||||
testLine2,
|
||||
testLine3,
|
||||
testLine4,
|
||||
testLine5,
|
||||
testLine6,
|
||||
testLine7,
|
||||
testLine8,
|
||||
testLine9
|
||||
static void testLine10a() {
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(8,4);
|
||||
path.lineTo(4,0);
|
||||
path.close();
|
||||
path.moveTo(2,2);
|
||||
path.lineTo(3,3);
|
||||
path.lineTo(4,2);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void addCWContainer(SkPath& path) {
|
||||
path.moveTo(6,4);
|
||||
path.lineTo(0,4);
|
||||
path.lineTo(3,1);
|
||||
path.close();
|
||||
}
|
||||
|
||||
static void addCCWContainer(SkPath& path) {
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(6,4);
|
||||
path.lineTo(3,1);
|
||||
path.close();
|
||||
}
|
||||
|
||||
static void addCWContents(SkPath& path) {
|
||||
path.moveTo(2,3);
|
||||
path.lineTo(3,2);
|
||||
path.lineTo(4,3);
|
||||
path.close();
|
||||
}
|
||||
|
||||
static void addCCWContents(SkPath& path) {
|
||||
path.moveTo(3,2);
|
||||
path.lineTo(2,3);
|
||||
path.lineTo(4,3);
|
||||
path.close();
|
||||
}
|
||||
|
||||
static void testLine11() {
|
||||
SkPath path, simple;
|
||||
addCWContainer(path);
|
||||
addCWContents(path);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine12() {
|
||||
SkPath path, simple;
|
||||
addCCWContainer(path);
|
||||
addCWContents(path);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine13() {
|
||||
SkPath path, simple;
|
||||
addCWContainer(path);
|
||||
addCCWContents(path);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine14() {
|
||||
SkPath path, simple;
|
||||
addCCWContainer(path);
|
||||
addCCWContents(path);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine15() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 9, 9, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine16() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(0, 4, 9, 9, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine17() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine18() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(12, 4, 21, 21, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine19() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(12, 16, 21, 21, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine20() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(0, 12, 9, 9, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine21() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(0, 16, 9, 9, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine22() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine23() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(12, 0, 21, 21, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void testLine24a() {
|
||||
SkPath path, simple;
|
||||
path.moveTo(2,0);
|
||||
path.lineTo(4,4);
|
||||
path.lineTo(0,4);
|
||||
path.close();
|
||||
path.moveTo(2,0);
|
||||
path.lineTo(1,2);
|
||||
path.lineTo(2,2);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine24() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 18, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine25() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 6, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(12, 0, 21, 21, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine26() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 18, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(0, 12, 9, 9, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine27() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 18, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(12, 8, 21, 21, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
#define TEST(name) { name, #name }
|
||||
|
||||
static struct {
|
||||
void (*fun)();
|
||||
const char* str;
|
||||
} tests[] = {
|
||||
TEST(testLine1),
|
||||
TEST(testLine2),
|
||||
TEST(testLine3),
|
||||
TEST(testLine4),
|
||||
TEST(testLine5),
|
||||
TEST(testLine6),
|
||||
TEST(testLine7),
|
||||
TEST(testLine8),
|
||||
TEST(testLine9),
|
||||
TEST(testLine10),
|
||||
TEST(testLine10a),
|
||||
TEST(testLine11),
|
||||
TEST(testLine12),
|
||||
TEST(testLine13),
|
||||
TEST(testLine14),
|
||||
TEST(testLine15),
|
||||
TEST(testLine16),
|
||||
TEST(testLine17),
|
||||
TEST(testLine18),
|
||||
TEST(testLine19),
|
||||
TEST(testLine20),
|
||||
TEST(testLine21),
|
||||
TEST(testLine22),
|
||||
TEST(testLine23),
|
||||
TEST(testLine24a),
|
||||
TEST(testLine24),
|
||||
TEST(testLine25),
|
||||
TEST(testLine26),
|
||||
TEST(testLine27),
|
||||
};
|
||||
|
||||
static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
|
||||
@ -170,14 +361,14 @@ void SimplifyNew_Test() {
|
||||
}
|
||||
size_t index = 0;
|
||||
if (firstTest) {
|
||||
while (index < testCount && tests[index] != firstTest) {
|
||||
while (index < testCount && tests[index].fun != firstTest) {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
bool firstTestComplete = false;
|
||||
for ( ; index < testCount; ++index) {
|
||||
SkDebugf("%s [%d]\n", __FUNCTION__, index + 1);
|
||||
(*tests[index])();
|
||||
SkDebugf("%s [%s]\n", __FUNCTION__, tests[index].str);
|
||||
(*tests[index].fun)();
|
||||
firstTestComplete = true;
|
||||
}
|
||||
}
|
||||
|
209
experimental/Intersection/SimplifyRect4x4_Test.cpp
Normal file
209
experimental/Intersection/SimplifyRect4x4_Test.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "EdgeWalker_Test.h"
|
||||
#include "Intersection_Tests.h"
|
||||
#include "ShapeOps.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// four rects, of four sizes
|
||||
// for 3 smaller sizes, tall, wide
|
||||
// top upper mid lower bottom aligned (3 bits, 5 values)
|
||||
// same with x (3 bits, 5 values)
|
||||
// not included, square, tall, wide (2 bits)
|
||||
// cw or ccw (1 bit)
|
||||
|
||||
static void* testSimplify4x4RectsMain(void* data)
|
||||
{
|
||||
char pathStr[1024]; // gdb: set print elements 400
|
||||
bzero(pathStr, sizeof(pathStr));
|
||||
SkASSERT(data);
|
||||
State4& state = *(State4*) data;
|
||||
int aShape = state.a & 0x03;
|
||||
int aCW = state.a >> 1;
|
||||
int bShape = state.b & 0x03;
|
||||
int bCW = state.b >> 1;
|
||||
int cShape = state.c & 0x03;
|
||||
int cCW = state.c >> 1;
|
||||
int dShape = state.d & 0x03;
|
||||
int dCW = state.d >> 1;
|
||||
for (int aXAlign = 0 ; aXAlign < 5; ++aXAlign) {
|
||||
for (int aYAlign = 0 ; aYAlign < 5; ++aYAlign) {
|
||||
for (int bXAlign = 0 ; bXAlign < 5; ++bXAlign) {
|
||||
for (int bYAlign = 0 ; bYAlign < 5; ++bYAlign) {
|
||||
for (int cXAlign = 0 ; cXAlign < 5; ++cXAlign) {
|
||||
for (int cYAlign = 0 ; cYAlign < 5; ++cYAlign) {
|
||||
for (int dXAlign = 0 ; dXAlign < 5; ++dXAlign) {
|
||||
for (int dYAlign = 0 ; dYAlign < 5; ++dYAlign) {
|
||||
SkPath path, out;
|
||||
char* str = pathStr;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
int l, t, r, b;
|
||||
if (aShape) {
|
||||
switch (aShape) {
|
||||
case 1: // square
|
||||
l = 0; r = 60;
|
||||
t = 0; b = 60;
|
||||
aXAlign = 5;
|
||||
aYAlign = 5;
|
||||
break;
|
||||
case 2:
|
||||
l = aXAlign * 12;
|
||||
r = l + 30;
|
||||
t = 0; b = 60;
|
||||
aYAlign = 5;
|
||||
break;
|
||||
case 3:
|
||||
l = 0; r = 60;
|
||||
t = aYAlign * 12;
|
||||
b = l + 30;
|
||||
aXAlign = 5;
|
||||
break;
|
||||
}
|
||||
path.addRect(l, t, r, b, (SkPath::Direction) aCW);
|
||||
str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
|
||||
" (SkPath::Direction) %d);\n", l, t, r, b, aCW);
|
||||
} else {
|
||||
aXAlign = 5;
|
||||
aYAlign = 5;
|
||||
}
|
||||
if (bShape) {
|
||||
switch (bShape) {
|
||||
case 1: // square
|
||||
l = bXAlign * 10;
|
||||
r = l + 20;
|
||||
t = bYAlign * 10;
|
||||
b = l + 20;
|
||||
break;
|
||||
case 2:
|
||||
l = bXAlign * 10;
|
||||
r = l + 20;
|
||||
t = 10; b = 40;
|
||||
bYAlign = 5;
|
||||
break;
|
||||
case 3:
|
||||
l = 10; r = 40;
|
||||
t = bYAlign * 10;
|
||||
b = l + 20;
|
||||
bXAlign = 5;
|
||||
break;
|
||||
}
|
||||
path.addRect(l, t, r, b, (SkPath::Direction) bCW);
|
||||
str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
|
||||
" (SkPath::Direction) %d);\n", l, t, r, b, bCW);
|
||||
} else {
|
||||
bXAlign = 5;
|
||||
bYAlign = 5;
|
||||
}
|
||||
if (cShape) {
|
||||
switch (cShape) {
|
||||
case 1: // square
|
||||
l = cXAlign * 6;
|
||||
r = l + 12;
|
||||
t = cYAlign * 6;
|
||||
b = l + 12;
|
||||
break;
|
||||
case 2:
|
||||
l = cXAlign * 6;
|
||||
r = l + 12;
|
||||
t = 20; b = 30;
|
||||
cYAlign = 5;
|
||||
break;
|
||||
case 3:
|
||||
l = 20; r = 30;
|
||||
t = cYAlign * 6;
|
||||
b = l + 20;
|
||||
cXAlign = 5;
|
||||
break;
|
||||
}
|
||||
path.addRect(l, t, r, b, (SkPath::Direction) cCW);
|
||||
str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
|
||||
" (SkPath::Direction) %d);\n", l, t, r, b, cCW);
|
||||
} else {
|
||||
cXAlign = 5;
|
||||
cYAlign = 5;
|
||||
}
|
||||
if (dShape) {
|
||||
switch (dShape) {
|
||||
case 1: // square
|
||||
l = dXAlign * 4;
|
||||
r = l + 9;
|
||||
t = dYAlign * 4;
|
||||
b = l + 9;
|
||||
break;
|
||||
case 2:
|
||||
l = dXAlign * 6;
|
||||
r = l + 9;
|
||||
t = 32; b = 36;
|
||||
dYAlign = 5;
|
||||
break;
|
||||
case 3:
|
||||
l = 32; r = 36;
|
||||
t = dYAlign * 6;
|
||||
b = l + 9;
|
||||
dXAlign = 5;
|
||||
break;
|
||||
}
|
||||
path.addRect(l, t, r, b, (SkPath::Direction) dCW);
|
||||
str += sprintf(str, " path.addRect(%d, %d, %d, %d,"
|
||||
" (SkPath::Direction) %d);\n", l, t, r, b, dCW);
|
||||
} else {
|
||||
dXAlign = 5;
|
||||
dYAlign = 5;
|
||||
}
|
||||
path.close();
|
||||
SkDebugf("%s", pathStr);
|
||||
if (!testSimplifyx(path, out, state.bitmap, state.canvas)) {
|
||||
SkDebugf("*/\n{ %s %d, %d, %d, %d, %d, %d, %d, %d,"
|
||||
" %d, %d, %d, %d },\n/*\n",
|
||||
__FUNCTION__, state.a, state.b, state.c, state.d,
|
||||
aXAlign, aYAlign, bXAlign, bYAlign,
|
||||
cXAlign, cYAlign, dXAlign, dYAlign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int maxThreads = 1; // gRunTestsInOneThread ? 1 : 24;
|
||||
|
||||
void Simplify4x4RectsThreaded_Test()
|
||||
{
|
||||
State4 threadState[maxThreads];
|
||||
int threadIndex = 0;
|
||||
for (int a = 0; a < 8; ++a) { // outermost
|
||||
for (int b = a ; b < 8; ++b) {
|
||||
for (int c = b ; c < 8; ++c) {
|
||||
for (int d = c; d < 8; ++d) {
|
||||
State4* statePtr = &threadState[threadIndex];
|
||||
statePtr->a = a;
|
||||
statePtr->b = b;
|
||||
statePtr->c = c;
|
||||
statePtr->d = d;
|
||||
if (maxThreads > 1) {
|
||||
createThread(statePtr, testSimplify4x4RectsMain);
|
||||
if (++threadIndex >= maxThreads) {
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
} else {
|
||||
testSimplify4x4RectsMain(statePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
waitForCompletion(threadState, threadIndex);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -259,11 +259,76 @@ path.close();
|
||||
testSimplify(path, true, out, bitmap);
|
||||
drawAsciiPaths(path, out, true);
|
||||
</div>
|
||||
|
||||
<div id="testSimplifyQuadratic19">
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(6,4);
|
||||
path.lineTo(3,1);
|
||||
path.close();
|
||||
path.moveTo(2,3);
|
||||
path.lineTo(3,2);
|
||||
path.lineTo(4,3);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<div id="testSimplifyQuadratic20">
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(6,4);
|
||||
path.lineTo(3,1);
|
||||
path.close();
|
||||
path.moveTo(2,3);
|
||||
path.lineTo(4,3);
|
||||
path.lineTo(3,2);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<div id="testSimplifyQuadratic21">
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
path.lineTo(8,4);
|
||||
path.lineTo(4,0);
|
||||
path.close();
|
||||
path.moveTo(2,2);
|
||||
path.lineTo(3,3);
|
||||
path.lineTo(4,2);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<div id="testLine6">
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,0);
|
||||
path.lineTo(4,0);
|
||||
path.lineTo(2,2);
|
||||
path.close();
|
||||
path.moveTo(2,0);
|
||||
path.lineTo(6,0);
|
||||
path.lineTo(4,2);
|
||||
path.close();
|
||||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<!-- don't support addRect yet -->
|
||||
<div id="testLine17">
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
testLine6,
|
||||
testSimplifyQuadratic21,
|
||||
testSimplifyQuadratic20,
|
||||
testSimplifyQuadratic19,
|
||||
testSimplifyQuadratic18,
|
||||
testSimplifyQuadratic17,
|
||||
testSimplifyQuadratic16,
|
||||
@ -412,10 +477,10 @@ function draw(test, _at_x, _at_y, scale) {
|
||||
}
|
||||
ctx.strokeStyle = "red";
|
||||
var contours, verbs, pts;
|
||||
ctx.beginPath();
|
||||
for (contours in test) {
|
||||
var contour = test[contours];
|
||||
if (contours == 2) ctx.strokeStyle = "blue";
|
||||
ctx.beginPath();
|
||||
var first = true;
|
||||
for (verbs in contour) {
|
||||
var verb = contour[verbs];
|
||||
@ -438,8 +503,11 @@ function draw(test, _at_x, _at_y, scale) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.fillStyle="rgba(192,192,255, 0.3)";
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle="blue";
|
||||
for (contours in test) {
|
||||
|
@ -164,3 +164,356 @@ According to Mike/Rob, the flatness for quadratics increases by 4 for each
|
||||
subdivision, and a crude guess of the curvature can be had by comparing P1 to
|
||||
(P0+P2)/2. By looking at the ULPS of the numbers, I can guess what value of
|
||||
T may be far enough that the curves diverge but don't cross.
|
||||
|
||||
====
|
||||
|
||||
Code I May Not Need Any More
|
||||
|
||||
static bool CoincidentCandidate(const Angle* current) {
|
||||
const Segment* segment = current->segment();
|
||||
int min = SkMin32(current->start(), current->end());
|
||||
do {
|
||||
const Span& span = segment->fTs[min];
|
||||
if (span.fCoincident == Span::kStart_Coincidence) {
|
||||
return true;
|
||||
}
|
||||
} while (--min >= 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CoincidentHalf(const Angle* current, const Angle* next) {
|
||||
const Segment* other = next->segment();
|
||||
const Segment* segment = current->segment();
|
||||
int min = SkMin32(current->start(), current->end());
|
||||
const Span& minSpan = segment->fTs[min];
|
||||
if (minSpan.fOther == other) {
|
||||
return minSpan.fCoincident == Span::kStart_Coincidence;
|
||||
}
|
||||
int index = min;
|
||||
int spanCount = segment->fTs.count();
|
||||
while (++index < spanCount) {
|
||||
const Span& span = segment->fTs[index];
|
||||
if (minSpan.fT != span.fT) {
|
||||
break;
|
||||
}
|
||||
if (span.fOther != other) {
|
||||
continue;
|
||||
}
|
||||
return span.fCoincident == Span::kStart_Coincidence;
|
||||
}
|
||||
index = min;
|
||||
while (--index >= 0) {
|
||||
const Span& span = segment->fTs[index];
|
||||
if (span.fOther != other) {
|
||||
continue;
|
||||
}
|
||||
return span.fCoincident == Span::kStart_Coincidence;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Coincident(const Angle* current, const Angle* next) {
|
||||
return CoincidentHalf(current, next) &&
|
||||
CoincidentHalf(next, current);
|
||||
}
|
||||
|
||||
// If three lines cancel in a - b - c order, a - b may or may not
|
||||
// eliminate the edge that describes the b - c cancellation. Check done to
|
||||
// determine this.
|
||||
static bool CoincidentCancels(const Angle* current, const Angle* next) {
|
||||
int curMin = SkMin32(current->start(), current->end());
|
||||
if (current->segment()->fTs[curMin].fDone) {
|
||||
return false;
|
||||
}
|
||||
int nextMin = SkMin32(next->start(), next->end());
|
||||
if (next->segment()->fTs[nextMin].fDone) {
|
||||
return false;
|
||||
}
|
||||
return SkSign32(current->start() - current->end())
|
||||
!= SkSign32(next->start() - next->end());
|
||||
}
|
||||
|
||||
// FIXME: at this point, just have two functions for the different steps
|
||||
int coincidentEnd(int from, int step) const {
|
||||
double fromT = fTs[from].fT;
|
||||
int count = fTs.count();
|
||||
int to = from;
|
||||
while (step > 0 ? ++to < count : --to >= 0) {
|
||||
const Span& span = fTs[to];
|
||||
if ((step > 0 ? span.fT - fromT : fromT - span.fT) >= FLT_EPSILON ) {
|
||||
// FIXME: we assume that if the T changes, we don't care about
|
||||
// coincident -- but in nextSpan, we require that both the T
|
||||
// and actual loc change to represent a span. This asymettry may
|
||||
// be OK or may be trouble -- if trouble, probably will need to
|
||||
// detect coincidence earlier or sort differently
|
||||
break;
|
||||
}
|
||||
#if 01
|
||||
if (span.fCoincident == (step < 0 ? Span::kStart_Coincidence :
|
||||
Span::kEnd_Coincidence)) {
|
||||
from = to;
|
||||
}
|
||||
#else
|
||||
from = to;
|
||||
#endif
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
// once past current span, if step>0, look for coicident==1
|
||||
// if step<0, look for coincident==-1
|
||||
int nextSpanEnd(int from, int step) const {
|
||||
int result = nextSpan(from, step);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
return coincidentEnd(result, step);
|
||||
}
|
||||
|
||||
|
||||
void adjustFirst(const SkTDArray<Angle*>& sorted, int& first, int& winding,
|
||||
bool outside) {
|
||||
int firstIndex = first;
|
||||
int angleCount = sorted.count();
|
||||
if (true || outside) {
|
||||
const Angle* angle = sorted[firstIndex];
|
||||
int prior = firstIndex;
|
||||
do {
|
||||
if (--prior < 0) {
|
||||
prior = angleCount - 1;
|
||||
}
|
||||
if (prior == firstIndex) { // all are coincident with each other
|
||||
return;
|
||||
}
|
||||
if (!Coincident(sorted[prior], sorted[first])) {
|
||||
return;
|
||||
}
|
||||
winding += angle->sign();
|
||||
first = prior;
|
||||
angle = sorted[prior];
|
||||
winding -= angle->sign();
|
||||
} while (true);
|
||||
}
|
||||
do {
|
||||
int next = first + 1;
|
||||
if (next == angleCount) {
|
||||
next = 0;
|
||||
}
|
||||
if (next == firstIndex) { // all are coincident with each other
|
||||
return;
|
||||
}
|
||||
if (!Coincident(sorted[first], sorted[next])) {
|
||||
return;
|
||||
}
|
||||
first = next;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
bool nextIsCoincident = CoincidentCandidate(nextAngle);
|
||||
bool finalOrNoCoincident = true;
|
||||
bool pairCoincides = false;
|
||||
bool pairCancels = false;
|
||||
if (nextIsCoincident) {
|
||||
int followIndex = nextIndex + 1;
|
||||
if (followIndex == angleCount) {
|
||||
followIndex = 0;
|
||||
}
|
||||
const Angle* followAngle = sorted[followIndex];
|
||||
finalOrNoCoincident = !Coincident(nextAngle, followAngle);
|
||||
if ((pairCoincides = Coincident(angle, nextAngle))) {
|
||||
pairCancels = CoincidentCancels(angle, nextAngle);
|
||||
}
|
||||
}
|
||||
if (pairCancels && !foundAngle && !nextSegment->done()) {
|
||||
Segment* aSeg = angle->segment();
|
||||
// alreadyMarked |= aSeg == sorted[firstIndex]->segment();
|
||||
aSeg->markAndChaseCoincident(angle->start(), angle->end(),
|
||||
nextSegment);
|
||||
if (firstEdge) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (pairCoincides) {
|
||||
if (pairCancels) {
|
||||
goto doNext;
|
||||
}
|
||||
int minT = SkMin32(nextAngle->start(), nextAngle->end());
|
||||
bool markNext = abs(maxWinding) < abs(winding);
|
||||
if (markNext) {
|
||||
nextSegment->markDone(minT, winding);
|
||||
}
|
||||
int oldMinT = SkMin32(angle->start(), angle->end());
|
||||
if (true || !foundAngle) {
|
||||
// SkASSERT(0); // do we ever get here?
|
||||
Segment* aSeg = angle->segment();
|
||||
// alreadyMarked |= aSeg == sorted[firstIndex]->segment();
|
||||
aSeg->markDone(oldMinT, maxWinding);
|
||||
}
|
||||
}
|
||||
|
||||
// OPTIMIZATION: uses tail recursion. Unwise?
|
||||
void innerCoincidentChase(int step, Segment* other) {
|
||||
// find other at index
|
||||
// SkASSERT(!done());
|
||||
const Span* start = NULL;
|
||||
const Span* end = NULL;
|
||||
int index, startIndex, endIndex;
|
||||
int count = fTs.count();
|
||||
for (index = 0; index < count; ++index) {
|
||||
const Span& span = fTs[index];
|
||||
if (!span.fCoincident || span.fOther != other) {
|
||||
continue;
|
||||
}
|
||||
if (!start) {
|
||||
startIndex = index;
|
||||
start = &span;
|
||||
} else {
|
||||
SkASSERT(!end);
|
||||
endIndex = index;
|
||||
end = &span;
|
||||
}
|
||||
}
|
||||
if (!end) {
|
||||
return;
|
||||
}
|
||||
bool thisDone = fTs[SkMin32(startIndex, endIndex)].fDone;
|
||||
bool otherDone = other->fTs[SkMin32(start->fOtherIndex,
|
||||
end->fOtherIndex)].fDone;
|
||||
if (thisDone && otherDone) {
|
||||
return;
|
||||
}
|
||||
Segment* next;
|
||||
Segment* nextOther;
|
||||
if (step < 0) {
|
||||
next = start->fT == 0 ? NULL : this;
|
||||
nextOther = other->fTs[start->fOtherIndex].fT > 1 - FLT_EPSILON ? NULL : other;
|
||||
} else {
|
||||
next = end->fT == 1 ? NULL : this;
|
||||
nextOther = other->fTs[end->fOtherIndex].fT < FLT_EPSILON ? NULL : other;
|
||||
}
|
||||
SkASSERT(!next || !nextOther);
|
||||
for (index = 0; index < count; ++index) {
|
||||
const Span& span = fTs[index];
|
||||
if (span.fCoincident || span.fOther == other) {
|
||||
continue;
|
||||
}
|
||||
bool checkNext = !next && (step < 0 ? span.fT < FLT_EPSILON
|
||||
&& span.fOtherT > 1 - FLT_EPSILON : span.fT > 1 - FLT_EPSILON
|
||||
&& span.fOtherT < FLT_EPSILON);
|
||||
bool checkOther = !nextOther && (step < 0 ? fabs(span.fT - start->fT) < FLT_EPSILON
|
||||
&& span.fOtherT < FLT_EPSILON : fabs(span.fT - end->fT) < FLT_EPSILON
|
||||
&& span.fOtherT > 1 - FLT_EPSILON);
|
||||
if (!checkNext && !checkOther) {
|
||||
continue;
|
||||
}
|
||||
Segment* oSegment = span.fOther;
|
||||
if (oSegment->done()) {
|
||||
continue;
|
||||
}
|
||||
int oCount = oSegment->fTs.count();
|
||||
for (int oIndex = 0; oIndex < oCount; ++oIndex) {
|
||||
const Span& oSpan = oSegment->fTs[oIndex];
|
||||
if (oSpan.fT >= FLT_EPSILON && oSpan.fT <= 1 - FLT_EPSILON) {
|
||||
continue;
|
||||
}
|
||||
if (!oSpan.fCoincident) {
|
||||
continue;
|
||||
}
|
||||
if (checkNext && (oSpan.fT < FLT_EPSILON ^ step < 0)) {
|
||||
next = oSegment;
|
||||
checkNext = false;
|
||||
}
|
||||
if (checkOther && (oSpan.fT > 1 - FLT_EPSILON ^ step < 0)) {
|
||||
nextOther = oSegment;
|
||||
checkOther = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// this needs to walk both spans in lock step, skipping edges that
|
||||
// are already marked done on one or the other
|
||||
markCanceled(startIndex, endIndex);
|
||||
if (next && nextOther) {
|
||||
next->innerCoincidentChase(step, nextOther);
|
||||
}
|
||||
}
|
||||
|
||||
// cancel coincident edges in lock step
|
||||
void markCanceled(int start, int end) {
|
||||
if (done()) {
|
||||
return;
|
||||
}
|
||||
Segment* other = fTs[start].fOther;
|
||||
if (other->done()) {
|
||||
return;
|
||||
}
|
||||
if (start > end) {
|
||||
SkTSwap<int>(start, end);
|
||||
}
|
||||
double maxT = fTs[end].fT - FLT_EPSILON;
|
||||
int spanCount = fTs.count();
|
||||
// since these cancel, this walks up and other walks down
|
||||
int oStart = fTs[start].fOtherIndex;
|
||||
double oStartT = other->fTs[oStart].fT;
|
||||
while (oStartT - other->fTs[--oStart].fT < FLT_EPSILON)
|
||||
;
|
||||
double startT = fTs[start].fT;
|
||||
while (start > 0 && startT - fTs[start - 1].fT < FLT_EPSILON) {
|
||||
--start;
|
||||
}
|
||||
do {
|
||||
Span* span = &fTs[start];
|
||||
Span* oSpan = &other->fTs[oStart];
|
||||
// find start of each, and see if both are not done
|
||||
bool markDone = !span->fDone && !oSpan->fDone;
|
||||
double spanT = span->fT;
|
||||
do {
|
||||
if (markDone) {
|
||||
span->fCanceled = true;
|
||||
#if DEBUG_MARK_DONE
|
||||
const SkPoint& pt = xyAtT(span);
|
||||
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, fID, start, span->fT, pt.fX, pt.fY);
|
||||
#endif
|
||||
SkASSERT(!span->fDone);
|
||||
span->fDone = true;
|
||||
span->fWinding = 0;
|
||||
fDoneSpans++;
|
||||
}
|
||||
if (++start == spanCount) {
|
||||
break;
|
||||
}
|
||||
span = &fTs[start];
|
||||
} while (span->fT - spanT < FLT_EPSILON);
|
||||
double oSpanT = oSpan->fT;
|
||||
do {
|
||||
if (markDone) {
|
||||
oSpan->fCanceled = true;
|
||||
#if DEBUG_MARK_DONE
|
||||
const SkPoint& oPt = xyAtT(oSpan);
|
||||
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, other->fID, oStart, oSpan->fT,
|
||||
oPt.fX, oPt.fY);
|
||||
#endif
|
||||
SkASSERT(!oSpan->fDone);
|
||||
oSpan->fDone = true;
|
||||
oSpan->fWinding = 0;
|
||||
other->fDoneSpans++;
|
||||
}
|
||||
if (--oStart < 0) {
|
||||
break;
|
||||
}
|
||||
oSpan = &other->fTs[oStart];
|
||||
} while (oSpanT - oSpan->fT < FLT_EPSILON);
|
||||
} while (fTs[start].fT <= maxT);
|
||||
}
|
||||
|
||||
bool canceled(int start, int end) const {
|
||||
int min = SkMin32(start, end);
|
||||
return fTs[min].fCanceled;
|
||||
}
|
||||
|
||||
void markAndChaseCoincident(int index, int endIndex, Segment* other) {
|
||||
int step = SkSign32(endIndex - index);
|
||||
innerCoincidentChase(step, other);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user