work in progress
in the middle of switching to sortless version git-svn-id: http://skia.googlecode.com/svn/trunk@3768 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
8e124a2454
commit
fa0588ff67
@ -74,9 +74,9 @@ void ActiveEdge_Test() {
|
|||||||
right.fWorkEdge.fEdge = &rightIn;
|
right.fWorkEdge.fEdge = &rightIn;
|
||||||
for (size_t x = 0; x < leftRightCount; ++x) {
|
for (size_t x = 0; x < leftRightCount; ++x) {
|
||||||
left.fAbove = leftRight[x][0];
|
left.fAbove = leftRight[x][0];
|
||||||
left.fBelow = leftRight[x][1];
|
left.fTangent = left.fBelow = leftRight[x][1];
|
||||||
right.fAbove = leftRight[x][2];
|
right.fAbove = leftRight[x][2];
|
||||||
right.fBelow = leftRight[x][3];
|
right.fTangent = right.fBelow = leftRight[x][3];
|
||||||
SkASSERT(left < right);
|
SkASSERT(left < right);
|
||||||
SkASSERT(operator_less_than(left, right));
|
SkASSERT(operator_less_than(left, right));
|
||||||
SkASSERT(!(right < left));
|
SkASSERT(!(right < left));
|
||||||
|
@ -1,10 +1,63 @@
|
|||||||
/*
|
#include "DataTypes.h"
|
||||||
* CubicBounds.cpp
|
#include "Extrema.h"
|
||||||
* edge
|
|
||||||
*
|
|
||||||
* Created by Cary Clark on 1/27/12.
|
|
||||||
* Copyright 2012 __MyCompanyName__. All rights reserved.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
static int isBoundedByEndPoints(double a, double b, double c, double d)
|
||||||
|
{
|
||||||
|
return (a <= b && a <= c && b <= d && c <= d)
|
||||||
|
|| (a >= b && a >= c && b >= d && c >= d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double leftMostT(const Cubic& cubic, double startT, double endT) {
|
||||||
|
double leftTs[2];
|
||||||
|
_Point pt[2];
|
||||||
|
int results = findExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x,
|
||||||
|
leftTs);
|
||||||
|
int best = -1;
|
||||||
|
for (int index = 0; index < results; ++index) {
|
||||||
|
if (startT > leftTs[index] || leftTs[index] > endT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (best < 0) {
|
||||||
|
best = index;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xy_at_t(cubic, leftTs[0], pt[0].x, pt[0].y);
|
||||||
|
xy_at_t(cubic, leftTs[1], pt[1].x, pt[1].y);
|
||||||
|
if (pt[0].x > pt[1].x) {
|
||||||
|
best = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best >= 0) {
|
||||||
|
return leftTs[best];
|
||||||
|
}
|
||||||
|
xy_at_t(cubic, startT, pt[0].x, pt[0].y);
|
||||||
|
xy_at_t(cubic, endT, pt[1].x, pt[1].y);
|
||||||
|
return pt[0].x <= pt[1].x ? startT : endT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Rect::setBounds(const Cubic& cubic) {
|
||||||
|
set(cubic[0]);
|
||||||
|
add(cubic[3]);
|
||||||
|
double tValues[4];
|
||||||
|
int roots = 0;
|
||||||
|
if (!isBoundedByEndPoints(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x)) {
|
||||||
|
roots = findExtrema(cubic[0].x, cubic[1].x, cubic[2].x,
|
||||||
|
cubic[3].x, tValues);
|
||||||
|
}
|
||||||
|
if (!isBoundedByEndPoints(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y)) {
|
||||||
|
roots += findExtrema(cubic[0].y, cubic[1].y, cubic[2].y,
|
||||||
|
cubic[3].y, &tValues[roots]);
|
||||||
|
}
|
||||||
|
for (int x = 0; x < roots; ++x) {
|
||||||
|
_Point result;
|
||||||
|
xy_at_t(cubic, tValues[x], result.x, result.y);
|
||||||
|
add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Rect::setRawBounds(const Cubic& cubic) {
|
||||||
|
set(cubic[0]);
|
||||||
|
for (int x = 1; x < 4; ++x) {
|
||||||
|
add(cubic[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ static int vertical_line(const Cubic& cubic, Cubic& reduction) {
|
|||||||
reduction[1] = cubic[3];
|
reduction[1] = cubic[3];
|
||||||
int smaller = reduction[1].y > reduction[0].y;
|
int smaller = reduction[1].y > reduction[0].y;
|
||||||
int larger = smaller ^ 1;
|
int larger = smaller ^ 1;
|
||||||
int roots = SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
int roots = findExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
||||||
for (int index = 0; index < roots; ++index) {
|
for (int index = 0; index < roots; ++index) {
|
||||||
double yExtrema = interp_cubic_coords(&cubic[0].y, tValues[index]);
|
double yExtrema = interp_cubic_coords(&cubic[0].y, tValues[index]);
|
||||||
if (reduction[smaller].y > yExtrema) {
|
if (reduction[smaller].y > yExtrema) {
|
||||||
@ -44,7 +44,7 @@ static int horizontal_line(const Cubic& cubic, Cubic& reduction) {
|
|||||||
reduction[1] = cubic[3];
|
reduction[1] = cubic[3];
|
||||||
int smaller = reduction[1].x > reduction[0].x;
|
int smaller = reduction[1].x > reduction[0].x;
|
||||||
int larger = smaller ^ 1;
|
int larger = smaller ^ 1;
|
||||||
int roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
int roots = findExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
||||||
for (int index = 0; index < roots; ++index) {
|
for (int index = 0; index < roots; ++index) {
|
||||||
double xExtrema = interp_cubic_coords(&cubic[0].x, tValues[index]);
|
double xExtrema = interp_cubic_coords(&cubic[0].x, tValues[index]);
|
||||||
if (reduction[smaller].x > xExtrema) {
|
if (reduction[smaller].x > xExtrema) {
|
||||||
@ -127,9 +127,9 @@ static int check_linear(const Cubic& cubic, Cubic& reduction,
|
|||||||
double tValues[2];
|
double tValues[2];
|
||||||
int roots;
|
int roots;
|
||||||
if (useX) {
|
if (useX) {
|
||||||
roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
roots = findExtrema(cubic[0].x, cubic[1].x, cubic[2].x, cubic[3].x, tValues);
|
||||||
} else {
|
} else {
|
||||||
roots = SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
roots = findExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y, tValues);
|
||||||
}
|
}
|
||||||
for (index = 0; index < roots; ++index) {
|
for (index = 0; index < roots; ++index) {
|
||||||
_Point extrema;
|
_Point extrema;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
class Intersections;
|
class Intersections;
|
||||||
|
|
||||||
// unit-testable utilities
|
// unit-testable utilities
|
||||||
|
double axialIntersect(const Quadratic& q1, const _Point& p, bool vert);
|
||||||
bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT);
|
bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT);
|
||||||
bool bezier_clip(const Quadratic& q1, const Quadratic& q2, double& minT, double& maxT);
|
bool bezier_clip(const Quadratic& q1, const Quadratic& q2, double& minT, double& maxT);
|
||||||
void chop_at(const Cubic& src, CubicPair& dst, double t);
|
void chop_at(const Cubic& src, CubicPair& dst, double t);
|
||||||
@ -34,11 +35,26 @@ int reduceOrder(const Quadratic& quad, Quadratic& reduction);
|
|||||||
int horizontalIntersect(const Cubic& cubic, double y, double tRange[3]);
|
int horizontalIntersect(const Cubic& cubic, double y, double tRange[3]);
|
||||||
int horizontalIntersect(const Cubic& cubic, double left, double right, double y,
|
int horizontalIntersect(const Cubic& cubic, double left, double right, double y,
|
||||||
double tRange[3]);
|
double tRange[3]);
|
||||||
|
int horizontalIntersect(const Cubic& cubic, double left, double right, double y,
|
||||||
|
bool flipped, Intersections&);
|
||||||
|
int horizontalIntersect(const _Line& line, double left, double right,
|
||||||
|
double y, bool flipped, Intersections& );
|
||||||
int horizontalIntersect(const Quadratic& quad, double left, double right,
|
int horizontalIntersect(const Quadratic& quad, double left, double right,
|
||||||
double y, double tRange[2]);
|
double y, double tRange[2]);
|
||||||
|
int horizontalIntersect(const Quadratic& quad, double left, double right,
|
||||||
|
double y, bool flipped, Intersections& );
|
||||||
bool intersect(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
|
bool intersect(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
|
||||||
int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]);
|
int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]);
|
||||||
bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& );
|
bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& );
|
||||||
bool intersect(const Quadratic& quad, const _Line& line, Intersections& );
|
bool intersect(const Quadratic& quad, const _Line& line, Intersections& );
|
||||||
|
double leftMostT(const Cubic& , double startT, double endT);
|
||||||
|
double leftMostT(const _Line& , double startT, double endT);
|
||||||
|
double leftMostT(const Quadratic& , double startT, double endT);
|
||||||
|
int verticalIntersect(const Cubic& cubic, double top, double bottom, double x,
|
||||||
|
bool flipped, Intersections& );
|
||||||
|
int verticalIntersect(const _Line& line, double top, double bottom, double x,
|
||||||
|
bool flipped, Intersections& );
|
||||||
|
int verticalIntersect(const Quadratic& quad, double top, double bottom,
|
||||||
|
double x, bool flipped, Intersections& );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc.
|
* Copyright 2012 Google Inc.
|
||||||
*
|
*
|
||||||
@ -20,9 +19,9 @@
|
|||||||
#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
|
#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
|
||||||
|
|
||||||
// FIXME: remove once debugging is complete
|
// FIXME: remove once debugging is complete
|
||||||
#if 0 // set to 1 for no debugging whatsoever
|
#if 01 // set to 1 for no debugging whatsoever
|
||||||
|
|
||||||
const bool gRunTestsInOneThread = true;
|
const bool gRunTestsInOneThread = false;
|
||||||
|
|
||||||
#define DEBUG_ACTIVE_LESS_THAN 0
|
#define DEBUG_ACTIVE_LESS_THAN 0
|
||||||
#define DEBUG_ADD 0
|
#define DEBUG_ADD 0
|
||||||
@ -1381,23 +1380,51 @@ struct WorkEdge {
|
|||||||
class ActiveEdge {
|
class ActiveEdge {
|
||||||
public:
|
public:
|
||||||
// this logic must be kept in sync with tooCloseToCall
|
// this logic must be kept in sync with tooCloseToCall
|
||||||
// callers expect this to only read fAbove, fBelow
|
// callers expect this to only read fAbove, fTangent
|
||||||
bool operator<(const ActiveEdge& rh) const {
|
bool operator<(const ActiveEdge& rh) const {
|
||||||
double topD = fAbove.fX - rh.fAbove.fX;
|
if (fVerb == rh.fVerb) {
|
||||||
if (rh.fAbove.fY < fAbove.fY) {
|
// FIXME: don't know what to do if verb is quad, cubic
|
||||||
topD = (rh.fBelow.fY - rh.fAbove.fY) * topD
|
return abCompare(fAbove, fBelow, rh.fAbove, rh.fBelow);
|
||||||
- (fAbove.fY - rh.fAbove.fY) * (rh.fBelow.fX - rh.fAbove.fX);
|
|
||||||
} else if (rh.fAbove.fY > fAbove.fY) {
|
|
||||||
topD = (fBelow.fY - fAbove.fY) * topD
|
|
||||||
+ (rh.fAbove.fY - fAbove.fY) * (fBelow.fX - fAbove.fX);
|
|
||||||
}
|
}
|
||||||
double botD = fBelow.fX - rh.fBelow.fX;
|
// figure out which is quad, line
|
||||||
if (rh.fBelow.fY > fBelow.fY) {
|
// if cached data says line did not intersect quad, use top/bottom
|
||||||
botD = (rh.fBelow.fY - rh.fAbove.fY) * botD
|
if (fVerb != SkPath::kLine_Verb ? noIntersect(rh) : rh.noIntersect(*this)) {
|
||||||
- (fBelow.fY - rh.fBelow.fY) * (rh.fBelow.fX - rh.fAbove.fX);
|
return abCompare(fAbove, fBelow, rh.fAbove, rh.fBelow);
|
||||||
} else if (rh.fBelow.fY < fBelow.fY) {
|
}
|
||||||
botD = (fBelow.fY - fAbove.fY) * botD
|
// use whichever of top/tangent tangent/bottom overlaps more
|
||||||
+ (rh.fBelow.fY - fBelow.fY) * (fBelow.fX - fAbove.fX);
|
// with line top/bot
|
||||||
|
// assumes quad/cubic can already be upconverted to cubic/cubic
|
||||||
|
const SkPoint* line[2];
|
||||||
|
const SkPoint* curve[4];
|
||||||
|
if (fVerb != SkPath::kLine_Verb) {
|
||||||
|
line[0] = &rh.fAbove;
|
||||||
|
line[1] = &rh.fBelow;
|
||||||
|
curve[0] = &fAbove;
|
||||||
|
curve[1] = &fTangent;
|
||||||
|
curve[2] = &fBelow;
|
||||||
|
} else {
|
||||||
|
line[0] = &fAbove;
|
||||||
|
line[1] = &fBelow;
|
||||||
|
curve[0] = &rh.fAbove;
|
||||||
|
curve[1] = &rh.fTangent;
|
||||||
|
curve[2] = &rh.fBelow;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool abCompare(const SkPoint& a1, const SkPoint& a2, const SkPoint& b1,
|
||||||
|
const SkPoint& b2) const {
|
||||||
|
double topD = a1.fX - b1.fX;
|
||||||
|
if (b1.fY < a1.fY) {
|
||||||
|
topD = (b2.fY - b1.fY) * topD - (a1.fY - b1.fY) * (b2.fX - b1.fX);
|
||||||
|
} else if (b1.fY > a1.fY) {
|
||||||
|
topD = (a2.fY - a1.fY) * topD + (b1.fY - a1.fY) * (a2.fX - a1.fX);
|
||||||
|
}
|
||||||
|
double botD = a2.fX - b2.fX;
|
||||||
|
if (b2.fY > a2.fY) {
|
||||||
|
botD = (b2.fY - b1.fY) * botD - (a2.fY - b2.fY) * (b2.fX - b1.fX);
|
||||||
|
} else if (b2.fY < a2.fY) {
|
||||||
|
botD = (a2.fY - a1.fY) * botD + (b2.fY - a2.fY) * (a2.fX - a1.fX);
|
||||||
}
|
}
|
||||||
// return sign of greater absolute value
|
// return sign of greater absolute value
|
||||||
return (fabs(topD) > fabs(botD) ? topD : botD) < 0;
|
return (fabs(topD) > fabs(botD) ? topD : botD) < 0;
|
||||||
@ -1477,6 +1504,37 @@ public:
|
|||||||
SkASSERT(!fExplicitTs);
|
SkASSERT(!fExplicitTs);
|
||||||
fTIndex = fTs->count() + 1;
|
fTIndex = fTs->count() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void calcAboveBelow(double tAbove, double tBelow) {
|
||||||
|
fVerb = fWorkEdge.verb();
|
||||||
|
switch (fVerb) {
|
||||||
|
case SkPath::kLine_Verb:
|
||||||
|
LineXYAtT(fWorkEdge.fPts, tAbove, &fAbove);
|
||||||
|
LineXYAtT(fWorkEdge.fPts, tBelow, &fTangent);
|
||||||
|
fBelow = fTangent;
|
||||||
|
break;
|
||||||
|
case SkPath::kQuad_Verb:
|
||||||
|
// FIXME: put array in struct to avoid copy?
|
||||||
|
SkPoint quad[3];
|
||||||
|
QuadSubDivide(fWorkEdge.fPts, tAbove, tBelow, quad);
|
||||||
|
fAbove = quad[0];
|
||||||
|
fTangent = quad[0] != quad[1] ? quad[1] : quad[2];
|
||||||
|
fBelow = quad[2];
|
||||||
|
break;
|
||||||
|
case SkPath::kCubic_Verb:
|
||||||
|
SkPoint cubic[3];
|
||||||
|
CubicSubDivide(fWorkEdge.fPts, tAbove, tBelow, cubic);
|
||||||
|
fAbove = cubic[0];
|
||||||
|
// FIXME: can't see how quad logic for how tangent is used
|
||||||
|
// extends to cubic
|
||||||
|
fTangent = cubic[0] != cubic[1] ? cubic[1]
|
||||||
|
: cubic[0] != cubic[2] ? cubic[2] : cubic[3];
|
||||||
|
fBelow = cubic[3];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SkASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void calcLeft(SkScalar y) {
|
void calcLeft(SkScalar y) {
|
||||||
// OPTIMIZE: put a kDone_Verb at the end of the verb list?
|
// OPTIMIZE: put a kDone_Verb at the end of the verb list?
|
||||||
@ -1491,29 +1549,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void calcLeft() {
|
void calcLeft() {
|
||||||
void (*xyAtTFunc)(const SkPoint a[], double t, SkPoint* out);
|
|
||||||
switch (fWorkEdge.verb()) {
|
|
||||||
case SkPath::kLine_Verb:
|
|
||||||
xyAtTFunc = LineXYAtT;
|
|
||||||
break;
|
|
||||||
case SkPath::kQuad_Verb:
|
|
||||||
xyAtTFunc = QuadXYAtT;
|
|
||||||
break;
|
|
||||||
case SkPath::kCubic_Verb:
|
|
||||||
xyAtTFunc = CubicXYAtT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkASSERT(0);
|
|
||||||
}
|
|
||||||
// OPTIMIZATION: if fXAbove, fXBelow have already been computed
|
|
||||||
// for the fTIndex, don't do it again
|
|
||||||
// For identical x, this lets us know which edge is first.
|
|
||||||
// If both edges have T values < 1, check x at next T (fXBelow).
|
|
||||||
int add = (fTIndex <= fTs->count() - fExplicitTs) - 1;
|
int add = (fTIndex <= fTs->count() - fExplicitTs) - 1;
|
||||||
double tAbove = t(fTIndex + add);
|
double tAbove = t(fTIndex + add);
|
||||||
(*xyAtTFunc)(fWorkEdge.fPts, tAbove, &fAbove);
|
|
||||||
double tBelow = t(fTIndex - ~add);
|
double tBelow = t(fTIndex - ~add);
|
||||||
(*xyAtTFunc)(fWorkEdge.fPts, tBelow, &fBelow);
|
// OPTIMIZATION: if fAbove, fBelow have already been computed
|
||||||
|
// for the fTIndex, don't do it again
|
||||||
|
calcAboveBelow(tAbove, tBelow);
|
||||||
|
// For identical x, this lets us know which edge is first.
|
||||||
|
// If both edges have T values < 1, check x at next T (fBelow).
|
||||||
SkASSERT(tAbove != tBelow);
|
SkASSERT(tAbove != tBelow);
|
||||||
// FIXME: this can loop forever
|
// FIXME: this can loop forever
|
||||||
// need a break if we hit the end
|
// need a break if we hit the end
|
||||||
@ -1523,13 +1566,12 @@ public:
|
|||||||
add -= 1;
|
add -= 1;
|
||||||
SkASSERT(fTIndex + add >= 0);
|
SkASSERT(fTIndex + add >= 0);
|
||||||
tAbove = t(fTIndex + add);
|
tAbove = t(fTIndex + add);
|
||||||
(*xyAtTFunc)(fWorkEdge.fPts, tAbove, &fAbove);
|
|
||||||
} else {
|
} else {
|
||||||
add += 1;
|
add += 1;
|
||||||
SkASSERT(fTIndex - ~add <= fTs->count() + 1);
|
SkASSERT(fTIndex - ~add <= fTs->count() + 1);
|
||||||
tBelow = t(fTIndex - ~add);
|
tBelow = t(fTIndex - ~add);
|
||||||
(*xyAtTFunc)(fWorkEdge.fPts, tBelow, &fBelow);
|
|
||||||
}
|
}
|
||||||
|
calcAboveBelow(tAbove, tBelow);
|
||||||
}
|
}
|
||||||
fTAbove = tAbove;
|
fTAbove = tAbove;
|
||||||
fTBelow = tBelow;
|
fTBelow = tBelow;
|
||||||
@ -1541,28 +1583,17 @@ public:
|
|||||||
|
|
||||||
void fixBelow() {
|
void fixBelow() {
|
||||||
if (fFixBelow) {
|
if (fFixBelow) {
|
||||||
switch (fWorkEdge.verb()) {
|
fTBelow = nextT();
|
||||||
case SkPath::kLine_Verb:
|
calcAboveBelow(fTAbove, fTBelow);
|
||||||
LineXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
|
|
||||||
break;
|
|
||||||
case SkPath::kQuad_Verb:
|
|
||||||
QuadXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
|
|
||||||
break;
|
|
||||||
case SkPath::kCubic_Verb:
|
|
||||||
CubicXYAtT(fWorkEdge.fPts, nextT(), &fBelow);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkASSERT(0);
|
|
||||||
}
|
|
||||||
fFixBelow = false;
|
fFixBelow = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(const InEdge* edge) {
|
void init(const InEdge* edge) {
|
||||||
fWorkEdge.init(edge);
|
fWorkEdge.init(edge);
|
||||||
|
fDone = false;
|
||||||
initT();
|
initT();
|
||||||
fBelow.fY = SK_ScalarMin;
|
fBelow.fY = SK_ScalarMin;
|
||||||
fDone = false;
|
|
||||||
fYBottom = SK_ScalarMin;
|
fYBottom = SK_ScalarMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1576,6 +1607,10 @@ public:
|
|||||||
// fTs = &fWorkEdge.fEdge->fIntercepts[fWorkEdge.verbIndex()].fTs;
|
// fTs = &fWorkEdge.fEdge->fIntercepts[fWorkEdge.verbIndex()].fTs;
|
||||||
// but templated arrays don't allow returning a pointer to the end() element
|
// but templated arrays don't allow returning a pointer to the end() element
|
||||||
fTIndex = 0;
|
fTIndex = 0;
|
||||||
|
if (!fDone) {
|
||||||
|
fVerb = fWorkEdge.verb();
|
||||||
|
}
|
||||||
|
SkASSERT(fVerb > SkPath::kMove_Verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OPTIMIZATION: record if two edges are coincident when the are intersected
|
// OPTIMIZATION: record if two edges are coincident when the are intersected
|
||||||
@ -1586,13 +1621,10 @@ public:
|
|||||||
if (fAbove != edge->fAbove || fBelow != edge->fBelow) {
|
if (fAbove != edge->fAbove || fBelow != edge->fBelow) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SkPath::Verb verb = fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
|
if (fVerb != edge->fVerb) {
|
||||||
SkPath::Verb edgeVerb = edge->fDone ? edge->fWorkEdge.lastVerb()
|
|
||||||
: edge->fWorkEdge.verb();
|
|
||||||
if (verb != edgeVerb) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (verb) {
|
switch (fVerb) {
|
||||||
case SkPath::kLine_Verb:
|
case SkPath::kLine_Verb:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@ -1607,13 +1639,18 @@ public:
|
|||||||
return fAbove == edge->fAbove && fBelow == edge->fBelow;
|
return fAbove == edge->fAbove && fBelow == edge->fBelow;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPath::Verb lastVerb() const {
|
// SkPath::Verb lastVerb() const {
|
||||||
return fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
|
// return fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
|
||||||
}
|
// }
|
||||||
|
|
||||||
const SkPoint* lastPoints() const {
|
const SkPoint* lastPoints() const {
|
||||||
return fDone ? fWorkEdge.lastPoints() : fWorkEdge.points();
|
return fDone ? fWorkEdge.lastPoints() : fWorkEdge.points();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool noIntersect(const ActiveEdge& ) const {
|
||||||
|
// incomplete
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// The shortest close call edge should be moved into a position where
|
// The shortest close call edge should be moved into a position where
|
||||||
// it contributes if the winding is transitioning to or from zero.
|
// it contributes if the winding is transitioning to or from zero.
|
||||||
@ -1654,8 +1691,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool swapUnordered(const ActiveEdge* edge, SkScalar bottom) const {
|
bool swapUnordered(const ActiveEdge* edge, SkScalar bottom) const {
|
||||||
SkASSERT(lastVerb() != SkPath::kLine_Verb
|
SkASSERT(fVerb != SkPath::kLine_Verb
|
||||||
|| edge->lastVerb() != SkPath::kLine_Verb);
|
|| edge->fVerb != SkPath::kLine_Verb);
|
||||||
if (fDone || edge->fDone) {
|
if (fDone || edge->fDone) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1670,24 +1707,24 @@ public:
|
|||||||
double t1, t2, b1, b2;
|
double t1, t2, b1, b2;
|
||||||
// This logic must be kept in sync with operator <
|
// This logic must be kept in sync with operator <
|
||||||
if (edge->fAbove.fY < fAbove.fY) {
|
if (edge->fAbove.fY < fAbove.fY) {
|
||||||
t1 = (edge->fBelow.fY - edge->fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
t1 = (edge->fTangent.fY - edge->fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
||||||
t2 = (fAbove.fY - edge->fAbove.fY) * (edge->fBelow.fX - edge->fAbove.fX);
|
t2 = (fAbove.fY - edge->fAbove.fY) * (edge->fTangent.fX - edge->fAbove.fX);
|
||||||
} else if (edge->fAbove.fY > fAbove.fY) {
|
} else if (edge->fAbove.fY > fAbove.fY) {
|
||||||
t1 = (fBelow.fY - fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
t1 = (fTangent.fY - fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
|
||||||
t2 = (fAbove.fY - edge->fAbove.fY) * (fBelow.fX - fAbove.fX);
|
t2 = (fAbove.fY - edge->fAbove.fY) * (fTangent.fX - fAbove.fX);
|
||||||
} else {
|
} else {
|
||||||
t1 = fAbove.fX;
|
t1 = fAbove.fX;
|
||||||
t2 = edge->fAbove.fX;
|
t2 = edge->fAbove.fX;
|
||||||
}
|
}
|
||||||
if (edge->fBelow.fY > fBelow.fY) {
|
if (edge->fTangent.fY > fTangent.fY) {
|
||||||
b1 = (edge->fBelow.fY - edge->fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
|
b1 = (edge->fTangent.fY - edge->fAbove.fY) * (fTangent.fX - edge->fTangent.fX);
|
||||||
b2 = (fBelow.fY - edge->fBelow.fY) * (edge->fBelow.fX - edge->fAbove.fX);
|
b2 = (fTangent.fY - edge->fTangent.fY) * (edge->fTangent.fX - edge->fAbove.fX);
|
||||||
} else if (edge->fBelow.fY < fBelow.fY) {
|
} else if (edge->fTangent.fY < fTangent.fY) {
|
||||||
b1 = (fBelow.fY - fAbove.fY) * (fBelow.fX - edge->fBelow.fX);
|
b1 = (fTangent.fY - fAbove.fY) * (fTangent.fX - edge->fTangent.fX);
|
||||||
b2 = (fBelow.fY - edge->fBelow.fY) * (fBelow.fX - fAbove.fX);
|
b2 = (fTangent.fY - edge->fTangent.fY) * (fTangent.fX - fAbove.fX);
|
||||||
} else {
|
} else {
|
||||||
b1 = fBelow.fX;
|
b1 = fTangent.fX;
|
||||||
b2 = edge->fBelow.fX;
|
b2 = edge->fTangent.fX;
|
||||||
}
|
}
|
||||||
if (fabs(t1 - t2) > fabs(b1 - b2)) {
|
if (fabs(t1 - t2) > fabs(b1 - b2)) {
|
||||||
ulps = UlpsDiff(t1, t2);
|
ulps = UlpsDiff(t1, t2);
|
||||||
@ -1701,32 +1738,30 @@ public:
|
|||||||
if (ulps < 0 || ulps > 32) {
|
if (ulps < 0 || ulps > 32) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SkPath::Verb verb = lastVerb();
|
if (fVerb == SkPath::kLine_Verb && edge->fVerb == SkPath::kLine_Verb) {
|
||||||
SkPath::Verb edgeVerb = edge->lastVerb();
|
|
||||||
if (verb == SkPath::kLine_Verb && edgeVerb == SkPath::kLine_Verb) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (verb != SkPath::kLine_Verb && edgeVerb != SkPath::kLine_Verb) {
|
if (fVerb != SkPath::kLine_Verb && edge->fVerb != SkPath::kLine_Verb) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ts[2];
|
double ts[2];
|
||||||
bool isLine = true;
|
bool isLine = true;
|
||||||
bool curveQuad = true;
|
bool curveQuad = true;
|
||||||
if (verb == SkPath::kCubic_Verb) {
|
if (fVerb == SkPath::kCubic_Verb) {
|
||||||
ts[0] = (fTAbove * 2 + fTBelow) / 3;
|
ts[0] = (fTAbove * 2 + fTBelow) / 3;
|
||||||
ts[1] = (fTAbove + fTBelow * 2) / 3;
|
ts[1] = (fTAbove + fTBelow * 2) / 3;
|
||||||
curveQuad = isLine = false;
|
curveQuad = isLine = false;
|
||||||
} else if (edgeVerb == SkPath::kCubic_Verb) {
|
} else if (edge->fVerb == SkPath::kCubic_Verb) {
|
||||||
ts[0] = (edge->fTAbove * 2 + edge->fTBelow) / 3;
|
ts[0] = (edge->fTAbove * 2 + edge->fTBelow) / 3;
|
||||||
ts[1] = (edge->fTAbove + edge->fTBelow * 2) / 3;
|
ts[1] = (edge->fTAbove + edge->fTBelow * 2) / 3;
|
||||||
curveQuad = false;
|
curveQuad = false;
|
||||||
} else if (verb == SkPath::kQuad_Verb) {
|
} else if (fVerb == SkPath::kQuad_Verb) {
|
||||||
ts[0] = fTAbove;
|
ts[0] = fTAbove;
|
||||||
ts[1] = (fTAbove + fTBelow) / 2;
|
ts[1] = (fTAbove + fTBelow) / 2;
|
||||||
isLine = false;
|
isLine = false;
|
||||||
} else {
|
} else {
|
||||||
SkASSERT(edgeVerb == SkPath::kQuad_Verb);
|
SkASSERT(edge->fVerb == SkPath::kQuad_Verb);
|
||||||
ts[0] = edge->fTAbove;
|
ts[0] = edge->fTAbove;
|
||||||
ts[1] = (edge->fTAbove + edge->fTBelow) / 2;
|
ts[1] = (edge->fTAbove + edge->fTBelow) / 2;
|
||||||
}
|
}
|
||||||
@ -1775,10 +1810,10 @@ private:
|
|||||||
// utility used only by swapUnordered
|
// utility used only by swapUnordered
|
||||||
void extractAboveBelow(ActiveEdge& extracted) const {
|
void extractAboveBelow(ActiveEdge& extracted) const {
|
||||||
SkPoint curve[4];
|
SkPoint curve[4];
|
||||||
switch (lastVerb()) {
|
switch (fVerb) {
|
||||||
case SkPath::kLine_Verb:
|
case SkPath::kLine_Verb:
|
||||||
extracted.fAbove = fAbove;
|
extracted.fAbove = fAbove;
|
||||||
extracted.fBelow = fBelow;
|
extracted.fTangent = fTangent;
|
||||||
return;
|
return;
|
||||||
case SkPath::kQuad_Verb:
|
case SkPath::kQuad_Verb:
|
||||||
QuadSubDivide(lastPoints(), fTAbove, fTBelow, curve);
|
QuadSubDivide(lastPoints(), fTAbove, fTBelow, curve);
|
||||||
@ -1790,19 +1825,21 @@ private:
|
|||||||
SkASSERT(0);
|
SkASSERT(0);
|
||||||
}
|
}
|
||||||
extracted.fAbove = curve[0];
|
extracted.fAbove = curve[0];
|
||||||
extracted.fBelow = curve[1];
|
extracted.fTangent = curve[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WorkEdge fWorkEdge;
|
WorkEdge fWorkEdge;
|
||||||
const SkTDArray<double>* fTs;
|
const SkTDArray<double>* fTs;
|
||||||
SkPoint fAbove;
|
SkPoint fAbove;
|
||||||
|
SkPoint fTangent;
|
||||||
SkPoint fBelow;
|
SkPoint fBelow;
|
||||||
double fTAbove; // OPTIMIZATION: only required if edge has quads or cubics
|
double fTAbove; // OPTIMIZATION: only required if edge has quads or cubics
|
||||||
double fTBelow;
|
double fTBelow;
|
||||||
SkScalar fYBottom;
|
SkScalar fYBottom;
|
||||||
int fCoincident;
|
int fCoincident;
|
||||||
int fTIndex;
|
int fTIndex;
|
||||||
|
SkPath::Verb fVerb;
|
||||||
bool fSkip; // OPTIMIZATION: use bitfields?
|
bool fSkip; // OPTIMIZATION: use bitfields?
|
||||||
bool fCloseCall;
|
bool fCloseCall;
|
||||||
bool fDone;
|
bool fDone;
|
||||||
@ -2253,17 +2290,16 @@ static SkScalar adjustCoincident(SkTDArray<ActiveEdge*>& edgeList,
|
|||||||
for (index = 1; index < edgeCount; ++index) {
|
for (index = 1; index < edgeCount; ++index) {
|
||||||
activePtr = nextPtr;
|
activePtr = nextPtr;
|
||||||
nextPtr = edgeList[index];
|
nextPtr = edgeList[index];
|
||||||
if (firstIndex != index - 1 && !activePtr->fSkip) {
|
if (firstIndex != index - 1 && activePtr->fVerb > SkPath::kLine_Verb
|
||||||
if (nextPtr->fWorkEdge.verb() == SkPath::kLine_Verb
|
&& nextPtr->fVerb == SkPath::kLine_Verb
|
||||||
&& activePtr->isUnordered(nextPtr)) {
|
&& activePtr->isUnordered(nextPtr)) {
|
||||||
start here;
|
// swap the line with the curve
|
||||||
// swap the line with the curve
|
// back up to the previous edge and retest
|
||||||
// back up to the previous edge and retest
|
SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
|
||||||
SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
|
SkASSERT(index > 1);
|
||||||
SkASSERT(index > 1);
|
index -= 2;
|
||||||
index -= 2;
|
nextPtr = edgeList[index];
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool closeCall = false;
|
bool closeCall = false;
|
||||||
activePtr->fCoincident = firstIndex;
|
activePtr->fCoincident = firstIndex;
|
||||||
@ -2444,9 +2480,9 @@ static void stitchEdge(SkTDArray<ActiveEdge*>& edgeList, SkScalar y,
|
|||||||
bool moreToDo, aboveBottom;
|
bool moreToDo, aboveBottom;
|
||||||
do {
|
do {
|
||||||
double currentT = activePtr->t();
|
double currentT = activePtr->t();
|
||||||
uint8_t verb = wt.verb();
|
|
||||||
const SkPoint* points = wt.fPts;
|
const SkPoint* points = wt.fPts;
|
||||||
double nextT;
|
double nextT;
|
||||||
|
SkPath::Verb verb = activePtr->fVerb;
|
||||||
do {
|
do {
|
||||||
nextT = activePtr->nextT();
|
nextT = activePtr->nextT();
|
||||||
// FIXME: obtuse: want efficient way to say
|
// FIXME: obtuse: want efficient way to say
|
||||||
@ -2503,9 +2539,10 @@ static void stitchEdge(SkTDArray<ActiveEdge*>& edgeList, SkScalar y,
|
|||||||
// will use these values if they're still valid instead of
|
// will use these values if they're still valid instead of
|
||||||
// recomputing
|
// recomputing
|
||||||
if (clipped[verb].fY > activePtr->fBelow.fY
|
if (clipped[verb].fY > activePtr->fBelow.fY
|
||||||
&& bottom >= activePtr->fBelow.fY ) {
|
&& bottom >= activePtr->fBelow.fY
|
||||||
|
&& verb == SkPath::kLine_Verb) {
|
||||||
activePtr->fAbove = activePtr->fBelow;
|
activePtr->fAbove = activePtr->fBelow;
|
||||||
activePtr->fBelow = clipped[verb];
|
activePtr->fBelow = activePtr->fTangent = clipped[verb];
|
||||||
activePtr->fTAbove = activePtr->fTBelow < 1
|
activePtr->fTAbove = activePtr->fTBelow < 1
|
||||||
? activePtr->fTBelow : 0;
|
? activePtr->fTBelow : 0;
|
||||||
activePtr->fTBelow = nextT;
|
activePtr->fTBelow = nextT;
|
||||||
@ -2609,6 +2646,17 @@ void simplify(const SkPath& path, bool asFill, SkPath& simple) {
|
|||||||
// if a quadratic or cubic now has an intermediate T value, see if the Ts
|
// if a quadratic or cubic now has an intermediate T value, see if the Ts
|
||||||
// on either side cause the Y values to monotonically increase. If not, split
|
// on either side cause the Y values to monotonically increase. If not, split
|
||||||
// the curve at the new T.
|
// the curve at the new T.
|
||||||
|
|
||||||
|
// try an alternate approach which does not split curves or stitch edges
|
||||||
|
// (may still need adjustCoincident, though)
|
||||||
|
// the idea is to output non-intersecting contours, then figure out their
|
||||||
|
// respective winding contribution
|
||||||
|
// each contour will need to know whether it is CW or CCW, and then whether
|
||||||
|
// a ray from that contour hits any a contour that contains it. The ray can
|
||||||
|
// move to the left and then arbitrarily move up or down (as long as it never
|
||||||
|
// moves to the right) to find a reference sibling contour or containing
|
||||||
|
// contour. If the contour is part of an intersection, the companion contour
|
||||||
|
// that is part of the intersection can determine the containership.
|
||||||
if (builder.containsCurves()) {
|
if (builder.containsCurves()) {
|
||||||
currentPtr = edgeList.begin();
|
currentPtr = edgeList.begin();
|
||||||
SkTArray<InEdge> splits;
|
SkTArray<InEdge> splits;
|
||||||
|
101
experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp
Normal file
101
experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "EdgeWalker_Test.h"
|
||||||
|
#include "Intersection_Tests.h"
|
||||||
|
#include "SkBitmap.h"
|
||||||
|
#include "SkCanvas.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void* testSimplify4x4QuadraticsMain(void* data)
|
||||||
|
{
|
||||||
|
char pathStr[1024];
|
||||||
|
bzero(pathStr, sizeof(pathStr));
|
||||||
|
SkASSERT(data);
|
||||||
|
State4& state = *(State4*) data;
|
||||||
|
int ax = state.a & 0x03;
|
||||||
|
int ay = state.a >> 2;
|
||||||
|
int bx = state.b & 0x03;
|
||||||
|
int by = state.b >> 2;
|
||||||
|
int cx = state.c & 0x03;
|
||||||
|
int cy = state.c >> 2;
|
||||||
|
int dx = state.d & 0x03;
|
||||||
|
int dy = state.d >> 2;
|
||||||
|
for (int e = 0 ; e < 16; ++e) {
|
||||||
|
int ex = e & 0x03;
|
||||||
|
int ey = e >> 2;
|
||||||
|
for (int f = e ; f < 16; ++f) {
|
||||||
|
int fx = f & 0x03;
|
||||||
|
int fy = f >> 2;
|
||||||
|
for (int g = f ; g < 16; ++g) {
|
||||||
|
int gx = g & 0x03;
|
||||||
|
int gy = g >> 2;
|
||||||
|
for (int h = g ; h < 16; ++h) {
|
||||||
|
int hx = h & 0x03;
|
||||||
|
int hy = h >> 2;
|
||||||
|
SkPath path, out;
|
||||||
|
path.setFillType(SkPath::kWinding_FillType);
|
||||||
|
path.moveTo(ax, ay);
|
||||||
|
path.quadTo(bx, by, cx, cy);
|
||||||
|
path.lineTo(dx, dy);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(ex, ey);
|
||||||
|
path.lineTo(fx, fy);
|
||||||
|
path.quadTo(gx, gy, hx, hy);
|
||||||
|
path.close();
|
||||||
|
if (1) { // gdb: set print elements 400
|
||||||
|
char* str = pathStr;
|
||||||
|
str += sprintf(str, " path.moveTo(%d, %d);\n", ax, ay);
|
||||||
|
str += sprintf(str, " path.quadTo(%d, %d, %d, %d);\n", bx, by, cx, cy);
|
||||||
|
str += sprintf(str, " path.lineTo(%d, %d);\n", dx, dy);
|
||||||
|
str += sprintf(str, " path.close();\n");
|
||||||
|
str += sprintf(str, " path.moveTo(%d, %d);\n", ex, ey);
|
||||||
|
str += sprintf(str, " path.lineTo(%d, %d);\n", fx, fy);
|
||||||
|
str += sprintf(str, " path.quadTo(%d, %d, %d, %d);\n", gx, gy, hx, hy);
|
||||||
|
str += sprintf(str, " path.close();");
|
||||||
|
}
|
||||||
|
if (!testSimplify(path, true, out, state.bitmap, state.canvas)) {
|
||||||
|
SkDebugf("*/\n{ SkPath::kWinding_FillType, %d, %d, %d, %d,"
|
||||||
|
" %d, %d, %d, %d },\n/*\n", state.a, state.b, state.c, state.d,
|
||||||
|
e, f, g, h);
|
||||||
|
}
|
||||||
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||||
|
if (!testSimplify(path, true, out, state.bitmap, state.canvas)) {
|
||||||
|
SkDebugf("*/\n{ SkPath::kEvenOdd_FillType, %d, %d, %d, %d,"
|
||||||
|
" %d, %d, %d, %d },\n/*\n", state.a, state.b, state.c, state.d,
|
||||||
|
e, f, g, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int maxThreads = gRunTestsInOneThread ? 1 : 24;
|
||||||
|
|
||||||
|
void Simplify4x4QuadraticsThreaded_Test()
|
||||||
|
{
|
||||||
|
State4 threadState[maxThreads];
|
||||||
|
int threadIndex = 0;
|
||||||
|
for (int a = 0; a < 16; ++a) {
|
||||||
|
for (int b = a ; b < 16; ++b) {
|
||||||
|
for (int c = b ; c < 16; ++c) {
|
||||||
|
for (int d = c; d < 16; ++d) {
|
||||||
|
State4* statePtr = &threadState[threadIndex];
|
||||||
|
statePtr->a = a;
|
||||||
|
statePtr->b = b;
|
||||||
|
statePtr->c = c;
|
||||||
|
statePtr->d = d;
|
||||||
|
if (maxThreads > 1) {
|
||||||
|
createThread(statePtr, testSimplify4x4QuadraticsMain);
|
||||||
|
if (++threadIndex >= maxThreads) {
|
||||||
|
waitForCompletion(threadState, threadIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
testSimplify4x4QuadraticsMain(statePtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waitForCompletion(threadState, threadIndex);
|
||||||
|
}
|
@ -218,7 +218,22 @@ static void testSimplifyQuadratic16() {
|
|||||||
drawAsciiPaths(path, out, true);
|
drawAsciiPaths(path, out, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testSimplifyQuadratic17() {
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 0, 0, 0);
|
||||||
|
path.lineTo(2, 2);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 1);
|
||||||
|
path.lineTo(0, 1);
|
||||||
|
path.quadTo(2, 1, 3, 3);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void (*simplifyTests[])() = {
|
static void (*simplifyTests[])() = {
|
||||||
|
testSimplifyQuadratic17,
|
||||||
testSimplifyQuadratic16,
|
testSimplifyQuadratic16,
|
||||||
testSimplifyQuadratic15,
|
testSimplifyQuadratic15,
|
||||||
testSimplifyQuadratic14,
|
testSimplifyQuadratic14,
|
||||||
@ -239,7 +254,7 @@ static void (*simplifyTests[])() = {
|
|||||||
|
|
||||||
static size_t simplifyTestsCount = sizeof(simplifyTests) / sizeof(simplifyTests[0]);
|
static size_t simplifyTestsCount = sizeof(simplifyTests) / sizeof(simplifyTests[0]);
|
||||||
|
|
||||||
static void (*firstTest)() = 0;
|
static void (*firstTest)() = testSimplifyQuadratic14;
|
||||||
static bool skipAll = false;
|
static bool skipAll = false;
|
||||||
|
|
||||||
void SimplifyQuadraticPaths_Test() {
|
void SimplifyQuadraticPaths_Test() {
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
#include "DataTypes.h"
|
#include "DataTypes.h"
|
||||||
#include "Extrema.h"
|
#include "Extrema.h"
|
||||||
|
|
||||||
static int valid_unit_divide(double numer, double denom, double* ratio)
|
static int validUnitDivide(double numer, double denom, double* ratio)
|
||||||
{
|
{
|
||||||
if (numer < 0)
|
if (numer < 0) {
|
||||||
{
|
|
||||||
numer = -numer;
|
numer = -numer;
|
||||||
denom = -denom;
|
denom = -denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (denom == 0 || numer == 0 || numer >= denom)
|
if (denom == 0 || numer == 0 || numer >= denom)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double r = numer / denom;
|
double r = numer / denom;
|
||||||
if (r == 0) // catch underflow if numer <<<< denom
|
if (r == 0) { // catch underflow if numer <<<< denom
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
*ratio = r;
|
*ratio = r;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -25,10 +23,10 @@ static int valid_unit_divide(double numer, double denom, double* ratio)
|
|||||||
x1 = Q / A
|
x1 = Q / A
|
||||||
x2 = C / Q
|
x2 = C / Q
|
||||||
*/
|
*/
|
||||||
static int SkFindUnitQuadRoots(double A, double B, double C, double roots[2])
|
static int findUnitQuadRoots(double A, double B, double C, double roots[2])
|
||||||
{
|
{
|
||||||
if (A == 0)
|
if (A == 0)
|
||||||
return valid_unit_divide(-C, B, roots);
|
return validUnitDivide(-C, B, roots);
|
||||||
|
|
||||||
double* r = roots;
|
double* r = roots;
|
||||||
|
|
||||||
@ -39,8 +37,8 @@ static int SkFindUnitQuadRoots(double A, double B, double C, double roots[2])
|
|||||||
R = sqrt(R);
|
R = sqrt(R);
|
||||||
|
|
||||||
double Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
|
double Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
|
||||||
r += valid_unit_divide(Q, A, r);
|
r += validUnitDivide(Q, A, r);
|
||||||
r += valid_unit_divide(C, Q, r);
|
r += validUnitDivide(C, Q, r);
|
||||||
if (r - roots == 2 && approximately_equal(roots[0], roots[1])) { // nearly-equal?
|
if (r - roots == 2 && approximately_equal(roots[0], roots[1])) { // nearly-equal?
|
||||||
r -= 1; // skip the double root
|
r -= 1; // skip the double root
|
||||||
}
|
}
|
||||||
@ -51,16 +49,16 @@ static int SkFindUnitQuadRoots(double A, double B, double C, double roots[2])
|
|||||||
A = 3(-a + 3(b - c) + d)
|
A = 3(-a + 3(b - c) + d)
|
||||||
B = 6(a - 2b + c)
|
B = 6(a - 2b + c)
|
||||||
C = 3(b - a)
|
C = 3(b - a)
|
||||||
Solve for t, keeping only those that fit betwee 0 < t < 1
|
Solve for t, keeping only those that fit between 0 < t < 1
|
||||||
*/
|
*/
|
||||||
int SkFindCubicExtrema(double a, double b, double c, double d, double tValues[2])
|
int findExtrema(double a, double b, double c, double d, double tValues[2])
|
||||||
{
|
{
|
||||||
// we divide A,B,C by 3 to simplify
|
// we divide A,B,C by 3 to simplify
|
||||||
double A = d - a + 3*(b - c);
|
double A = d - a + 3*(b - c);
|
||||||
double B = 2*(a - b - b + c);
|
double B = 2*(a - b - b + c);
|
||||||
double C = b - a;
|
double C = b - a;
|
||||||
|
|
||||||
return SkFindUnitQuadRoots(A, B, C, tValues);
|
return findUnitQuadRoots(A, B, C, tValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Quad'(t) = At + B, where
|
/** Quad'(t) = At + B, where
|
||||||
@ -68,10 +66,10 @@ int SkFindCubicExtrema(double a, double b, double c, double d, double tValues[2]
|
|||||||
B = 2(b - a)
|
B = 2(b - a)
|
||||||
Solve for t, only if it fits between 0 < t < 1
|
Solve for t, only if it fits between 0 < t < 1
|
||||||
*/
|
*/
|
||||||
int SkFindQuadExtrema(double a, double b, double c, double tValue[1])
|
int findExtrema(double a, double b, double c, double tValue[1])
|
||||||
{
|
{
|
||||||
/* At + B == 0
|
/* At + B == 0
|
||||||
t = -B / A
|
t = -B / A
|
||||||
*/
|
*/
|
||||||
return valid_unit_divide(a - b, a - b - b + c, tValue);
|
return validUnitDivide(a - b, a - b - b + c, tValue);
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
int SkFindCubicExtrema(double a, double b, double c, double d, double tValues[2]);
|
int findExtrema(double a, double b, double c, double d, double tValues[2]);
|
||||||
int SkFindQuadExtrema(double a, double b, double c, double tValue[1]);
|
int findExtrema(double a, double b, double c, double tValue[1]);
|
||||||
|
@ -4,12 +4,10 @@
|
|||||||
void cubecode_test(int test);
|
void cubecode_test(int test);
|
||||||
void testSimplify();
|
void testSimplify();
|
||||||
|
|
||||||
#define TEST_QUADS_FIRST 01
|
#define TEST_QUADS_FIRST 0
|
||||||
|
|
||||||
void Intersection_Tests() {
|
void Intersection_Tests() {
|
||||||
#if !TEST_QUADS_FIRST
|
SimplifyAddIntersectingTs_Test();
|
||||||
ActiveEdge_Test();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cubecode_test(1);
|
cubecode_test(1);
|
||||||
convert_testx();
|
convert_testx();
|
||||||
@ -29,8 +27,8 @@ void Intersection_Tests() {
|
|||||||
SimplifyRectangularPaths_Test();
|
SimplifyRectangularPaths_Test();
|
||||||
SimplifyQuadralateralPaths_Test();
|
SimplifyQuadralateralPaths_Test();
|
||||||
|
|
||||||
#if TEST_QUADS_FIRST
|
|
||||||
ActiveEdge_Test();
|
ActiveEdge_Test();
|
||||||
|
#if TEST_QUADS_FIRST
|
||||||
Simplify4x4QuadraticsThreaded_Test();
|
Simplify4x4QuadraticsThreaded_Test();
|
||||||
#endif
|
#endif
|
||||||
SimplifyDegenerate4x4TrianglesThreaded_Test();
|
SimplifyDegenerate4x4TrianglesThreaded_Test();
|
||||||
|
@ -12,6 +12,7 @@ void LineCubicIntersection_Test();
|
|||||||
void LineIntersection_Test();
|
void LineIntersection_Test();
|
||||||
void LineParameter_Test();
|
void LineParameter_Test();
|
||||||
void LineQuadraticIntersection_Test();
|
void LineQuadraticIntersection_Test();
|
||||||
|
void SimplifyAddIntersectingTs_Test();
|
||||||
void SimplifyDegenerate4x4TrianglesThreaded_Test();
|
void SimplifyDegenerate4x4TrianglesThreaded_Test();
|
||||||
void SimplifyNondegenerate4x4TrianglesThreaded_Test();
|
void SimplifyNondegenerate4x4TrianglesThreaded_Test();
|
||||||
void SimplifyPolygonPaths_Test();
|
void SimplifyPolygonPaths_Test();
|
||||||
|
@ -109,6 +109,13 @@ int horizontalIntersect(double axisIntercept) {
|
|||||||
return cubicRoots(A, B, C, D, range);
|
return cubicRoots(A, B, C, D, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(double axisIntercept) {
|
||||||
|
double A, B, C, D;
|
||||||
|
coefficients(&cubic[0].x, A, B, C, D);
|
||||||
|
D -= axisIntercept;
|
||||||
|
return cubicRoots(A, B, C, D, range);
|
||||||
|
}
|
||||||
|
|
||||||
double findLineT(double t) {
|
double findLineT(double t) {
|
||||||
const double* cPtr;
|
const double* cPtr;
|
||||||
const double* lPtr;
|
const double* lPtr;
|
||||||
@ -158,6 +165,56 @@ int horizontalIntersect(const Cubic& cubic, double left, double right, double y,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int horizontalIntersect(const Cubic& cubic, double left, double right, double y,
|
||||||
|
bool flipped, Intersections& intersections) {
|
||||||
|
LineCubicIntersections c(cubic, *((_Line*) 0), intersections.fT[0]);
|
||||||
|
int result = c.horizontalIntersect(y);
|
||||||
|
for (int index = 0; index < result; ) {
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(cubic, intersections.fT[0][index], x, y);
|
||||||
|
if (x < left || x > right) {
|
||||||
|
if (--result > index) {
|
||||||
|
intersections.fT[0][index] = intersections.fT[0][result];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
intersections.fT[0][index] = (x - left) / (right - left);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0].x
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(const Cubic& cubic, double top, double bottom, double x,
|
||||||
|
bool flipped, Intersections& intersections) {
|
||||||
|
LineCubicIntersections c(cubic, *((_Line*) 0), intersections.fT[0]);
|
||||||
|
int result = c.verticalIntersect(x);
|
||||||
|
for (int index = 0; index < result; ) {
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(cubic, intersections.fT[0][index], x, y);
|
||||||
|
if (y < top || y > bottom) {
|
||||||
|
if (--result > index) {
|
||||||
|
intersections.fT[0][index] = intersections.fT[0][result];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
intersections.fT[0][index] = (y - top) / (bottom - top);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0].x
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]) {
|
int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]) {
|
||||||
LineCubicIntersections c(cubic, line, cRange);
|
LineCubicIntersections c(cubic, line, cRange);
|
||||||
int roots;
|
int roots;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "DataTypes.h"
|
#include "DataTypes.h"
|
||||||
|
#include "Intersections.h"
|
||||||
#include "LineIntersection.h"
|
#include "LineIntersection.h"
|
||||||
#include <algorithm> // used for std::swap
|
#include <algorithm> // used for std::swap
|
||||||
|
|
||||||
@ -112,9 +113,9 @@ int horizontalLineIntersect(const _Line& line, double left, double right,
|
|||||||
double y, double tRange[2]) {
|
double y, double tRange[2]) {
|
||||||
int result = horizontalIntersect(line, y, tRange);
|
int result = horizontalIntersect(line, y, tRange);
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
|
// FIXME: this is incorrect if result == 2
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// FIXME: this is incorrect if result == 2
|
|
||||||
double xIntercept = line[0].x + tRange[0] * (line[1].x - line[0].x);
|
double xIntercept = line[0].x + tRange[0] * (line[1].x - line[0].x);
|
||||||
if (xIntercept > right || xIntercept < left) {
|
if (xIntercept > right || xIntercept < left) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -122,6 +123,116 @@ int horizontalLineIntersect(const _Line& line, double left, double right,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int horizontalIntersect(const _Line& line, double left, double right,
|
||||||
|
double y, bool flipped, Intersections& intersections) {
|
||||||
|
int result = horizontalIntersect(line, y, intersections.fT[0]);
|
||||||
|
switch (result) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
double xIntercept = line[0].x + intersections.fT[0][0]
|
||||||
|
* (line[1].x - line[0].x);
|
||||||
|
if (xIntercept > right || xIntercept < left) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
intersections.fT[1][0] = (xIntercept - left) / (right - left);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
double lineL = line[0].x;
|
||||||
|
double lineR = line[1].x;
|
||||||
|
if (lineL > lineR) {
|
||||||
|
std::swap(lineL, lineR);
|
||||||
|
}
|
||||||
|
double overlapL = std::max(left, lineL);
|
||||||
|
double overlapR = std::min(right, lineR);
|
||||||
|
if (overlapL > overlapR) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (overlapL == overlapR) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
intersections.fT[0][0] = (overlapL - line[0].x) / (line[1].x - line[0].x);
|
||||||
|
intersections.fT[1][0] = (overlapL - left) / (right - left);
|
||||||
|
if (result > 1) {
|
||||||
|
intersections.fT[0][1] = (overlapR - line[0].x) / (line[1].x - line[0].x);
|
||||||
|
intersections.fT[1][1] = (overlapR - left) / (right - left);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0].x
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(const _Line& line, double x, double tRange[2]) {
|
||||||
|
double min = line[0].x;
|
||||||
|
double max = line[1].x;
|
||||||
|
if (min > max) {
|
||||||
|
std::swap(min, max);
|
||||||
|
}
|
||||||
|
if (min > x || max < x) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (approximately_equal(min, max)) {
|
||||||
|
tRange[0] = 0;
|
||||||
|
tRange[1] = 1;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
tRange[0] = (x - line[0].x) / (line[1].x - line[0].x);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(const _Line& line, double top, double bottom,
|
||||||
|
double x, bool flipped, Intersections& intersections) {
|
||||||
|
int result = verticalIntersect(line, x, intersections.fT[0]);
|
||||||
|
switch (result) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
double yIntercept = line[0].y + intersections.fT[0][0]
|
||||||
|
* (line[1].y - line[0].y);
|
||||||
|
if (yIntercept > bottom || yIntercept < top) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
intersections.fT[1][0] = (yIntercept - top) / (bottom - top);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
double lineT = line[0].y;
|
||||||
|
double lineB = line[1].y;
|
||||||
|
if (lineT > lineB) {
|
||||||
|
std::swap(lineT, lineB);
|
||||||
|
}
|
||||||
|
double overlapT = std::max(top, lineT);
|
||||||
|
double overlapB = std::min(bottom, lineB);
|
||||||
|
if (overlapT > overlapB) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (overlapT == overlapB) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
intersections.fT[0][0] = (overlapT - line[0].y) / (line[1].y - line[0].y);
|
||||||
|
intersections.fT[1][0] = (overlapT - top) / (bottom - top);
|
||||||
|
if (result > 1) {
|
||||||
|
intersections.fT[0][1] = (overlapB - line[0].y) / (line[1].y - line[0].y);
|
||||||
|
intersections.fT[1][1] = (overlapB - top) / (bottom - top);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].y - [0].y
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.py
|
// from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.py
|
||||||
// 4 subs, 2 muls, 1 cmp
|
// 4 subs, 2 muls, 1 cmp
|
||||||
static bool ccw(const _Point& A, const _Point& B, const _Point& C) {
|
static bool ccw(const _Point& A, const _Point& B, const _Point& C) {
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
int horizontalIntersect(const _Line& line, double y, double tRange[2]);
|
int horizontalIntersect(const _Line& line, double y, double tRange[2]);
|
||||||
int horizontalLineIntersect(const _Line& line, double left, double right,
|
int horizontalLineIntersect(const _Line& line, double left, double right,
|
||||||
double y, double tRange[2]);
|
double y, double tRange[2]);
|
||||||
|
int verticalLineIntersect(const _Line& line, double top, double bottom,
|
||||||
|
double x, double tRange[2]);
|
||||||
int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]);
|
int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]);
|
||||||
bool testIntersect(const _Line& a, const _Line& b);
|
bool testIntersect(const _Line& a, const _Line& b);
|
||||||
|
|
||||||
|
@ -141,6 +141,16 @@ int horizontalIntersect(double axisIntercept) {
|
|||||||
return quadraticRoots(D, E, F, intersections.fT[0]);
|
return quadraticRoots(D, E, F, intersections.fT[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(double axisIntercept) {
|
||||||
|
double D = quad[2].x; // f
|
||||||
|
double E = quad[1].x; // e
|
||||||
|
double F = quad[0].x; // d
|
||||||
|
D += F - 2 * E; // D = d - 2*e + f
|
||||||
|
E -= F; // E = -(d - e)
|
||||||
|
F -= axisIntercept;
|
||||||
|
return quadraticRoots(D, E, F, intersections.fT[0]);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
double findLineT(double t) {
|
double findLineT(double t) {
|
||||||
@ -167,6 +177,46 @@ bool moreHorizontal;
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// utility for pairs of coincident quads
|
||||||
|
static double horizontalIntersect(const Quadratic& quad, const _Point& pt) {
|
||||||
|
Intersections intersections;
|
||||||
|
LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
|
||||||
|
int result = q.horizontalIntersect(pt.y);
|
||||||
|
if (result == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
assert(result == 1);
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(quad, intersections.fT[0][0], x, y);
|
||||||
|
if (approximately_equal(x, pt.x)) {
|
||||||
|
return intersections.fT[0][0];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double verticalIntersect(const Quadratic& quad, const _Point& pt) {
|
||||||
|
Intersections intersections;
|
||||||
|
LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
|
||||||
|
int result = q.horizontalIntersect(pt.x);
|
||||||
|
if (result == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
assert(result == 1);
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(quad, intersections.fT[0][0], x, y);
|
||||||
|
if (approximately_equal(y, pt.y)) {
|
||||||
|
return intersections.fT[0][0];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double axialIntersect(const Quadratic& q1, const _Point& p, bool vertical) {
|
||||||
|
if (vertical) {
|
||||||
|
return verticalIntersect(q1, p);
|
||||||
|
}
|
||||||
|
return horizontalIntersect(q1, p);
|
||||||
|
}
|
||||||
|
|
||||||
int horizontalIntersect(const Quadratic& quad, double left, double right,
|
int horizontalIntersect(const Quadratic& quad, double left, double right,
|
||||||
double y, double tRange[2]) {
|
double y, double tRange[2]) {
|
||||||
Intersections i;
|
Intersections i;
|
||||||
@ -184,6 +234,56 @@ int horizontalIntersect(const Quadratic& quad, double left, double right,
|
|||||||
return tCount;
|
return tCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int horizontalIntersect(const Quadratic& quad, double left, double right, double y,
|
||||||
|
bool flipped, Intersections& intersections) {
|
||||||
|
LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
|
||||||
|
int result = q.horizontalIntersect(y);
|
||||||
|
for (int index = 0; index < result; ) {
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(quad, intersections.fT[0][index], x, y);
|
||||||
|
if (x < left || x > right) {
|
||||||
|
if (--result > index) {
|
||||||
|
intersections.fT[0][index] = intersections.fT[0][result];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
intersections.fT[0][index] = (x - left) / (right - left);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0].x
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verticalIntersect(const Quadratic& quad, double top, double bottom, double x,
|
||||||
|
bool flipped, Intersections& intersections) {
|
||||||
|
LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
|
||||||
|
int result = q.verticalIntersect(x);
|
||||||
|
for (int index = 0; index < result; ) {
|
||||||
|
double x, y;
|
||||||
|
xy_at_t(quad, intersections.fT[0][index], x, y);
|
||||||
|
if (y < top || y > bottom) {
|
||||||
|
if (--result > index) {
|
||||||
|
intersections.fT[0][index] = intersections.fT[0][result];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
intersections.fT[0][index] = (y - top) / (bottom - top);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (flipped) {
|
||||||
|
// OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0].x
|
||||||
|
for (int index = 0; index < result; ++index) {
|
||||||
|
intersections.fT[1][index] = 1 - intersections.fT[1][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool intersect(const Quadratic& quad, const _Line& line, Intersections& i) {
|
bool intersect(const Quadratic& quad, const _Line& line, Intersections& i) {
|
||||||
LineQuadraticIntersections q(quad, line, i);
|
LineQuadraticIntersections q(quad, line, i);
|
||||||
return q.intersect();
|
return q.intersect();
|
||||||
|
@ -8,7 +8,9 @@ struct lineQuad {
|
|||||||
Quadratic quad;
|
Quadratic quad;
|
||||||
_Line line;
|
_Line line;
|
||||||
} lineQuadTests[] = {
|
} lineQuadTests[] = {
|
||||||
{{{0, 0}, {0, 1}, {1, 1}}, {{0, 1}, {1, 0}}}
|
{{{2, 0}, {1, 1}, {2, 2}}, {{0, 0}, {0, 2}}},
|
||||||
|
{{{4, 0}, {0, 1}, {4, 2}}, {{3, 1}, {4, 1}}},
|
||||||
|
{{{0, 0}, {0, 1}, {1, 1}}, {{0, 1}, {1, 0}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t lineQuadTests_count = sizeof(lineQuadTests) / sizeof(lineQuadTests[0]);
|
size_t lineQuadTests_count = sizeof(lineQuadTests) / sizeof(lineQuadTests[0]);
|
||||||
|
@ -30,3 +30,28 @@ void sub_divide(const _Line& line, double t1, double t2, _Line& dst) {
|
|||||||
dst[1].x = line[0].x - t2 * delta.x;
|
dst[1].x = line[0].x - t2 * delta.x;
|
||||||
dst[1].y = line[0].y - t2 * delta.y;
|
dst[1].y = line[0].y - t2 * delta.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// may have this below somewhere else already:
|
||||||
|
// copying here because I thought it was clever
|
||||||
|
|
||||||
|
// Copyright 2001, softSurfer (www.softsurfer.com)
|
||||||
|
// This code may be freely used and modified for any purpose
|
||||||
|
// providing that this copyright notice is included with it.
|
||||||
|
// SoftSurfer makes no warranty for this code, and cannot be held
|
||||||
|
// liable for any real or imagined damage resulting from its use.
|
||||||
|
// Users of this code must verify correctness for their application.
|
||||||
|
|
||||||
|
// Assume that a class is already given for the object:
|
||||||
|
// Point with coordinates {float x, y;}
|
||||||
|
//===================================================================
|
||||||
|
|
||||||
|
// isLeft(): tests if a point is Left|On|Right of an infinite line.
|
||||||
|
// Input: three points P0, P1, and P2
|
||||||
|
// Return: >0 for P2 left of the line through P0 and P1
|
||||||
|
// =0 for P2 on the line
|
||||||
|
// <0 for P2 right of the line
|
||||||
|
// See: the January 2001 Algorithm on Area of Triangles
|
||||||
|
float isLeft( _Point P0, _Point P1, _Point P2 )
|
||||||
|
{
|
||||||
|
return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y);
|
||||||
|
}
|
||||||
|
46
experimental/Intersection/QuadraticBounds.cpp
Normal file
46
experimental/Intersection/QuadraticBounds.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "DataTypes.h"
|
||||||
|
#include "Extrema.h"
|
||||||
|
|
||||||
|
static int isBoundedByEndPoints(double a, double b, double c)
|
||||||
|
{
|
||||||
|
return (a <= b && b <= c) || (a >= b && b >= c);
|
||||||
|
}
|
||||||
|
|
||||||
|
double leftMostT(const Quadratic& quad, double startT, double endT) {
|
||||||
|
double leftT;
|
||||||
|
if (findExtrema(quad[0].x, quad[1].x, quad[2].x, &leftT)
|
||||||
|
&& startT <= leftT && leftT <= endT) {
|
||||||
|
return leftT;
|
||||||
|
}
|
||||||
|
_Point startPt;
|
||||||
|
xy_at_t(quad, startT, startPt.x, startPt.y);
|
||||||
|
_Point endPt;
|
||||||
|
xy_at_t(quad, endT, endPt.x, endPt.y);
|
||||||
|
return startPt.x <= endPt.x ? startT : endT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Rect::setBounds(const Quadratic& quad) {
|
||||||
|
set(quad[0]);
|
||||||
|
add(quad[2]);
|
||||||
|
double tValues[2];
|
||||||
|
int roots = 0;
|
||||||
|
if (!isBoundedByEndPoints(quad[0].x, quad[1].x, quad[2].x)) {
|
||||||
|
roots = findExtrema(quad[0].x, quad[1].x, quad[2].x, tValues);
|
||||||
|
}
|
||||||
|
if (!isBoundedByEndPoints(quad[0].y, quad[1].y, quad[2].y)) {
|
||||||
|
roots += findExtrema(quad[0].y, quad[1].y, quad[2].y,
|
||||||
|
&tValues[roots]);
|
||||||
|
}
|
||||||
|
for (int x = 0; x < roots; ++x) {
|
||||||
|
_Point result;
|
||||||
|
xy_at_t(quad, tValues[x], result.x, result.y);
|
||||||
|
add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _Rect::setRawBounds(const Quadratic& quad) {
|
||||||
|
set(quad[0]);
|
||||||
|
for (int x = 1; x < 3; ++x) {
|
||||||
|
add(quad[x]);
|
||||||
|
}
|
||||||
|
}
|
@ -97,7 +97,6 @@ bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
|
|||||||
double newMinT2 = interp(minT2, maxT2, minT);
|
double newMinT2 = interp(minT2, maxT2, minT);
|
||||||
double newMaxT2 = interp(minT2, maxT2, maxT);
|
double newMaxT2 = interp(minT2, maxT2, maxT);
|
||||||
split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
|
split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
|
||||||
#define VERBOSE 0
|
|
||||||
#if VERBOSE
|
#if VERBOSE
|
||||||
printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
|
printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
|
||||||
splits, newMinT2, newMaxT2, minT2, maxT2, split);
|
splits, newMinT2, newMaxT2, minT2, maxT2, split);
|
||||||
@ -144,6 +143,35 @@ int splits;
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||||
|
if (implicit_matches(q1, q2)) {
|
||||||
|
// FIXME: compute T values
|
||||||
|
// compute the intersections of the ends to find the coincident span
|
||||||
|
bool useVertical = fabs(q1[0].x - q1[2].x) < fabs(q1[0].y - q1[2].y);
|
||||||
|
double t;
|
||||||
|
if ((t = axialIntersect(q1, q2[0], useVertical)) >= 0) {
|
||||||
|
i.fT[0][0] = t;
|
||||||
|
i.fT[1][0] = 0;
|
||||||
|
i.fUsed++;
|
||||||
|
}
|
||||||
|
if ((t = axialIntersect(q1, q2[2], useVertical)) >= 0) {
|
||||||
|
i.fT[0][i.fUsed] = t;
|
||||||
|
i.fT[1][i.fUsed] = 1;
|
||||||
|
i.fUsed++;
|
||||||
|
}
|
||||||
|
useVertical = fabs(q2[0].x - q2[2].x) < fabs(q2[0].y - q2[2].y);
|
||||||
|
if ((t = axialIntersect(q2, q1[0], useVertical)) >= 0) {
|
||||||
|
i.fT[0][i.fUsed] = 0;
|
||||||
|
i.fT[1][i.fUsed] = t;
|
||||||
|
i.fUsed++;
|
||||||
|
}
|
||||||
|
if ((t = axialIntersect(q2, q1[2], useVertical)) >= 0) {
|
||||||
|
i.fT[0][i.fUsed] = 1;
|
||||||
|
i.fT[1][i.fUsed] = t;
|
||||||
|
i.fUsed++;
|
||||||
|
}
|
||||||
|
assert(i.fUsed <= 2);
|
||||||
|
return i.fUsed > 0;
|
||||||
|
}
|
||||||
QuadraticIntersections q(q1, q2, i);
|
QuadraticIntersections q(q1, q2, i);
|
||||||
return q.intersect();
|
return q.intersect();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ static int vertical_line(const Quadratic& quad, Quadratic& reduction) {
|
|||||||
reduction[1] = quad[2];
|
reduction[1] = quad[2];
|
||||||
int smaller = reduction[1].y > reduction[0].y;
|
int smaller = reduction[1].y > reduction[0].y;
|
||||||
int larger = smaller ^ 1;
|
int larger = smaller ^ 1;
|
||||||
if (SkFindQuadExtrema(quad[0].y, quad[1].y, quad[2].y, &tValue)) {
|
if (findExtrema(quad[0].y, quad[1].y, quad[2].y, &tValue)) {
|
||||||
double yExtrema = interp_quad_coords(quad[0].y, quad[1].y, quad[2].y, tValue);
|
double yExtrema = interp_quad_coords(quad[0].y, quad[1].y, quad[2].y, tValue);
|
||||||
if (reduction[smaller].y > yExtrema) {
|
if (reduction[smaller].y > yExtrema) {
|
||||||
reduction[smaller].y = yExtrema;
|
reduction[smaller].y = yExtrema;
|
||||||
@ -38,7 +38,7 @@ static int horizontal_line(const Quadratic& quad, Quadratic& reduction) {
|
|||||||
reduction[1] = quad[2];
|
reduction[1] = quad[2];
|
||||||
int smaller = reduction[1].x > reduction[0].x;
|
int smaller = reduction[1].x > reduction[0].x;
|
||||||
int larger = smaller ^ 1;
|
int larger = smaller ^ 1;
|
||||||
if (SkFindQuadExtrema(quad[0].x, quad[1].x, quad[2].x, &tValue)) {
|
if (findExtrema(quad[0].x, quad[1].x, quad[2].x, &tValue)) {
|
||||||
double xExtrema = interp_quad_coords(quad[0].x, quad[1].x, quad[2].x, tValue);
|
double xExtrema = interp_quad_coords(quad[0].x, quad[1].x, quad[2].x, tValue);
|
||||||
if (reduction[smaller].x > xExtrema) {
|
if (reduction[smaller].x > xExtrema) {
|
||||||
reduction[smaller].x = xExtrema;
|
reduction[smaller].x = xExtrema;
|
||||||
@ -85,9 +85,9 @@ static int check_linear(const Quadratic& quad, Quadratic& reduction,
|
|||||||
double tValue;
|
double tValue;
|
||||||
int root;
|
int root;
|
||||||
if (useX) {
|
if (useX) {
|
||||||
root = SkFindQuadExtrema(quad[0].x, quad[1].x, quad[2].x, &tValue);
|
root = findExtrema(quad[0].x, quad[1].x, quad[2].x, &tValue);
|
||||||
} else {
|
} else {
|
||||||
root = SkFindQuadExtrema(quad[0].y, quad[1].y, quad[2].y, &tValue);
|
root = findExtrema(quad[0].y, quad[1].y, quad[2].y, &tValue);
|
||||||
}
|
}
|
||||||
if (root) {
|
if (root) {
|
||||||
_Point extrema;
|
_Point extrema;
|
||||||
@ -146,8 +146,8 @@ int reduceOrder(const Quadratic& quad, Quadratic& reduction) {
|
|||||||
minYSet |= 1 << index;
|
minYSet |= 1 << index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (minXSet == 0xF) { // test for vertical line
|
if (minXSet == 0x7) { // test for vertical line
|
||||||
if (minYSet == 0xF) { // return 1 if all four are coincident
|
if (minYSet == 0x7) { // return 1 if all four are coincident
|
||||||
return coincident_line(quad, reduction);
|
return coincident_line(quad, reduction);
|
||||||
}
|
}
|
||||||
return vertical_line(quad, reduction);
|
return vertical_line(quad, reduction);
|
||||||
|
@ -25,5 +25,3 @@ int quadraticRoots(double A, double B, double C, double t[2]) {
|
|||||||
}
|
}
|
||||||
return foundRoots;
|
return foundRoots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
#include "DataTypes.h"
|
|
||||||
#include "Extrema.h"
|
|
||||||
|
|
||||||
void _Rect::setBounds(const Cubic& cubic) {
|
|
||||||
set(cubic[0]);
|
|
||||||
add(cubic[3]);
|
|
||||||
double tValues[4];
|
|
||||||
int roots = SkFindCubicExtrema(cubic[0].x, cubic[1].x, cubic[2].x,
|
|
||||||
cubic[3].x, tValues);
|
|
||||||
roots += SkFindCubicExtrema(cubic[0].y, cubic[1].y, cubic[2].y, cubic[3].y,
|
|
||||||
&tValues[roots]);
|
|
||||||
for (int x = 0; x < roots; ++x) {
|
|
||||||
_Point result;
|
|
||||||
xy_at_t(cubic, tValues[x], result.x, result.y);
|
|
||||||
add(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _Rect::setRawBounds(const Cubic& cubic) {
|
|
||||||
set(cubic[0]);
|
|
||||||
for (int x = 1; x < 4; ++x) {
|
|
||||||
add(cubic[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _Rect::setBounds(const Quadratic& quad) {
|
|
||||||
set(quad[0]);
|
|
||||||
add(quad[2]);
|
|
||||||
double tValues[2];
|
|
||||||
int roots = SkFindQuadExtrema(quad[0].x, quad[1].x, quad[2].x, tValues);
|
|
||||||
roots += SkFindQuadExtrema(quad[0].y, quad[1].y, quad[2].y, &tValues[roots]);
|
|
||||||
for (int x = 0; x < roots; ++x) {
|
|
||||||
_Point result;
|
|
||||||
xy_at_t(quad, tValues[x], result.x, result.y);
|
|
||||||
add(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _Rect::setRawBounds(const Quadratic& quad) {
|
|
||||||
set(quad[0]);
|
|
||||||
for (int x = 1; x < 3; ++x) {
|
|
||||||
add(quad[x]);
|
|
||||||
}
|
|
||||||
}
|
|
1213
experimental/Intersection/Simplify.cpp
Normal file
1213
experimental/Intersection/Simplify.cpp
Normal file
File diff suppressed because it is too large
Load Diff
132
experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp
Normal file
132
experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#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"
|
||||||
|
|
||||||
|
namespace SimplifyAddIntersectingTsTest {
|
||||||
|
|
||||||
|
#include "Simplify.cpp"
|
||||||
|
|
||||||
|
} // end of SimplifyAddIntersectingTsTest namespace
|
||||||
|
|
||||||
|
#include "Intersection_Tests.h"
|
||||||
|
|
||||||
|
static const SkPoint lines[][2] = {
|
||||||
|
{{ 1, 1}, { 1, 1}}, // degenerate
|
||||||
|
{{ 1, 1}, { 4, 1}}, // horizontal
|
||||||
|
{{ 4, 1}, { 9, 1}},
|
||||||
|
{{ 2, 1}, { 3, 1}},
|
||||||
|
{{ 2, 1}, { 6, 1}},
|
||||||
|
{{ 5, 1}, { 9, 1}},
|
||||||
|
{{ 1, 1}, { 1, 4}}, // vertical
|
||||||
|
{{ 1, 2}, { 1, 3}},
|
||||||
|
{{ 1, 2}, { 1, 6}},
|
||||||
|
{{ 1, 5}, { 1, 9}},
|
||||||
|
{{ 1, 1}, { 3, 3}}, // diagonal
|
||||||
|
{{ 2, 2}, { 4, 4}},
|
||||||
|
{{ 2, 4}, { 4, 2}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t lineCount = sizeof(lines) / sizeof(lines[0]);
|
||||||
|
|
||||||
|
static const SkPoint quads[][3] = {
|
||||||
|
{{ 1, 1}, { 1, 1}, { 1, 1}}, // degenerate
|
||||||
|
{{ 1, 1}, { 4, 1}, { 5, 1}}, // line
|
||||||
|
{{ 1, 1}, { 4, 1}, { 4, 4}}, // curve
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t quadCount = sizeof(quads) / sizeof(quads[0]);
|
||||||
|
|
||||||
|
static const SkPoint cubics[][4] = {
|
||||||
|
{{ 1, 1}, { 1, 1}, { 1, 1}, { 1, 1}}, // degenerate
|
||||||
|
{{ 1, 1}, { 4, 1}, { 5, 1}, { 6, 1}}, // line
|
||||||
|
{{ 1, 1}, { 3, 1}, { 4, 2}, { 4, 4}}, // curve
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t cubicCount = sizeof(cubics) / sizeof(cubics[0]);
|
||||||
|
static const size_t testCount = lineCount + quadCount + cubicCount;
|
||||||
|
|
||||||
|
static SkPath::Verb setPath(int outer, SkPath& path, const SkPoint*& pts1) {
|
||||||
|
SkPath::Verb c1Type;
|
||||||
|
if (outer < lineCount) {
|
||||||
|
path.moveTo(lines[outer][0].fX, lines[outer][0].fY);
|
||||||
|
path.lineTo(lines[outer][1].fX, lines[outer][1].fY);
|
||||||
|
c1Type = SkPath::kLine_Verb;
|
||||||
|
pts1 = lines[outer];
|
||||||
|
} else {
|
||||||
|
outer -= lineCount;
|
||||||
|
if (outer < quadCount) {
|
||||||
|
path.moveTo(quads[outer][0].fX, quads[outer][0].fY);
|
||||||
|
path.quadTo(quads[outer][1].fX, quads[outer][1].fY,
|
||||||
|
quads[outer][2].fX, quads[outer][2].fY);
|
||||||
|
c1Type = SkPath::kQuad_Verb;
|
||||||
|
pts1 = quads[outer];
|
||||||
|
} else {
|
||||||
|
outer -= quadCount;
|
||||||
|
path.moveTo(cubics[outer][0].fX, cubics[outer][0].fY);
|
||||||
|
path.cubicTo(cubics[outer][1].fX, cubics[outer][1].fY,
|
||||||
|
cubics[outer][2].fX, cubics[outer][2].fY,
|
||||||
|
cubics[outer][3].fX, cubics[outer][3].fY);
|
||||||
|
c1Type = SkPath::kCubic_Verb;
|
||||||
|
pts1 = cubics[outer];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c1Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testPath(const SkPath& path, const SkPoint* pts1, SkPath::Verb c1Type,
|
||||||
|
const SkPoint* pts2, SkPath::Verb c2Type) {
|
||||||
|
SkTArray<SimplifyAddIntersectingTsTest::Contour> contour;
|
||||||
|
SimplifyAddIntersectingTsTest::EdgeBuilder builder(path, contour);
|
||||||
|
if (contour.count() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SimplifyAddIntersectingTsTest::Contour& c1 = contour[0];
|
||||||
|
SimplifyAddIntersectingTsTest::Contour& c2 = contour[1];
|
||||||
|
addIntersectingTs(&c1, &c2);
|
||||||
|
bool c1Intersected = c1.fSegments[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",
|
||||||
|
__FUNCTION__, SimplifyAddIntersectingTsTest::kLVerbStr[c1Type],
|
||||||
|
pts1[0].fX, pts1[0].fY,
|
||||||
|
pts1[c1Type].fX, pts1[c1Type].fY,
|
||||||
|
c1Intersected ? "intersects" : "does not intersect",
|
||||||
|
SimplifyAddIntersectingTsTest::kLVerbStr[c2Type],
|
||||||
|
pts2[0].fX, pts2[0].fY,
|
||||||
|
pts2[c2Type].fX, pts2[c2Type].fY);
|
||||||
|
if (c1Intersected) {
|
||||||
|
c1.dump();
|
||||||
|
c2.dump();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int firstO = 6;
|
||||||
|
static const int firstI = 1;
|
||||||
|
|
||||||
|
void SimplifyAddIntersectingTs_Test() {
|
||||||
|
const SkPoint* pts1, * pts2;
|
||||||
|
if (firstO > 0 || firstI > 0) {
|
||||||
|
SkPath path;
|
||||||
|
SkPath::Verb c1Type = setPath(firstO, path, pts1);
|
||||||
|
SkPath path2(path);
|
||||||
|
SkPath::Verb c2Type = setPath(firstI, path2, pts2);
|
||||||
|
testPath(path2, pts1, c1Type, pts2, c2Type);
|
||||||
|
}
|
||||||
|
for (int o = 0; o < testCount; ++o) {
|
||||||
|
SkPath path;
|
||||||
|
SkPath::Verb c1Type = setPath(o, path, pts1);
|
||||||
|
for (int i = 0; i < testCount; ++i) {
|
||||||
|
SkPath path2(path);
|
||||||
|
SkPath::Verb c2Type = setPath(i, path2, pts2);
|
||||||
|
testPath(path2, pts1, c1Type, pts2, c2Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,116 +1,133 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<div style="height:0">
|
<div style="height:0">
|
||||||
<div id="test_1div">
|
|
||||||
path.moveTo(213.673737, 413.292938);
|
<div id="testSimplifyQuadratic1">
|
||||||
path.lineTo(225.200134, 343.616821);
|
SkPath path, out;
|
||||||
path.lineTo(236.726532, 273.940704);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(219.386414, 231.373322);
|
path.quadTo(1, 0, 1, 1);
|
||||||
path.lineTo(213.673737, 413.292938);
|
path.close();
|
||||||
path.close();
|
path.moveTo(1, 0);
|
||||||
path.moveTo(43.485352, 308.984497);
|
path.quadTo(0, 0, 0, 1);
|
||||||
path.lineTo(122.610657, 305.950134);
|
path.close();
|
||||||
path.lineTo(201.735962, 302.915802);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(280.861267, 299.881470);
|
}
|
||||||
path.lineTo(43.485352, 308.984497);
|
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_2div">
|
|
||||||
path.moveTo(-177.878387, 265.368988);
|
<div id="testSimplifyQuadratic2">
|
||||||
path.lineTo(-254.415771, 303.709961);
|
SkPath path, out;
|
||||||
path.lineTo(-317.465363, 271.325562);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(-374.520386, 207.507660);
|
path.quadTo(20, 0, 20, 20);
|
||||||
path.lineTo(-177.878387, 265.368988);
|
path.close();
|
||||||
path.close();
|
path.moveTo(20, 0);
|
||||||
path.moveTo(-63.582489, -3.679123);
|
path.quadTo(0, 0, 0, 20);
|
||||||
path.lineTo(-134.496841, 26.434566);
|
path.close();
|
||||||
path.lineTo(-205.411209, 56.548256);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(-276.325562, 86.661942);
|
}
|
||||||
path.lineTo(-63.582489, -3.679123);
|
|
||||||
path.close();
|
|
||||||
path.moveTo(-57.078423, 162.633453);
|
|
||||||
path.lineTo(-95.963928, 106.261139);
|
|
||||||
path.lineTo(-134.849457, 49.888824);
|
|
||||||
path.lineTo(-173.734955, -6.483480);
|
|
||||||
path.lineTo(-57.078423, 162.633453);
|
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_3div">
|
|
||||||
path.moveTo(98.666489, -94.295059);
|
<div id="testSimplifyQuadratic3">
|
||||||
path.lineTo(156.584320, -61.939133);
|
SkPath path, out;
|
||||||
path.lineTo(174.672974, -12.343765);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(158.622345, 52.028267);
|
path.quadTo(20, 0, 20, 20);
|
||||||
path.lineTo(98.666489, -94.295059);
|
path.close();
|
||||||
path.close();
|
path.moveTo(0, 20);
|
||||||
path.moveTo(-133.225616, -48.622055);
|
path.quadTo(0, 0, 20, 0);
|
||||||
path.lineTo(-73.855499, -10.375397);
|
path.close();
|
||||||
path.lineTo(-14.485367, 27.871277);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(44.884750, 66.117935);
|
}
|
||||||
path.lineTo(-133.225616, -48.622055);
|
|
||||||
path.close();
|
|
||||||
path.moveTo( 9.030045, -163.413132);
|
|
||||||
path.lineTo(-19.605331, -89.588760);
|
|
||||||
path.lineTo(-48.240707, -15.764404);
|
|
||||||
path.lineTo(-76.876053, 58.059944);
|
|
||||||
path.lineTo( 9.030045, -163.413132);
|
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_4div">
|
|
||||||
path.moveTo(340.41568, -170.97171);
|
<div id="testSimplifyQuadratic4">
|
||||||
path.lineTo(418.846893, -142.428329);
|
SkPath path, out;
|
||||||
path.lineTo(497.278107, -113.884933);
|
path.moveTo(0, 20);
|
||||||
path.lineTo(449.18222, -45.6723022);
|
path.quadTo(20, 0, 40, 20);
|
||||||
path.lineTo(340.41568, -170.97171);
|
path.close();
|
||||||
path.close();
|
path.moveTo(40, 10);
|
||||||
path.moveTo(326.610535, 34.0393639);
|
path.quadTo(20, 30, 0, 10);
|
||||||
path.lineTo(371.334595, -14.9620667);
|
path.close();
|
||||||
path.lineTo(416.058624, -63.9634857);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(460.782654, -112.96492);
|
drawAsciiPaths(path, out, true);
|
||||||
path.lineTo(326.610535, 34.0393639);
|
}
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_5div">
|
|
||||||
original:
|
<div id="testSimplifyQuadratic5">
|
||||||
path.moveTo(0, 0);
|
SkPath path, out;
|
||||||
path.quadTo(20, 0, 20, 20);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(0, 0);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.close();
|
path.lineTo(0, 0);
|
||||||
path.moveTo(0, 20);
|
path.close();
|
||||||
path.quadTo(0, 0, 20, 0);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(0, 20);
|
path.lineTo(0, 0);
|
||||||
path.close();
|
path.quadTo(0, 0, 0, 1);
|
||||||
simplified:
|
path.close();
|
||||||
path.moveTo(0, 0);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(5, 5);
|
drawAsciiPaths(path, out, true);
|
||||||
path.quadTo(0, 10, 0, 20);
|
}
|
||||||
path.lineTo(20, 20);
|
|
||||||
path.quadTo(20, 10, 15, 5);
|
|
||||||
path.lineTo(20, 0);
|
|
||||||
path.quadTo(14.1421356, 0, 10, 1.71572876);
|
|
||||||
path.quadTo(5.85786438, 0, 0, 0);
|
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_6div">
|
|
||||||
original:
|
<div id="testSimplifyQuadratic6">
|
||||||
path.moveTo(0, 20);
|
SkPath path, out;
|
||||||
path.quadTo(20, 0, 40, 20);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(0, 20);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.close();
|
path.lineTo(1, 0);
|
||||||
path.moveTo(40, 10);
|
path.close();
|
||||||
path.quadTo(20, 30, 0, 10);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(40, 10);
|
path.lineTo(0, 0);
|
||||||
path.close();
|
path.quadTo(1, 0, 0, 1);
|
||||||
simplified:
|
path.close();
|
||||||
path.moveTo(0, 10);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.quadTo(2.92893219, 12.9289322, 5.85786438, 15);
|
drawAsciiPaths(path, out, true);
|
||||||
path.quadTo(2.92893219, 17.0710678, 0, 20);
|
}
|
||||||
path.lineTo(40, 20);
|
|
||||||
path.quadTo(37.0710678, 17.0710678, 34.1421356, 15);
|
|
||||||
path.quadTo(37.0710678, 12.9289322, 40, 10);
|
|
||||||
path.lineTo(0, 10);
|
|
||||||
path.close();
|
|
||||||
</div>
|
</div>
|
||||||
<div id="test_7div">
|
|
||||||
|
<div id="testSimplifyQuadratic7">
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 0, 0, 0);
|
||||||
|
path.lineTo(0, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.quadTo(1, 0, 0, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testSimplifyQuadratic8">
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 0, 0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.quadTo(1, 0, 0, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testSimplifyQuadratic9">
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 0, 0, 0);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.quadTo(1, 0, 2, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testSimplifyQuadratic10">
|
||||||
|
SkPath path, out;
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0, 0, 0, 0);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 0);
|
||||||
@ -118,67 +135,44 @@ path.close();
|
|||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(0, 1);
|
path.lineTo(0, 1);
|
||||||
path.quadTo(1, 1, 1, 2);
|
path.quadTo(1, 1, 1, 2);
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="test_8div">
|
<div id="testSimplifyQuadratic11">
|
||||||
original:
|
SkPath path, out;
|
||||||
path.moveTo(0, 0);
|
|
||||||
path.lineTo(3, 1);
|
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
|
||||||
path.moveTo(1, 0);
|
|
||||||
path.lineTo(0, 1);
|
|
||||||
path.quadTo(2, 1, 3, 3);
|
|
||||||
path.lineTo(1, 0);
|
|
||||||
path.close();
|
|
||||||
simplified:
|
|
||||||
path.moveTo(1, 0);
|
|
||||||
path.lineTo(0, 1);
|
|
||||||
path.quadTo(1.42857146, 1, 2.34693885, 2.02040815);
|
|
||||||
path.lineTo(1.28571427, 0.428571433);
|
|
||||||
path.lineTo(1, 0);
|
|
||||||
path.close();
|
|
||||||
path.moveTo(2.34693885, 2.02040815);
|
|
||||||
path.quadTo(2.71428561, 2.42857146, 3, 3);
|
|
||||||
path.lineTo(2.34693885, 2.02040815);
|
|
||||||
path.close();
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="test_9div">
|
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0, 0, 0, 0);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.lineTo(0, 2);
|
path.lineTo(0, 2);
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
path.close();
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(2, 1);
|
path.lineTo(2, 1);
|
||||||
path.quadTo(2, 2, 3, 3);
|
path.quadTo(2, 2, 3, 3);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testSimplifyQuadratic12">
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 2);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 0);
|
||||||
path.close();
|
path.close();
|
||||||
|
path.moveTo(3, 0);
|
||||||
|
path.quadTo(1, 1, 0, 2);
|
||||||
|
path.lineTo(3, 0);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="test_10div">
|
<div id="testSimplifyQuadratic13">
|
||||||
original:
|
SkPath path, out;
|
||||||
path.moveTo(0, 0);
|
|
||||||
path.lineTo(0, 2);
|
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
|
||||||
path.moveTo(3, 0);
|
|
||||||
path.quadTo(1, 1, 0, 2);
|
|
||||||
path.lineTo(3, 0);
|
|
||||||
path.close();
|
|
||||||
simplified:
|
|
||||||
path.moveTo(0, 0);
|
|
||||||
path.lineTo(0, 2);
|
|
||||||
path.quadTo(1, 1, 3, 0);
|
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="test_11div">
|
|
||||||
original:
|
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0, 0, 1, 0);
|
path.quadTo(0, 0, 1, 0);
|
||||||
path.lineTo(1, 1);
|
path.lineTo(1, 1);
|
||||||
@ -188,56 +182,69 @@ path.moveTo(0, 0);
|
|||||||
path.quadTo(3, 0, 1, 1);
|
path.quadTo(3, 0, 1, 1);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 0);
|
||||||
path.close();
|
path.close();
|
||||||
simplified:
|
testSimplify(path, true, out, bitmap);
|
||||||
path.moveTo(0, 0);
|
drawAsciiPaths(path, out, true);
|
||||||
path.lineTo(1, 1);
|
}
|
||||||
path.lineTo(1, 0);
|
|
||||||
path.lineTo(0, 0);
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="test_12div">
|
<div id="testSimplifyQuadratic14">
|
||||||
|
SkPath path, out;
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0, 0, 0, 0);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.lineTo(1, 1);
|
path.lineTo(1, 1);
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
path.close();
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 0);
|
||||||
path.quadTo(0, 1, 2, 1);
|
path.quadTo(0, 1, 2, 1);
|
||||||
path.lineTo(0, 0);
|
|
||||||
path.close();
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="test_13div">
|
<div id="testSimplifyQuadratic15">
|
||||||
original:
|
SkPath path, out;
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0, 0, 1, 3);
|
path.quadTo(0, 0, 1, 3);
|
||||||
path.lineTo(3, 3);
|
path.lineTo(3, 3);
|
||||||
path.lineTo(0, 0);
|
path.close();
|
||||||
path.close();
|
path.moveTo(0, 1);
|
||||||
path.moveTo(0, 1);
|
path.lineTo(1, 1);
|
||||||
path.lineTo(1, 1);
|
path.quadTo(0, 3, 3, 3);
|
||||||
path.quadTo(0, 3, 3, 3);
|
path.close();
|
||||||
path.lineTo(0, 1);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.close();
|
drawAsciiPaths(path, out, true);
|
||||||
simplified:
|
}
|
||||||
path.moveTo(0, 0);
|
</div>
|
||||||
path.lineTo(0.333333343, 1);
|
|
||||||
path.lineTo(0, 1);
|
<div id="testSimplifyQuadratic16">
|
||||||
path.lineTo(0.428571433, 1.28571427);
|
SkPath path, out;
|
||||||
path.lineTo(0.333333343, 1);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(1, 1);
|
path.quadTo(0, 0, 0, 0);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 1);
|
||||||
path.close();
|
path.close();
|
||||||
path.moveTo(1, 1);
|
path.moveTo(0, 0);
|
||||||
path.quadTo(0.857142866, 1.28571427, 0.795918345, 1.53061223);
|
path.lineTo(0, 0);
|
||||||
path.lineTo(0.428571433, 1.28571427);
|
path.quadTo(1, 0, 0, 1);
|
||||||
path.lineTo(1, 3);
|
path.close();
|
||||||
path.lineTo(3, 3);
|
testSimplify(path, true, out, bitmap);
|
||||||
path.lineTo(0.795918345, 1.53061223);
|
drawAsciiPaths(path, out, true);
|
||||||
path.quadTo(0.428571433, 3, 3, 3);
|
}
|
||||||
path.lineTo(1, 1);
|
</div>
|
||||||
path.close();
|
|
||||||
|
<div id="testSimplifyQuadratic17">
|
||||||
|
SkPath path, out;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 0, 0, 0);
|
||||||
|
path.lineTo(2, 2);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 1);
|
||||||
|
path.lineTo(0, 1);
|
||||||
|
path.quadTo(2, 1, 3, 3);
|
||||||
|
path.close();
|
||||||
|
testSimplify(path, true, out, bitmap);
|
||||||
|
drawAsciiPaths(path, out, true);
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -245,19 +252,23 @@ path.close();
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var testDivs = [
|
var testDivs = [
|
||||||
test_13div,
|
testSimplifyQuadratic17,
|
||||||
test_12div,
|
testSimplifyQuadratic16,
|
||||||
test_11div,
|
testSimplifyQuadratic15,
|
||||||
test_10div,
|
testSimplifyQuadratic14,
|
||||||
test_9div,
|
testSimplifyQuadratic13,
|
||||||
test_8div,
|
testSimplifyQuadratic12,
|
||||||
test_7div,
|
testSimplifyQuadratic11,
|
||||||
test_6div,
|
testSimplifyQuadratic10,
|
||||||
test_5div,
|
testSimplifyQuadratic9,
|
||||||
test_4div,
|
testSimplifyQuadratic8,
|
||||||
test_3div,
|
testSimplifyQuadratic7,
|
||||||
test_2div,
|
testSimplifyQuadratic6,
|
||||||
test_1div,
|
testSimplifyQuadratic5,
|
||||||
|
testSimplifyQuadratic4,
|
||||||
|
testSimplifyQuadratic3,
|
||||||
|
testSimplifyQuadratic2,
|
||||||
|
testSimplifyQuadratic1,
|
||||||
];
|
];
|
||||||
|
|
||||||
var scale, columns, rows, xStart, yStart;
|
var scale, columns, rows, xStart, yStart;
|
||||||
@ -291,8 +302,18 @@ function parse(test) {
|
|||||||
if (pts.length > 0)
|
if (pts.length > 0)
|
||||||
verbs.push(pts);
|
verbs.push(pts);
|
||||||
}
|
}
|
||||||
if (verbs.length > 0)
|
if (verbs.length > 0) {
|
||||||
|
var lastIndex = verbs.length - 1;
|
||||||
|
var lastVerb = verbs[lastIndex];
|
||||||
|
var lastLen = lastVerb.length;
|
||||||
|
if (verbs[0][0] != lastVerb[lastLen - 2] && verbs[0][1] != lastVerb[lastLen - 1]) {
|
||||||
|
var lastPts = [];
|
||||||
|
lastPts.push(verbs[0][0]);
|
||||||
|
lastPts.push(verbs[0][1]);
|
||||||
|
verbs.push(lastPts);
|
||||||
|
}
|
||||||
contours.push(verbs);
|
contours.push(verbs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (contours.length > 0)
|
if (contours.length > 0)
|
||||||
tests.push(contours);
|
tests.push(contours);
|
||||||
@ -469,23 +490,24 @@ function doKeyPress(evt) {
|
|||||||
case 'n':
|
case 'n':
|
||||||
if (++testIndex >= tests.length)
|
if (++testIndex >= tests.length)
|
||||||
testIndex = 0;
|
testIndex = 0;
|
||||||
// insetScale = scale;
|
mouseX = Infinity;
|
||||||
|
drawTop();
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
case 'p':
|
||||||
|
if (--testIndex < 0)
|
||||||
|
testIndex = tests.length - 1;
|
||||||
mouseX = Infinity;
|
mouseX = Infinity;
|
||||||
drawTop();
|
drawTop();
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
case 't':
|
case 't':
|
||||||
// drawTs(testIndex);
|
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
// if (--insetScale < 1)
|
|
||||||
// insetScale = 1;
|
|
||||||
// else
|
|
||||||
redraw();
|
redraw();
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
case '+':
|
case '+':
|
||||||
// ++insetScale;
|
|
||||||
redraw();
|
redraw();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user