git-svn-id: http://skia.googlecode.com/svn/trunk@7738 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2013-02-14 15:29:11 +00:00
Родитель 3976825a21
Коммит 45a8fc6a8b
37 изменённых файлов: 2007 добавлений и 921 удалений

Просмотреть файл

@ -10,15 +10,13 @@
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);
return between(a, b, d) && between(a, 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 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) {
@ -48,12 +46,10 @@ void _Rect::setBounds(const Cubic& cubic) {
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);
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]);
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;

Просмотреть файл

@ -0,0 +1,165 @@
/*
* 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 "CubicUtilities.h"
#include "CurveIntersection.h"
#include "Intersections.h"
#include "IntersectionUtilities.h"
#include "LineIntersection.h"
static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
class CubicIntersections : public Intersections {
public:
CubicIntersections(const Cubic& c1, const Cubic& c2, Intersections& i)
: cubic1(c1)
, cubic2(c2)
, intersections(i)
, depth(0)
, splits(0) {
}
bool intersect() {
double minT1, minT2, maxT1, maxT2;
if (!bezier_clip(cubic2, cubic1, minT1, maxT1)) {
return false;
}
if (!bezier_clip(cubic1, cubic2, minT2, maxT2)) {
return false;
}
int split;
if (maxT1 - minT1 < maxT2 - minT2) {
intersections.swap();
minT2 = 0;
maxT2 = 1;
split = maxT1 - minT1 > tClipLimit;
} else {
minT1 = 0;
maxT1 = 1;
split = (maxT2 - minT2 > tClipLimit) << 1;
}
return chop(minT1, maxT1, minT2, maxT2, split);
}
protected:
bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
Cubic smaller, larger;
// FIXME: carry last subdivide and reduceOrder result with cubic
sub_divide(cubic1, minT1, maxT1, intersections.swapped() ? larger : smaller);
sub_divide(cubic2, minT2, maxT2, intersections.swapped() ? smaller : larger);
Cubic smallResult;
if (reduceOrder(smaller, smallResult,
kReduceOrder_NoQuadraticsAllowed) <= 2) {
Cubic largeResult;
if (reduceOrder(larger, largeResult,
kReduceOrder_NoQuadraticsAllowed) <= 2) {
const _Line& smallLine = (const _Line&) smallResult;
const _Line& largeLine = (const _Line&) largeResult;
Intersections lineTs;
// FIXME: this doesn't detect or deal with coincident lines
if (!::intersect(smallLine, largeLine, lineTs)) {
return false;
}
if (intersections.swapped()) {
lineTs.fT[0][0] = interp(minT2, maxT2, lineTs.fT[0][0]);
lineTs.fT[1][0] = interp(minT1, maxT1, lineTs.fT[1][0]);
} else {
lineTs.fT[0][0] = interp(minT1, maxT1, lineTs.fT[0][0]);
lineTs.fT[1][0] = interp(minT2, maxT2, lineTs.fT[1][0]);
}
_Point pt;
xy_at_t(cubic1, lineTs.fT[0][0], pt.x, pt.y);
intersections.insert(lineTs.fT[0][0], lineTs.fT[1][0], pt);
return true;
}
}
double minT, maxT;
if (!bezier_clip(smaller, larger, minT, maxT)) {
if (minT == maxT) {
if (intersections.swapped()) {
minT1 = (minT1 + maxT1) / 2;
minT2 = interp(minT2, maxT2, minT);
} else {
minT1 = interp(minT1, maxT1, minT);
minT2 = (minT2 + maxT2) / 2;
}
_Point pt;
xy_at_t(cubic1, minT1, pt.x, pt.y);
intersections.insert(minT1, minT2, pt);
return true;
}
return false;
}
int split;
if (intersections.swapped()) {
double newMinT1 = interp(minT1, maxT1, minT);
double newMaxT1 = interp(minT1, maxT1, maxT);
split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
#define VERBOSE 0
#if VERBOSE
printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n",
__FUNCTION__, depth, splits, newMinT1, newMaxT1, minT1, maxT1,
split);
#endif
minT1 = newMinT1;
maxT1 = newMaxT1;
} else {
double newMinT2 = interp(minT2, maxT2, minT);
double newMaxT2 = interp(minT2, maxT2, maxT);
split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
#if VERBOSE
printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n",
__FUNCTION__, depth, splits, newMinT2, newMaxT2, minT2, maxT2,
split);
#endif
minT2 = newMinT2;
maxT2 = newMaxT2;
}
return chop(minT1, maxT1, minT2, maxT2, split);
}
bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
++depth;
intersections.swap();
if (split) {
++splits;
if (split & 2) {
double middle1 = (maxT1 + minT1) / 2;
intersect(minT1, middle1, minT2, maxT2);
intersect(middle1, maxT1, minT2, maxT2);
} else {
double middle2 = (maxT2 + minT2) / 2;
intersect(minT1, maxT1, minT2, middle2);
intersect(minT1, maxT1, middle2, maxT2);
}
--splits;
intersections.swap();
--depth;
return intersections.intersected();
}
bool result = intersect(minT1, maxT1, minT2, maxT2);
intersections.swap();
--depth;
return result;
}
private:
const Cubic& cubic1;
const Cubic& cubic2;
Intersections& intersections;
int depth;
int splits;
};
bool intersect(const Cubic& c1, const Cubic& c2, Intersections& i) {
CubicIntersections c(c1, c2, i);
return c.intersect();
}

Просмотреть файл

@ -12,243 +12,12 @@
#include "LineIntersection.h"
#include "LineUtilities.h"
#define DEBUG_COMPUTE_DELTA 1
#define COMPUTE_DELTA 0
#if ONE_OFF_DEBUG
static const double tLimits[2][2] = {{0.516980827, 0.516981209}, {0.647714088, 0.64771447}};
#endif
#define DEBUG_QUAD_PART 0
static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
class CubicIntersections : public Intersections {
public:
CubicIntersections(const Cubic& c1, const Cubic& c2, Intersections& i)
: cubic1(c1)
, cubic2(c2)
, intersections(i)
, depth(0)
, splits(0) {
}
bool intersect() {
double minT1, minT2, maxT1, maxT2;
if (!bezier_clip(cubic2, cubic1, minT1, maxT1)) {
return false;
}
if (!bezier_clip(cubic1, cubic2, minT2, maxT2)) {
return false;
}
int split;
if (maxT1 - minT1 < maxT2 - minT2) {
intersections.swap();
minT2 = 0;
maxT2 = 1;
split = maxT1 - minT1 > tClipLimit;
} else {
minT1 = 0;
maxT1 = 1;
split = (maxT2 - minT2 > tClipLimit) << 1;
}
return chop(minT1, maxT1, minT2, maxT2, split);
}
protected:
bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
Cubic smaller, larger;
// FIXME: carry last subdivide and reduceOrder result with cubic
sub_divide(cubic1, minT1, maxT1, intersections.swapped() ? larger : smaller);
sub_divide(cubic2, minT2, maxT2, intersections.swapped() ? smaller : larger);
Cubic smallResult;
if (reduceOrder(smaller, smallResult,
kReduceOrder_NoQuadraticsAllowed) <= 2) {
Cubic largeResult;
if (reduceOrder(larger, largeResult,
kReduceOrder_NoQuadraticsAllowed) <= 2) {
const _Line& smallLine = (const _Line&) smallResult;
const _Line& largeLine = (const _Line&) largeResult;
double smallT[2];
double largeT[2];
// FIXME: this doesn't detect or deal with coincident lines
if (!::intersect(smallLine, largeLine, smallT, largeT)) {
return false;
}
if (intersections.swapped()) {
smallT[0] = interp(minT2, maxT2, smallT[0]);
largeT[0] = interp(minT1, maxT1, largeT[0]);
} else {
smallT[0] = interp(minT1, maxT1, smallT[0]);
largeT[0] = interp(minT2, maxT2, largeT[0]);
}
intersections.add(smallT[0], largeT[0]);
return true;
}
}
double minT, maxT;
if (!bezier_clip(smaller, larger, minT, maxT)) {
if (minT == maxT) {
if (intersections.swapped()) {
minT1 = (minT1 + maxT1) / 2;
minT2 = interp(minT2, maxT2, minT);
} else {
minT1 = interp(minT1, maxT1, minT);
minT2 = (minT2 + maxT2) / 2;
}
intersections.add(minT1, minT2);
return true;
}
return false;
}
int split;
if (intersections.swapped()) {
double newMinT1 = interp(minT1, maxT1, minT);
double newMaxT1 = interp(minT1, maxT1, maxT);
split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
#define VERBOSE 0
#if VERBOSE
printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n",
__FUNCTION__, depth, splits, newMinT1, newMaxT1, minT1, maxT1,
split);
#endif
minT1 = newMinT1;
maxT1 = newMaxT1;
} else {
double newMinT2 = interp(minT2, maxT2, minT);
double newMaxT2 = interp(minT2, maxT2, maxT);
split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
#if VERBOSE
printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n",
__FUNCTION__, depth, splits, newMinT2, newMaxT2, minT2, maxT2,
split);
#endif
minT2 = newMinT2;
maxT2 = newMaxT2;
}
return chop(minT1, maxT1, minT2, maxT2, split);
}
bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
++depth;
intersections.swap();
if (split) {
++splits;
if (split & 2) {
double middle1 = (maxT1 + minT1) / 2;
intersect(minT1, middle1, minT2, maxT2);
intersect(middle1, maxT1, minT2, maxT2);
} else {
double middle2 = (maxT2 + minT2) / 2;
intersect(minT1, maxT1, minT2, middle2);
intersect(minT1, maxT1, middle2, maxT2);
}
--splits;
intersections.swap();
--depth;
return intersections.intersected();
}
bool result = intersect(minT1, maxT1, minT2, maxT2);
intersections.swap();
--depth;
return result;
}
private:
const Cubic& cubic1;
const Cubic& cubic2;
Intersections& intersections;
int depth;
int splits;
};
bool intersect(const Cubic& c1, const Cubic& c2, Intersections& i) {
CubicIntersections c(c1, c2, i);
return c.intersect();
}
#if COMPUTE_DELTA
static void cubicTangent(const Cubic& cubic, double t, _Line& tangent, _Point& pt, _Point& dxy) {
xy_at_t(cubic, t, tangent[0].x, tangent[0].y);
pt = tangent[1] = tangent[0];
dxdy_at_t(cubic, t, dxy);
if (dxy.approximatelyZero()) {
if (approximately_zero(t)) {
SkASSERT(cubic[0].approximatelyEqual(cubic[1]));
dxy = cubic[2];
dxy -= cubic[0];
} else {
SkASSERT(approximately_equal(t, 1));
SkASSERT(cubic[3].approximatelyEqual(cubic[2]));
dxy = cubic[3];
dxy -= cubic[1];
}
SkASSERT(!dxy.approximatelyZero());
}
tangent[0] -= dxy;
tangent[1] += dxy;
#if DEBUG_COMPUTE_DELTA
SkDebugf("%s t=%1.9g tangent=(%1.9g,%1.9g %1.9g,%1.9g)"
" pt=(%1.9g %1.9g) dxy=(%1.9g %1.9g)\n", __FUNCTION__, t,
tangent[0].x, tangent[0].y, tangent[1].x, tangent[1].y, pt.x, pt.y,
dxy.x, dxy.y);
#endif
}
#endif
#if COMPUTE_DELTA
static double cubicDelta(const _Point& dxy, _Line& tangent, double scale) {
double tangentLen = dxy.length();
tangent[0] -= tangent[1];
double intersectLen = tangent[0].length();
double result = intersectLen / tangentLen + scale;
#if DEBUG_COMPUTE_DELTA
SkDebugf("%s tangent=(%1.9g,%1.9g %1.9g,%1.9g) intersectLen=%1.9g tangentLen=%1.9g scale=%1.9g"
" result=%1.9g\n", __FUNCTION__, tangent[0].x, tangent[0].y, tangent[1].x, tangent[1].y,
intersectLen, tangentLen, scale, result);
#endif
return result;
}
#endif
#if COMPUTE_DELTA
// FIXME: after testing, make this static
static void computeDelta(const Cubic& c1, double t1, double scale1, const Cubic& c2, double t2,
double scale2, double& delta1, double& delta2) {
#if DEBUG_COMPUTE_DELTA
SkDebugf("%s c1=(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) t1=%1.9g scale1=%1.9g"
" c2=(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) t2=%1.9g scale2=%1.9g\n",
__FUNCTION__,
c1[0].x, c1[0].y, c1[1].x, c1[1].y, c1[2].x, c1[2].y, c1[3].x, c1[3].y, t1, scale1,
c2[0].x, c2[0].y, c2[1].x, c2[1].y, c2[2].x, c2[2].y, c2[3].x, c2[3].y, t2, scale2);
#endif
_Line tangent1, tangent2, line1, line2;
_Point dxy1, dxy2;
cubicTangent(c1, t1, line1, tangent1[0], dxy1);
cubicTangent(c2, t2, line2, tangent2[0], dxy2);
double range1[2], range2[2];
int found = intersect(line1, line2, range1, range2);
if (found == 0) {
range1[0] = 0.5;
} else {
SkASSERT(found == 1);
}
xy_at_t(line1, range1[0], tangent1[1].x, tangent1[1].y);
#if SK_DEBUG
if (found == 1) {
xy_at_t(line2, range2[0], tangent2[1].x, tangent2[1].y);
SkASSERT(tangent2[1].approximatelyEqual(tangent1[1]));
}
#endif
tangent2[1] = tangent1[1];
delta1 = cubicDelta(dxy1, tangent1, scale1 / precisionUnit);
delta2 = cubicDelta(dxy2, tangent2, scale2 / precisionUnit);
}
#if SK_DEBUG
int debugDepth;
#endif
#endif
static int quadPart(const Cubic& cubic, double tStart, double tEnd, Quadratic& simple) {
Cubic part;
sub_divide(cubic, tStart, tEnd, part);
@ -283,7 +52,7 @@ static void intersectWithOrder(const Quadratic& simple1, int order1, const Quadr
if (order1 == 3 && order2 == 3) {
intersect2(simple1, simple2, i);
} else if (order1 <= 2 && order2 <= 2) {
i.fUsed = intersect((const _Line&) simple1, (const _Line&) simple2, i.fT[0], i.fT[1]);
intersect((const _Line&) simple1, (const _Line&) simple2, i);
} else if (order1 == 3 && order2 <= 2) {
intersect(simple1, (const _Line&) simple2, i);
} else {
@ -335,9 +104,9 @@ static bool doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
Quadratic s2a;
int o2a = quadPart(cubic2, p2s, p2e, s2a);
Intersections locals;
#if 0 && SK_DEBUG
if (0.497026154 >= p1s && 0.497026535 <= p1e
&& 0.710440575 >= p2s && 0.710440956 <= p2e) {
#if ONE_OFF_DEBUG
if (tLimits[0][0] >= p1s && tLimits[0][1] <= p1e
&& tLimits[1][0] >= p2s && tLimits[1][1] <= p2e) {
SkDebugf("t1=(%1.9g,%1.9g) o1=%d t2=(%1.9g,%1.9g) o2=%d\n",
p1s, p1e, o1a, p2s, p2e, o2a);
if (o1a == 2) {
@ -356,7 +125,7 @@ static bool doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
}
Intersections xlocals;
intersectWithOrder(s1a, o1a, s2a, o2a, xlocals);
SkDebugf("xlocals.fUsed=%d\n", xlocals.used());
SkDebugf("xlocals.fUsed=%d depth=%d\n", xlocals.used(), i.depth());
}
#endif
intersectWithOrder(s1a, o1a, s2a, o2a, locals);
@ -367,16 +136,21 @@ static bool doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
_Point p1, p2;
xy_at_t(cubic1, to1, p1.x, p1.y);
xy_at_t(cubic2, to2, p2.x, p2.y);
#if 0 && SK_DEBUG
#if ONE_OFF_DEBUG
SkDebugf("to1=%1.9g p1=(%1.9g,%1.9g) to2=%1.9g p2=(%1.9g,%1.9g) d=%1.9g\n",
to1, p1.x, p1.y, to2, p2.x, p2.y, p1.distance(p2));
#endif
if (p1.approximatelyEqual(p2)) {
i.insert(i.swapped() ? to2 : to1, i.swapped() ? to1 : to2);
if (p1.approximatelyEqualHalf(p2)) {
i.insertSwap(to1, to2, p1);
result = true;
} else {
result = doIntersect(cubic1, p1s, to1, p1e, cubic2, p2s, to2, p2e, i);
if (!result && p1.approximatelyEqual(p2)) {
i.insertSwap(to1, to2, p1);
SkDebugf("!!!\n");
result = true;
} else
// if both cubics curve in the same direction, the quadratic intersection
// may mark a range that does not contain the cubic intersection. If no
// intersection is found, look again including the t distance of the
@ -431,9 +205,9 @@ static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic&
const double t2 = t2s + (t2e - t2s) * tEnd2;
Quadratic s2;
int o2 = quadPart(cubic2, t2Start, t2, s2);
#if 0 && SK_DEBUG
if (0.497026154 >= t1Start && 0.497026535 <= t1
&& 0.710440575 + 0.0004 >= t2Start && 0.710440956 <= t2) {
#if ONE_OFF_DEBUG
if (tLimits[0][0] >= t1Start && tLimits[0][1] <= t1
&& tLimits[1][0] >= t2Start && tLimits[1][1] <= t2) {
Cubic cSub1, cSub2;
sub_divide(cubic1, t1Start, tEnd1, cSub1);
sub_divide(cubic2, t2Start, tEnd2, cSub2);
@ -455,31 +229,11 @@ static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic&
xy_at_t(cubic1, to1, p1.x, p1.y);
xy_at_t(cubic2, to2, p2.x, p2.y);
if (p1.approximatelyEqual(p2)) {
i.insert(i.swapped() ? to2 : to1, i.swapped() ? to1 : to2);
i.insert(to1, to2, p1);
} else {
#if COMPUTE_DELTA
double dt1, dt2;
computeDelta(cubic1, to1, (t1e - t1s), cubic2, to2, (t2e - t2s), dt1, dt2);
double scale = precisionScale;
if (dt1 > 0.125 || dt2 > 0.125) {
scale /= 2;
SkDebugf("%s scale=%1.9g\n", __FUNCTION__, scale);
}
#if SK_DEBUG
++debugDepth;
SkASSERT(debugDepth < 10);
#endif
i.swap();
intersect2(cubic2, SkTMax(to2 - dt2, 0.), SkTMin(to2 + dt2, 1.),
cubic1, SkTMax(to1 - dt1, 0.), SkTMin(to1 + dt1, 1.), scale, i);
i.swap();
#if SK_DEBUG
--debugDepth;
#endif
#else
#if 0 && SK_DEBUG
if (0.497026154 >= t1Start && 0.497026535 <= t1
&& 0.710440575 >= t2Start && 0.710440956 <= t2) {
#if ONE_OFF_DEBUG
if (tLimits[0][0] >= t1Start && tLimits[0][1] <= t1
&& tLimits[1][0] >= t2Start && tLimits[1][1] <= t2) {
SkDebugf("t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)\n",
t1Start, t1, t2Start, t2);
}
@ -493,17 +247,24 @@ static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic&
bumpForRetry(locals.fT[0][tIdx], locals.fT[1][tIdx], b1s, b1e, b2s, b2e);
doIntersect(cubic1, b1s, to1, b1e, cubic2, b2s, to2, b2e, i);
}
#endif
}
}
if (locals.coincidentUsed()) {
SkASSERT(locals.coincidentUsed() == 2);
int coincidentCount = locals.coincidentUsed();
if (coincidentCount) {
// FIXME: one day, we'll probably need to allow coincident + non-coincident pts
SkASSERT(coincidentCount == locals.used());
SkASSERT(coincidentCount == 2);
double coTs[2][2];
for (int tIdx = 0; tIdx < locals.coincidentUsed(); ++tIdx) {
coTs[0][tIdx] = t1Start + (t1 - t1Start) * locals.fCoincidentT[0][tIdx];
coTs[1][tIdx] = t2Start + (t2 - t2Start) * locals.fCoincidentT[1][tIdx];
for (int tIdx = 0; tIdx < coincidentCount; ++tIdx) {
if (locals.fIsCoincident[0] & (1 << tIdx)) {
coTs[0][tIdx] = t1Start + (t1 - t1Start) * locals.fT[0][tIdx];
}
if (locals.fIsCoincident[1] & (1 << tIdx)) {
coTs[1][tIdx] = t2Start + (t2 - t2Start) * locals.fT[1][tIdx];
}
}
i.addCoincident(coTs[0][0], coTs[0][1], coTs[1][0], coTs[1][1]);
i.insertCoincidentPair(coTs[0][0], coTs[0][1], coTs[1][0], coTs[1][1],
locals.fPt[0], locals.fPt[1]);
}
t2Start = t2;
}
@ -562,21 +323,113 @@ static bool intersectEnd(const Cubic& cubic1, bool start, const Cubic& cubic2, c
tMin = SkTMin(tMin, local2.fT[0][index]);
tMax = SkTMax(tMax, local2.fT[0][index]);
}
#if SK_DEBUG && COMPUTE_DELTA
debugDepth = 0;
#endif
return intersect2(cubic1, start ? 0 : 1, start ? 1.0 / precisionUnit : 1 - 1.0 / precisionUnit,
cubic2, tMin, tMax, 1, i);
}
// this flavor centers potential intersections recursively. In contrast, '2' may inadvertently
// chase intersections near quadratic ends, requiring odd hacks to find them.
static bool intersect3(const Cubic& cubic1, double t1s, double t1e, const Cubic& cubic2,
double t2s, double t2e, double precisionScale, Intersections& i) {
i.upDepth();
bool result = false;
Cubic c1, c2;
sub_divide(cubic1, t1s, t1e, c1);
sub_divide(cubic2, t2s, t2e, c2);
SkTDArray<double> ts1;
cubic_to_quadratics(c1, calcPrecision(c1) * precisionScale, ts1);
SkTDArray<double> ts2;
cubic_to_quadratics(c2, calcPrecision(c2) * precisionScale, ts2);
double t1Start = t1s;
int ts1Count = ts1.count();
for (int i1 = 0; i1 <= ts1Count; ++i1) {
const double tEnd1 = i1 < ts1Count ? ts1[i1] : 1;
const double t1 = t1s + (t1e - t1s) * tEnd1;
Quadratic s1;
int o1 = quadPart(cubic1, t1Start, t1, s1);
double t2Start = t2s;
int ts2Count = ts2.count();
for (int i2 = 0; i2 <= ts2Count; ++i2) {
const double tEnd2 = i2 < ts2Count ? ts2[i2] : 1;
const double t2 = t2s + (t2e - t2s) * tEnd2;
Quadratic s2;
int o2 = quadPart(cubic2, t2Start, t2, s2);
Intersections locals;
intersectWithOrder(s1, o1, s2, o2, locals);
double coStart[2] = { -1 };
_Point coPoint;
for (int tIdx = 0; tIdx < locals.used(); ++tIdx) {
double to1 = t1Start + (t1 - t1Start) * locals.fT[0][tIdx];
double to2 = t2Start + (t2 - t2Start) * locals.fT[1][tIdx];
// if the computed t is not sufficiently precise, iterate
_Point p1, p2;
xy_at_t(cubic1, to1, p1.x, p1.y);
xy_at_t(cubic2, to2, p2.x, p2.y);
if (p1.approximatelyEqual(p2)) {
if (locals.fIsCoincident[0] & 1 << tIdx) {
if (coStart[0] < 0) {
coStart[0] = to1;
coStart[1] = to2;
coPoint = p1;
} else {
i.insertCoincidentPair(coStart[0], to1, coStart[1], to2, coPoint, p1);
coStart[0] = -1;
}
} else {
i.insert(to1, to2, p1);
}
result = true;
} else {
double offset = precisionScale / 16; // FIME: const is arbitrary -- test & refine
double c1Min = SkTMax(0., to1 - offset);
double c1Max = SkTMin(1., to1 + offset);
double c2Min = SkTMax(0., to2 - offset);
double c2Max = SkTMin(1., to2 + offset);
bool found = intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
if (false && !found) {
// either offset was overagressive or cubics didn't really intersect
// if they didn't intersect, then quad tangents ought to be nearly parallel
offset = precisionScale / 2; // try much less agressive offset
c1Min = SkTMax(0., to1 - offset);
c1Max = SkTMin(1., to1 + offset);
c2Min = SkTMax(0., to2 - offset);
c2Max = SkTMin(1., to2 + offset);
found = intersect3(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offset, i);
if (found) {
SkDebugf("%s *** over-aggressive? offset=%1.9g depth=%d\n", __FUNCTION__,
offset, i.depth());
}
// try parallel measure
_Point d1 = dxdy_at_t(cubic1, to1);
_Point d2 = dxdy_at_t(cubic2, to2);
double shallow = d1.cross(d2);
#if 1 || ONE_OFF_DEBUG // not sure this is worth debugging
if (!approximately_zero(shallow)) {
SkDebugf("%s *** near-miss? shallow=%1.9g depth=%d\n", __FUNCTION__,
offset, i.depth());
}
#endif
if (i.depth() == 1 && shallow < 0.6) {
SkDebugf("%s !!! near-miss? shallow=%1.9g depth=%d\n", __FUNCTION__,
offset, i.depth());
}
}
}
}
SkASSERT(coStart[0] == -1);
t2Start = t2;
}
t1Start = t1;
}
i.downDepth();
return result;
}
// FIXME: add intersection of convex hull on cubics' ends with the opposite cubic. The hull line
// segments can be constructed to be only as long as the calculated precision suggests. If the hull
// line segments intersect the cubic, then use the intersections to construct a subdivision for
// quadratic curve fitting.
bool intersect2(const Cubic& c1, const Cubic& c2, Intersections& i) {
#if SK_DEBUG && COMPUTE_DELTA
debugDepth = 0;
#endif
bool result = intersect2(c1, 0, 1, c2, 0, 1, 1, i);
// FIXME: pass in cached bounds from caller
_Rect c1Bounds, c2Bounds;
@ -591,6 +444,21 @@ bool intersect2(const Cubic& c1, const Cubic& c2, Intersections& i) {
return result;
}
bool intersect3(const Cubic& c1, const Cubic& c2, Intersections& i) {
bool result = intersect3(c1, 0, 1, c2, 0, 1, 1, i);
// FIXME: pass in cached bounds from caller
_Rect c1Bounds, c2Bounds;
c1Bounds.setBounds(c1); // OPTIMIZE use setRawBounds ?
c2Bounds.setBounds(c2);
result |= intersectEnd(c1, false, c2, c2Bounds, i);
result |= intersectEnd(c1, true, c2, c2Bounds, i);
i.swap();
result |= intersectEnd(c2, false, c1, c1Bounds, i);
result |= intersectEnd(c2, true, c1, c1Bounds, i);
i.swap();
return result;
}
int intersect(const Cubic& cubic, const Quadratic& quad, Intersections& i) {
SkTDArray<double> ts;
double precision = calcPrecision(cubic);
@ -607,9 +475,7 @@ int intersect(const Cubic& cubic, const Quadratic& quad, Intersections& i) {
intersect2(q1, quad, locals);
for (int tIdx = 0; tIdx < locals.used(); ++tIdx) {
double globalT = tStart + (t - tStart) * locals.fT[0][tIdx];
i.insertOne(globalT, 0);
globalT = locals.fT[1][tIdx];
i.insertOne(globalT, 1);
i.insert(globalT, locals.fT[1][tIdx], locals.fPt[tIdx]);
}
tStart = t;
}
@ -648,7 +514,7 @@ bool intersect(const Cubic& cubic, Intersections& i) {
}
double to1 = t1Start + (t1 - t1Start) * t1sect;
double to2 = t2Start + (t2 - t2Start) * t2sect;
i.insert(to1, to2);
i.insert(to1, to2, locals.fPt[tIdx]);
}
t2Start = t2;
}

Просмотреть файл

@ -13,7 +13,7 @@
const int firstCubicIntersectionTest = 9;
void CubicIntersection_Test() {
static void standardTestCases() {
for (size_t index = firstCubicIntersectionTest; index < tests_count; ++index) {
const Cubic& cubic1 = tests[index][0];
const Cubic& cubic2 = tests[index][1];
@ -57,60 +57,22 @@ void CubicIntersection_Test() {
}
}
#define ONE_OFF_DEBUG 0
static void oneOff(const Cubic& cubic1, const Cubic& cubic2) {
SkTDArray<Quadratic> quads1;
cubic_to_quadratics(cubic1, calcPrecision(cubic1), quads1);
#if ONE_OFF_DEBUG
for (int index = 0; index < quads1.count(); ++index) {
const Quadratic& q = quads1[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
SkTDArray<Quadratic> quads2;
cubic_to_quadratics(cubic2, calcPrecision(cubic2), quads2);
#if ONE_OFF_DEBUG
for (int index = 0; index < quads2.count(); ++index) {
const Quadratic& q = quads2[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
Intersections intersections2;
intersect2(cubic1, cubic2, intersections2);
for (int pt = 0; pt < intersections2.used(); ++pt) {
double tt1 = intersections2.fT[0][pt];
_Point xy1, xy2;
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
double tt2 = intersections2.fT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
}
for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
double tt1 = intersections2.fCoincidentT[0][pt];
_Point xy1, xy2;
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
double tt2 = intersections2.fCoincidentT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
}
}
static const Cubic testSet[] = {
{{0,1}, {4,5}, {1,0}, {5,3}},
{{0,1}, {3,5}, {1,0}, {5,4}},
{{0, 1}, {1, 6}, {1, 0}, {1, 0}},
{{0, 1}, {0, 1}, {1, 0}, {6, 1}},
{{0,1}, {3,4}, {1,0}, {5,1}},
{{0,1}, {1,5}, {1,0}, {4,3}},
{{0,1}, {1,2}, {1,0}, {6,1}},
{{0,1}, {1,6}, {1,0}, {2,1}},
{{0,1}, {0,5}, {1,0}, {4,0}},
{{0,1}, {0,4}, {1,0}, {5,0}},
{{0,1}, {3,4}, {1,0}, {3,0}},
{{0,1}, {0,3}, {1,0}, {4,3}},
@ -169,22 +131,182 @@ static const Cubic testSet[] = {
const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
void CubicIntersection_OneOffTest() {
for (size_t outer = 0; outer < testSetCount - 1; ++outer) {
static void oneOff(const Cubic& cubic1, const Cubic& cubic2) {
SkTDArray<Quadratic> quads1;
cubic_to_quadratics(cubic1, calcPrecision(cubic1), quads1);
#if ONE_OFF_DEBUG
SkDebugf("%s quads1[%d]\n", __FUNCTION__, outer);
for (int index = 0; index < quads1.count(); ++index) {
const Quadratic& q = quads1[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
const Cubic& cubic1 = testSet[outer];
for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
SkTDArray<Quadratic> quads2;
cubic_to_quadratics(cubic2, calcPrecision(cubic2), quads2);
#if ONE_OFF_DEBUG
SkDebugf("%s quads2[%d]\n", __FUNCTION__, inner);
for (int index = 0; index < quads2.count(); ++index) {
const Quadratic& q = quads2[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
const Cubic& cubic2 = testSet[inner];
oneOff(cubic1, cubic2);
Intersections intersections2, intersections3;
intersect2(cubic1, cubic2, intersections2);
intersect3(cubic1, cubic2, intersections3);
int pt1, pt2, pt3;
bool found;
double tt1, tt2, last = -1;
_Point xy1, xy2;
for (pt1 = 0; pt1 < intersections2.used(); ++pt1) {
tt1 = intersections2.fT[0][pt1];
SkASSERT(!approximately_equal(last, tt1));
last = tt1;
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
pt2 = intersections2.fFlip ? intersections2.used() - pt1 - 1 : pt1;
tt2 = intersections2.fT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
__FUNCTION__, tt1, xy1.x, xy1.y, intersections2.fPt[pt1].x,
intersections2.fPt[pt1].y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
#if SK_DEBUG
found = false;
for (pt3 = 0; pt3 < intersections3.used(); ++pt3) {
if (roughly_equal(tt1, intersections3.fT[0][pt3])) {
found = true;
break;
}
}
SkASSERT(found);
#endif
}
last = -1;
for (pt3 = 0; pt3 < intersections3.used(); ++pt3) {
found = false;
double tt3 = intersections3.fT[0][pt3];
SkASSERT(!approximately_equal(last, tt3));
last = tt3;
for (pt1 = 0; pt1 < intersections2.used(); ++pt1) {
if (approximately_equal(tt3, intersections2.fT[0][pt1])) {
found = true;
break;
}
}
if (!found) {
tt1 = intersections3.fT[0][pt3];
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
pt2 = intersections3.fFlip ? intersections3.used() - pt3 - 1 : pt3;
tt2 = intersections3.fT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t3=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
__FUNCTION__, tt1, xy1.x, xy1.y, intersections3.fPt[pt1].x,
intersections3.fPt[pt1].y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
SkDebugf("%s missing in intersect2\n", __FUNCTION__);
}
}
}
static void oneOff3(const Cubic& cubic1, const Cubic& cubic2) {
SkTDArray<Quadratic> quads1;
cubic_to_quadratics(cubic1, calcPrecision(cubic1), quads1);
#if ONE_OFF_DEBUG
for (int index = 0; index < quads1.count(); ++index) {
const Quadratic& q = quads1[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
SkTDArray<Quadratic> quads2;
cubic_to_quadratics(cubic2, calcPrecision(cubic2), quads2);
#if ONE_OFF_DEBUG
for (int index = 0; index < quads2.count(); ++index) {
const Quadratic& q = quads2[index];
SkDebugf(" {{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", q[0].x, q[0].y,
q[1].x, q[1].y, q[2].x, q[2].y);
}
SkDebugf("\n");
#endif
Intersections intersections3;
intersect3(cubic1, cubic2, intersections3);
int pt2, pt3;
double tt1, tt2, last = -1;
_Point xy1, xy2;
for (pt3 = 0; pt3 < intersections3.used(); ++pt3) {
double tt3 = intersections3.fT[0][pt3];
SkASSERT(!approximately_equal(last, tt3));
last = tt3;
tt1 = intersections3.fT[0][pt3];
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
pt2 = intersections3.fFlip ? intersections3.used() - pt3 - 1 : pt3;
tt2 = intersections3.fT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t3=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n",
__FUNCTION__, tt1, xy1.x, xy1.y, intersections3.fPt[pt3].x,
intersections3.fPt[pt3].y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
}
}
static int fails[][2] = { {0, 23}, // fails in intersect2 recursing
{2, 7}, // answers differ, but neither is correct ('3' is closer)
{3, 26}, // fails in intersect2 recursing
{4, 9}, // fails in intersect2 recursing
{4, 10}, // fails in intersect2 recursing
{10, 17}, // fails in intersect2 recursing
{12, 14}, // loops indefinitely
{12, 21}, // fails in intersect2 recursing
{13, 21}, // fails in intersect2 recursing
{14, 21}, // fails in intersect2 recursing
{17, 25}, // fails in intersect2 recursing
{23, 25}, // fails in intersect2 recursing
};
static int failCount = sizeof(fails) / sizeof(fails[0]);
static void oneOff(int outer, int inner) {
const Cubic& cubic1 = testSet[outer];
const Cubic& cubic2 = testSet[inner];
bool failing = false;
for (int i = 0; i < failCount; ++i) {
if ((fails[i][0] == outer && fails[i][1] == inner)
|| (fails[i][1] == outer && fails[i][0] == inner)) {
failing = true;
break;
}
}
if (!failing) {
oneOff(cubic1, cubic2);
} else {
oneOff3(cubic1, cubic2);
}
}
void CubicIntersection_OneOffTest() {
oneOff(12, 14);
}
static void oneOffTests() {
for (size_t outer = 0; outer < testSetCount - 1; ++outer) {
for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
oneOff(outer, inner);
}
}
}
void CubicIntersection_OneOffTests() {
oneOffTests();
}
#define DEBUG_CRASH 0
class CubicChopper {
@ -400,12 +522,13 @@ void CubicIntersection_RandTest() {
}
void CubicIntersection_IntersectionFinder() {
Cubic cubic1 = {{0,1}, {3,4}, {1,0}, {3,0}};
Cubic cubic2 = {{0,1}, {0,3}, {1,0}, {4,3}};
double t1Seed = 0.496;
double t2Seed = 0.711;
double t1Step = 0.1;
double t2Step = 0.1;
const Cubic& cubic1 = testSet[2];
const Cubic& cubic2 = testSet[7];
double t1Seed = 0.254;
double t2Seed = 0.245;
double t1Step = 0.01;
double t2Step = 0.01;
_Point t1[3], t2[3];
bool toggle = true;
do {
@ -478,12 +601,27 @@ void CubicIntersection_IntersectionFinder() {
}
SkDebugf("%s t1=(%1.9g<%1.9g<%1.9g) t2=(%1.9g<%1.9g<%1.9g)\n", __FUNCTION__,
t10, t1Seed, t12, t20, t2Seed, t22);
_Point p10 = xy_at_t(cubic1, t10);
_Point p1Seed = xy_at_t(cubic1, t1Seed);
_Point p12 = xy_at_t(cubic1, t12);
SkDebugf("%s p1=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
p10.x, p10.y, p1Seed.x, p1Seed.y, p12.x, p12.y);
_Point p20 = xy_at_t(cubic2, t20);
_Point p2Seed = xy_at_t(cubic2, t2Seed);
_Point p22 = xy_at_t(cubic2, t22);
SkDebugf("%s p2=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
p20.x, p20.y, p2Seed.x, p2Seed.y, p22.x, p22.y);
}
static void coincidentTest() {
#if 0
void CubicIntersection_CoincidentTest() {
Cubic cubic1 = {{0, 1}, {0, 2}, {1, 0}, {1, 0}};
Cubic cubic2 = {{0, 1}, {0, 2}, {1, 0}, {6, 1}};
}
#endif
}
void CubicIntersection_Test() {
oneOffTests();
coincidentTest();
standardTestCases();
}

Просмотреть файл

@ -205,10 +205,20 @@ int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Flags allowQua
}
}
for (index = 0; index < 4; ++index) {
if (AlmostEqualUlps(cubic[index].x, cubic[minX].x)) {
double cx = cubic[index].x;
double cy = cubic[index].y;
double denom = SkTMax(fabs(cx), SkTMax(fabs(cy),
SkTMax(fabs(cubic[minX].x), fabs(cubic[minY].y))));
if (denom == 0) {
minXSet |= 1 << index;
minYSet |= 1 << index;
continue;
}
double inv = 1 / denom;
if (approximately_equal_half(cx * inv, cubic[minX].x * inv)) {
minXSet |= 1 << index;
}
if (AlmostEqualUlps(cubic[index].y, cubic[minY].y)) {
if (approximately_equal_half(cy * inv, cubic[minY].y * inv)) {
minYSet |= 1 << index;
}
}

Просмотреть файл

@ -149,11 +149,23 @@ void cubic_to_quadratics(const Cubic& cubic, double precision, SkTDArray<double>
double inflectT[2];
int inflections = find_cubic_inflections(cubic, inflectT);
SkASSERT(inflections <= 2);
CubicPair pair;
if (inflections == 1) {
chop_at(cubic, pair, inflectT[0]);
int orderP1 = reduceOrder(pair.first(), reduced, kReduceOrder_NoQuadraticsAllowed);
if (orderP1 < 2) {
--inflections;
} else {
int orderP2 = reduceOrder(pair.second(), reduced, kReduceOrder_NoQuadraticsAllowed);
if (orderP2 < 2) {
--inflections;
}
}
}
if (inflections == 0 && addSimpleTs(cubic, precision, ts)) {
return;
}
if (inflections == 1) {
CubicPair pair;
chop_at(cubic, pair, inflectT[0]);
addTs(pair.first(), precision, 0, inflectT[0], ts);
addTs(pair.second(), precision, inflectT[0], 1, ts);

Просмотреть файл

@ -129,6 +129,9 @@ void CubicToQuadratics_Test() {
}
static Cubic locals[] = {
{{0, 1}, {1.9274705288631189e-19, 1.0000000000000002}, {0.0017190297609673323, 0.99828097023903239},
{0.0053709083094631276, 0.99505672974365911}},
{{14.5975863, 41.632436}, {16.3518929, 26.2639684}, {18.5165519, 7.68775139}, {8.03767257, 89.1628526}},
{{69.7292014, 38.6877352}, {24.7648688, 23.1501713}, {84.9283191, 90.2588441}, {80.392774, 61.3533852}},
{{
@ -152,20 +155,31 @@ static size_t localsCount = sizeof(locals) / sizeof(locals[0]);
#define TEST_AVERAGE_END_POINTS 0 // must take const off to test
extern const bool AVERAGE_END_POINTS;
void CubicsToQuadratics_RandTest() {
static void oneOff(size_t x) {
const Cubic& cubic = locals[x];
const SkPoint skcubic[4] = {{(float) cubic[0].x, (float) cubic[0].y},
{(float) cubic[1].x, (float) cubic[1].y}, {(float) cubic[2].x, (float) cubic[2].y},
{(float) cubic[3].x, (float) cubic[3].y}};
SkScalar skinflect[2];
int skin = SkFindCubicInflections(skcubic, skinflect);
SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]);
SkTDArray<Quadratic> quads;
double precision = calcPrecision(cubic);
(void) cubic_to_quadratics(cubic, precision, quads);
SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count());
}
void CubicsToQuadratics_OneOffTests() {
for (size_t x = 0; x < localsCount; ++x) {
const Cubic& cubic = locals[x];
const SkPoint skcubic[4] = {{(float) cubic[0].x, (float) cubic[0].y},
{(float) cubic[1].x, (float) cubic[1].y}, {(float) cubic[2].x, (float) cubic[2].y},
{(float) cubic[3].x, (float) cubic[3].y}};
SkScalar skinflect[2];
int skin = SkFindCubicInflections(skcubic, skinflect);
SkDebugf("%s %d %1.9g\n", __FUNCTION__, skin, skinflect[0]);
SkTDArray<Quadratic> quads;
double precision = calcPrecision(cubic);
(void) cubic_to_quadratics(cubic, precision, quads);
SkDebugf("%s quads=%d\n", __FUNCTION__, quads.count());
oneOff(x);
}
}
void CubicsToQuadratics_OneOffTest() {
oneOff(0);
}
void CubicsToQuadratics_RandTest() {
srand(0);
const int arrayMax = 8;
const int sampleMax = 10;

Просмотреть файл

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "CubicUtilities.h"
#include "Extrema.h"
#include "QuadraticUtilities.h"
const int precisionUnit = 256; // FIXME: arbitrary -- should try different values in test framework
@ -112,7 +113,8 @@ int cubicRootsReal(double A, double B, double C, double D, double s[3]) {
bzero(str, sizeof(str));
sprintf(str, "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]", A, B, C, D);
#endif
if (approximately_zero_when_compared_to(A, B)
if (approximately_zero(A)
&& approximately_zero_when_compared_to(A, B)
&& approximately_zero_when_compared_to(A, C)
&& approximately_zero_when_compared_to(A, D)) { // we're just a quadratic
return quadraticRootsReal(B, C, D, s);
@ -235,6 +237,11 @@ void dxdy_at_t(const Cubic& cubic, double t, _Point& dxdy) {
dxdy.y = derivativeAtT(&cubic[0].y, t);
}
_Point dxdy_at_t(const Cubic& cubic, double t) {
_Point result = { derivativeAtT(&cubic[0].x, t), derivativeAtT(&cubic[0].y, t) };
return result;
}
int find_cubic_inflections(const Cubic& src, double tValues[])
{
double Ax = src[1].x - src[0].x;
@ -273,7 +280,29 @@ double secondDerivativeAtT(const double* cubic, double t) {
}
#endif
void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
_Point top(const Cubic& cubic, double startT, double endT) {
Cubic sub;
sub_divide(cubic, startT, endT, sub);
_Point topPt = sub[0];
if (topPt.y > sub[3].y || (topPt.y == sub[3].y && topPt.x > sub[3].x)) {
topPt = sub[3];
}
double extremeTs[2];
if (!between(sub[0].y, sub[1].y, sub[3].y) && !between(sub[0].y, sub[2].y, sub[3].y)) {
int roots = findExtrema(sub[0].y, sub[1].y, sub[2].y, sub[3].y, extremeTs);
for (int index = 0; index < roots; ++index) {
_Point mid;
double t = startT + (endT - startT) * extremeTs[index];
xy_at_t(cubic, t, mid.x, mid.y);
if (topPt.y > mid.y || (topPt.y == mid.y && topPt.x > mid.x)) {
topPt = mid;
}
}
}
return topPt;
}
_Point xy_at_t(const Cubic& cubic, double t) {
double one_t = 1 - t;
double one_t2 = one_t * one_t;
double a = one_t2 * one_t;
@ -281,10 +310,19 @@ void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
double t2 = t * t;
double c = 3 * one_t * t2;
double d = t2 * t;
_Point result = {a * cubic[0].x + b * cubic[1].x + c * cubic[2].x + d * cubic[3].x,
a * cubic[0].y + b * cubic[1].y + c * cubic[2].y + d * cubic[3].y};
return result;
}
void xy_at_t(const Cubic& cubic, double t, double& x, double& y) {
_Point xy = xy_at_t(cubic, t);
if (&x) {
x = a * cubic[0].x + b * cubic[1].x + c * cubic[2].x + d * cubic[3].x;
x = xy.x;
}
if (&y) {
y = a * cubic[0].y + b * cubic[1].y + c * cubic[2].y + d * cubic[3].y;
y = xy.y;
}
}

Просмотреть файл

@ -26,10 +26,13 @@ void demote_cubic_to_quad(const Cubic& cubic, Quadratic& quad);
double dx_at_t(const Cubic& , double t);
double dy_at_t(const Cubic& , double t);
void dxdy_at_t(const Cubic& , double t, _Point& y);
_Point dxdy_at_t(const Cubic& cubic, double t);
int find_cubic_inflections(const Cubic& src, double tValues[]);
bool rotate(const Cubic& cubic, int zero, int index, Cubic& rotPath);
void sub_divide(const Cubic& src, double t1, double t2, Cubic& dst);
_Point top(const Cubic& , double startT, double endT);
void xy_at_t(const Cubic& , double t, double& x, double& y);
_Point xy_at_t(const Cubic& , double t);
extern const int precisionUnit;

Просмотреть файл

@ -47,6 +47,8 @@ int horizontalIntersect(const Quadratic& quad, double left, double right,
bool intersect(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
// the following flavor uses quadratic approximation instead of convex hulls
bool intersect2(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
// like '2', but iterates on centers instead of possible edges
bool intersect3(const Cubic& cubic1, const Cubic& cubic2, Intersections& );
bool intersect(const Cubic& cubic, Intersections& i); // return true if cubic self-intersects
int intersect(const Cubic& cubic, const Quadratic& quad, Intersections& );
int intersect(const Cubic& cubic, const _Line& line, Intersections& );

Просмотреть файл

@ -10,7 +10,9 @@
#include <float.h> // for FLT_EPSILON
#include <math.h> // for fabs, sqrt
#include "SkTypes.h"
#include "SkPoint.h"
#define ONE_OFF_DEBUG 0
// FIXME: move these into SkTypes.h
template <typename T> inline T SkTMax(T a, T b) {
@ -33,22 +35,24 @@ int UlpsDiff(float A, float B);
// FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
const double FLT_EPSILON_SQRT = sqrt(FLT_EPSILON);
const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
inline bool approximately_zero(double x) {
#ifdef SK_DEBUG
const double ROUGH_EPSILON = FLT_EPSILON * 16;
#endif
inline bool approximately_zero(double x) {
return fabs(x) < FLT_EPSILON;
}
inline bool precisely_zero(double x) {
return fabs(x) < DBL_EPSILON;
}
inline bool approximately_zero(float x) {
return fabs(x) < FLT_EPSILON;
}
@ -56,6 +60,10 @@ inline bool approximately_zero_cubed(double x) {
return fabs(x) < FLT_EPSILON_CUBED;
}
inline bool approximately_zero_half(double x) {
return fabs(x) < FLT_EPSILON_HALF;
}
inline bool approximately_zero_squared(double x) {
return fabs(x) < FLT_EPSILON_SQUARED;
}
@ -97,6 +105,10 @@ inline bool approximately_equal(double x, double y) {
#endif
}
inline bool approximately_equal_half(double x, double y) {
return approximately_zero_half(x - y);
}
inline bool approximately_equal_squared(double x, double y) {
return approximately_equal(x, y);
}
@ -168,6 +180,12 @@ inline bool between(double a, double b, double c) {
return (a - b) * (c - b) <= 0;
}
#ifdef SK_DEBUG
inline bool roughly_equal(double x, double y) {
return fabs(x - y) < ROUGH_EPSILON;
}
#endif
struct _Point {
double x;
double y;
@ -209,22 +227,32 @@ struct _Point {
// return approximately_equal(a.y, y) && approximately_equal(a.x, x);
// because that will not take the magnitude of the values
bool approximatelyEqual(const _Point& a) const {
#if 0
return AlmostEqualUlps((float) x, (float) a.x)
&& AlmostEqualUlps((float) y, (float) a.y);
#else
double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
if (denom == 0) {
return true;
}
double inv = 1 / denom;
return approximately_equal(x * inv, a.x * inv) && approximately_equal(y * inv, a.y * inv);
#endif
}
bool approximatelyEqualHalf(const _Point& a) const {
double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
if (denom == 0) {
return true;
}
double inv = 1 / denom;
return approximately_equal_half(x * inv, a.x * inv)
&& approximately_equal_half(y * inv, a.y * inv);
}
bool approximatelyZero() const {
return approximately_zero(x) && approximately_zero(y);
}
SkPoint asSkPoint() const {
SkPoint pt = {SkDoubleToScalar(x), SkDoubleToScalar(y)};
return pt;
}
double cross(const _Point& a) const {
return x * a.y - y * a.x;

Просмотреть файл

@ -64,7 +64,7 @@ static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
Intersections& intersections) {
const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
return intersect(aLine, bLine, intersections);
}
static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
@ -87,7 +87,7 @@ static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
Intersections& intersections) {
const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
const Quadratic bQuad = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}};
intersect(aQuad, bQuad, intersections);
intersect2(aQuad, bQuad, intersections);
return intersections.fUsed;
}

Просмотреть файл

@ -13,9 +13,6 @@ struct State4;
//extern int comparePaths(const SkPath& one, const SkPath& two);
extern int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap);
extern int comparePaths(const SkPath& one, const SkPath& scaledOne, const SkPath& two,
const SkPath& scaledTwo, SkBitmap& bitmap,
const SkPath& a, const SkPath& b, const ShapeOp shapeOp);
extern void comparePathsTiny(const SkPath& one, const SkPath& two);
extern bool drawAsciiPaths(const SkPath& one, const SkPath& two,
bool drawPaths);

Просмотреть файл

@ -8,6 +8,7 @@
#include "Intersection_Tests.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkStream.h"
@ -103,8 +104,17 @@ void showPath(const SkPath& path, const char* str) {
showPathContour(iter);
}
const int bitWidth = 64;
const int bitHeight = 64;
static void showPath(const SkPath& path, const char* str, const SkMatrix& scale) {
SkPath scaled;
SkMatrix inverse;
bool success = scale.invert(&inverse);
if (!success) SkASSERT(0);
path.transform(inverse, &scaled);
showPath(scaled, str);
}
const int bitWidth = 64;
const int bitHeight = 64;
static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
SkRect larger = one.getBounds();
@ -249,19 +259,21 @@ int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap) {
}
static void showShapeOpPath(const SkPath& one, const SkPath& two, const SkPath& a, const SkPath& b,
const SkPath& scaledOne, const SkPath& scaledTwo, const ShapeOp shapeOp) {
const SkPath& scaledOne, const SkPath& scaledTwo, const ShapeOp shapeOp,
const SkMatrix& scale) {
SkASSERT((unsigned) shapeOp < sizeof(opStrs) / sizeof(opStrs[0]));
showPath(a, "minuend:");
SkDebugf("op: %s\n", opStrs[shapeOp]);
showPath(b, "subtrahend:");
showPath(one, "region:");
showPath(scaledOne, "region:", scale);
showPath(two, "op result:");
drawAsciiPaths(scaledOne, scaledTwo, true);
}
int comparePaths(const SkPath& one, const SkPath& scaledOne, const SkPath& two,
static int comparePaths(const SkPath& one, const SkPath& scaledOne, const SkPath& two,
const SkPath& scaledTwo,
SkBitmap& bitmap, const SkPath& a, const SkPath& b, const ShapeOp shapeOp) {
SkBitmap& bitmap, const SkPath& a, const SkPath& b, const ShapeOp shapeOp,
const SkMatrix& scale) {
int errors2x2;
int errors = pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
if (errors2x2 == 0) {
@ -269,11 +281,11 @@ int comparePaths(const SkPath& one, const SkPath& scaledOne, const SkPath& two,
}
const int MAX_ERRORS = 8;
if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
showShapeOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp);
showShapeOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
}
if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
showShapeOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp);
showShapeOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
SkASSERT(0);
}
return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
@ -390,7 +402,7 @@ bool testShapeOp(const SkPath& a, const SkPath& b, const ShapeOp shapeOp) {
SkPath scaledOut;
scaledOut.addPath(out, scale);
scaledOut.setFillType(out.getFillType());
int result = comparePaths(pathOut, scaledPathOut, out, scaledOut, bitmap, a, b, shapeOp);
int result = comparePaths(pathOut, scaledPathOut, out, scaledOut, bitmap, a, b, shapeOp, scale);
if (result && gPathStrAssert) {
SkASSERT(0);
}

Просмотреть файл

@ -14,14 +14,17 @@ void parseSVG();
void Intersection_Tests() {
int testsRun = 0;
SimplifyNew_Test();
QuadraticIntersection_OneOffTest();
CubicsToQuadratics_OneOffTest();
CubicIntersection_IntersectionFinder();
CubicIntersection_OneOffTest();
CubicIntersection_OneOffTests();
QuadraticIntersection_OneOffTest();
#if 0
parseSVG();
#endif
SimplifyNew_Test();
QuadraticIntersection_PointFinder();
// QuadraticIntersection_PointFinder();
ShapeOps4x4CubicsThreaded_Test(testsRun);
CubicToQuadratics_Test();
QuadraticIntersection_Test();
@ -62,7 +65,7 @@ void Intersection_Tests() {
SimplifyRectangularPaths_Test();
SimplifyQuadralateralPaths_Test();
ActiveEdge_Test();
// ActiveEdge_Test();
QuadraticCoincidence_Test();
QuadraticIntersection_Test();

Просмотреть файл

@ -13,11 +13,14 @@ void CubicBezierClip_Test();
void CubicCoincidence_Test();
void CubicIntersection_IntersectionFinder();
void CubicIntersection_OneOffTest();
void CubicIntersection_OneOffTests();
void CubicIntersection_Test();
void CubicIntersection_RandTest();
void CubicIntersection_RandTestOld();
void CubicParameterization_Test();
void CubicReduceOrder_Test();
void CubicsToQuadratics_OneOffTest();
void CubicsToQuadratics_OneOffTests();
void CubicsToQuadratics_RandTest();
void CubicToQuadratics_Test();
void Inline_Tests();

Просмотреть файл

@ -8,83 +8,93 @@
#include "DataTypes.h"
#include "Intersections.h"
void Intersections::addCoincident(double s1, double e1, double s2, double e2) {
SkASSERT((fCoincidentUsed & 1) != 1);
for (int index = 0; index < fCoincidentUsed; index += 2) {
double cs1 = fCoincidentT[fSwap][index];
double ce1 = fCoincidentT[fSwap][index + 1];
bool s1in = approximately_between(cs1, s1, ce1);
bool e1in = approximately_between(cs1, e1, ce1);
double cs2 = fCoincidentT[fSwap ^ 1][index];
double ce2 = fCoincidentT[fSwap ^ 1][index + 1];
bool s2in = approximately_between(cs2, s2, ce2);
bool e2in = approximately_between(cs2, e2, ce2);
void Intersections::insertCoincidentPair(double s1, double e1, double s2, double e2,
const _Point& startPt, const _Point& endPt) {
if (fSwap) {
remove(s2, e2, startPt, endPt);
} else {
remove(s1, e1, startPt, endPt);
}
SkASSERT(coincidentUsed() == fUsed);
SkASSERT((coincidentUsed() & 1) != 1);
int i1 = 0;
int i2 = 0;
do {
while (i1 < fUsed && !(fIsCoincident[fSwap] & (1 << i1))) {
++i1;
}
if (i1 == fUsed) {
break;
}
SkASSERT(i1 < fUsed);
int iEnd1 = i1 + 1;
while (!(fIsCoincident[fSwap] & (1 << iEnd1))) {
++iEnd1;
}
SkASSERT(iEnd1 < fUsed);
double cs1 = fT[fSwap][i1];
double ce1 = fT[fSwap][iEnd1];
bool s1in = between(cs1, s1, ce1) || startPt.approximatelyEqual(fPt[i1])
|| startPt.approximatelyEqual(fPt[iEnd1]);
bool e1in = between(cs1, e1, ce1) || endPt.approximatelyEqual(fPt[i1])
|| endPt.approximatelyEqual(fPt[iEnd1]);
while (i2 < fUsed && !(fIsCoincident[fSwap ^ 1] & (1 << i2))) {
++i2;
}
int iEnd2 = i2 + 1;
while (!(fIsCoincident[fSwap ^ 1] & (1 << iEnd2))) {
++iEnd2;
}
SkASSERT(iEnd2 < fUsed);
double cs2 = fT[fSwap ^ 1][i2];
double ce2 = fT[fSwap ^ 1][iEnd2];
bool s2in = between(cs2, s2, ce2) || startPt.approximatelyEqual(fPt[i2])
|| startPt.approximatelyEqual(fPt[iEnd2]);
bool e2in = between(cs2, e2, ce2) || endPt.approximatelyEqual(fPt[i2])
|| endPt.approximatelyEqual(fPt[iEnd2]);
if ((s1in | e1in) & (s2in | e2in)) {
double lesser1 = SkTMin(cs1, ce1);
index += cs1 > ce1;
if (s1 < lesser1) {
fCoincidentT[fSwap][index] = s1;
} else if (e1 < lesser1) {
fCoincidentT[fSwap][index] = e1;
if (s1 < cs1) {
fT[fSwap][i1] = s1;
fPt[i1] = startPt;
} else if (e1 < cs1) {
fT[fSwap][i1] = e1;
fPt[i1] = endPt;
}
index ^= 1;
double greater1 = fCoincidentT[fSwap][index];
if (s1 > greater1) {
fCoincidentT[fSwap][index] = s1;
} else if (e1 > greater1) {
fCoincidentT[fSwap][index] = e1;
if (s1 > ce1) {
fT[fSwap][iEnd1] = s1;
fPt[iEnd1] = startPt;
} else if (e1 > ce1) {
fT[fSwap][iEnd1] = e1;
fPt[iEnd1] = endPt;
}
index &= ~1;
double lesser2 = SkTMin(cs2, ce2);
index += cs2 > ce2;
if (s2 < lesser2) {
fCoincidentT[fSwap ^ 1][index] = s2;
} else if (e2 < lesser2) {
fCoincidentT[fSwap ^ 1][index] = e2;
if (s2 > e2) {
SkTSwap(cs2, ce2);
SkTSwap(i2, iEnd2);
}
index ^= 1;
double greater2 = fCoincidentT[fSwap ^ 1][index];
if (s2 > greater2) {
fCoincidentT[fSwap ^ 1][index] = s2;
} else if (e2 > greater2) {
fCoincidentT[fSwap ^ 1][index] = e2;
if (s2 < cs2) {
fT[fSwap ^ 1][i2] = s2;
} else if (e2 < cs2) {
fT[fSwap ^ 1][i2] = e2;
}
if (s2 > ce2) {
fT[fSwap ^ 1][iEnd2] = s2;
} else if (e2 > ce2) {
fT[fSwap ^ 1][iEnd2] = e2;
}
return;
}
}
SkASSERT(fCoincidentUsed < 9);
fCoincidentT[fSwap][fCoincidentUsed] = s1;
fCoincidentT[fSwap ^ 1][fCoincidentUsed] = s2;
++fCoincidentUsed;
fCoincidentT[fSwap][fCoincidentUsed] = e1;
fCoincidentT[fSwap ^ 1][fCoincidentUsed] = e2;
++fCoincidentUsed;
// FIXME: assert that no entries in normal range lie between s and e
remove(s1, e1);
remove(s2, e2);
} while (true);
SkASSERT(fUsed < 9);
insertCoincident(s1, s2, startPt);
insertCoincident(e1, e2, endPt);
}
void Intersections::cleanUp() {
SkASSERT(fCoincidentUsed);
SkASSERT(fUsed);
// find any entries in fT that could be part of the coincident range
}
// FIXME: this doesn't respect swap, but add coincident does -- seems inconsistent
void Intersections::insert(double one, double two) {
int Intersections::insert(double one, double two, const _Point& pt) {
SkASSERT(fUsed <= 1 || fT[0][0] < fT[0][1]);
int index;
for (index = 0; index < fCoincidentUsed; ++index ) {
if (approximately_equal(fCoincidentT[0][index], one)
&& approximately_equal(fCoincidentT[1][index], two)) {
return;
}
}
for (index = 0; index < fUsed; ++index) {
if (approximately_equal(fT[0][index], one)
&& approximately_equal(fT[1][index], two)) {
return;
if (approximately_equal(fT[0][index], one) || pt.approximatelyEqual(fPt[index])) {
return -1;
}
if (fT[0][index] > one) {
break;
@ -93,55 +103,35 @@ void Intersections::insert(double one, double two) {
SkASSERT(fUsed < 9);
int remaining = fUsed - index;
if (remaining > 0) {
memmove(&fPt[index + 1], &fPt[index], sizeof(fPt[0]) * remaining);
memmove(&fT[0][index + 1], &fT[0][index], sizeof(fT[0][0]) * remaining);
memmove(&fT[1][index + 1], &fT[1][index], sizeof(fT[1][0]) * remaining);
fIsCoincident[0] += fIsCoincident[0] & ~((1 << index) - 1);
fIsCoincident[1] += fIsCoincident[1] & ~((1 << index) - 1);
}
fPt[index] = pt;
fT[0][index] = one;
fT[1][index] = two;
++fUsed;
return index;
}
// FIXME: all callers should be moved to regular insert. Failures are likely
// if two separate callers differ on whether ts are equal or not
void Intersections::insertOne(double t, int side) {
int used = side ? fUsed2 : fUsed;
SkASSERT(used <= 1 || fT[side][0] < fT[side][1]);
int index;
for (index = 0; index < used; ++index) {
if (approximately_equal(fT[side][index], t)) {
return;
}
if (fT[side][index] > t) {
break;
void Intersections::remove(double one, double two, const _Point& startPt, const _Point& endPt) {
for (int index = fUsed - 1; index >= 0; --index) {
if (!(fIsCoincident[0] & (1 << index)) && (between(one, fT[fSwap][index], two)
|| startPt.approximatelyEqual(fPt[index])
|| endPt.approximatelyEqual(fPt[index]))) {
SkASSERT(fUsed > 0);
int remaining = --fUsed - index;
if (remaining > 0) {
memmove(&fPt[index], &fPt[index - 1], sizeof(fPt[0]) * remaining);
memmove(&fT[0][index], &fT[0][index - 1], sizeof(fT[0][0]) * remaining);
memmove(&fT[1][index], &fT[1][index - 1], sizeof(fT[1][0]) * remaining);
int coBit = fIsCoincident[0] & (1 << index);
fIsCoincident[0] -= ((fIsCoincident[0] >> 1) & ~((1 << index) - 1)) + coBit;
SkASSERT(!(coBit ^ (fIsCoincident[1] & (1 << index))));
fIsCoincident[1] -= ((fIsCoincident[1] >> 1) & ~((1 << index) - 1)) + coBit;
}
}
}
SkASSERT(used < 9);
int remaining = used - index;
if (remaining > 0) {
memmove(&fT[side][index + 1], &fT[side][index], sizeof(fT[side][0]) * remaining);
}
fT[side][index] = t;
side ? ++fUsed2 : ++fUsed;
}
void Intersections::remove(double one, double two) {
int index;
for (index = 0; index < fUsed; ++index) {
if (approximately_equal(fT[0][index], one)
&& approximately_equal(fT[1][index], two)) {
goto foundIt;
}
if (fT[0][index] > one) {
return;
}
}
return;
foundIt:
SkASSERT(fUsed > 0);
int remaining = fUsed - index;
if (remaining > 0) {
memmove(&fT[0][index], &fT[0][index - 1], sizeof(fT[0][0]) * remaining);
memmove(&fT[1][index], &fT[1][index - 1], sizeof(fT[1][0]) * remaining);
}
--fUsed;
}

Просмотреть файл

@ -11,60 +11,40 @@ class Intersections {
public:
Intersections()
: fFlip(0)
, fSwap(0)
#if SK_DEBUG
, fDepth(0)
#endif
, fSwap(0)
{
// OPTIMIZE: don't need to be initialized in release
#if SK_DEBUG
bzero(fPt, sizeof(fPt));
bzero(fT, sizeof(fT));
bzero(fCoincidentT, sizeof(fCoincidentT));
bzero(fIsCoincident, sizeof(fIsCoincident));
#endif
reset();
}
void add(double one, double two) {
for (int index = 0; index < fUsed; ++index) {
if (approximately_equal(fT[fSwap][index], one)
&& approximately_equal(fT[fSwap ^ 1][index], two)) {
return;
}
}
SkASSERT(fUsed < 9);
fT[fSwap][fUsed] = one;
fT[fSwap ^ 1][fUsed] = two;
++fUsed;
}
// start if index == 0 : end if index == 1
void addCoincident(double one, double two) {
for (int index = 0; index < fCoincidentUsed; ++index) {
if (approximately_equal(fCoincidentT[fSwap][index], one)
&& approximately_equal(fCoincidentT[fSwap ^ 1][index], two)) {
return;
}
}
SkASSERT(fCoincidentUsed < 9);
fCoincidentT[fSwap][fCoincidentUsed] = one;
fCoincidentT[fSwap ^ 1][fCoincidentUsed] = two;
++fCoincidentUsed;
}
void addCoincident(double s1, double e1, double s2, double e2);
// FIXME: this is necessary because curve/curve intersections are noisy
// remove once curve/curve intersections are improved
void cleanUp();
int coincidentUsed() const {
return fCoincidentUsed;
if (!fIsCoincident[0]) {
SkASSERT(!fIsCoincident[0]);
return 0;
}
int count = 0;
SkDEBUGCODE(int count2 = 0;)
for (int index = 0; index < fUsed; ++index) {
if (fIsCoincident[0] & (1 << index)) {
++count;
}
#if SK_DEBUG
if (fIsCoincident[1] & (1 << index)) {
++count2;
}
#endif
}
SkASSERT(count == count2);
return count;
}
#if SK_DEBUG
int depth() const {
return fDepth;
}
#endif
void offset(int base, double start, double end) {
for (int index = base; index < fUsed; ++index) {
double val = fT[fSwap][index];
@ -74,20 +54,34 @@ public:
}
}
void insert(double one, double two);
void insertOne(double t, int side);
int insert(double one, double two, const _Point& pt);
// start if index == 0 : end if index == 1
void insertCoincident(double one, double two, const _Point& pt) {
int index = insertSwap(one, two, pt);
int bit = 1 << index;
fIsCoincident[0] |= bit;
fIsCoincident[1] |= bit;
}
void insertCoincidentPair(double s1, double e1, double s2, double e2,
const _Point& startPt, const _Point& endPt);
int insertSwap(double one, double two, const _Point& pt) {
if (fSwap) {
return insert(two, one, pt);
} else {
return insert(one, two, pt);
}
}
bool intersected() const {
return fUsed > 0;
}
bool insertBalanced() const {
return fUsed == fUsed2;
}
// leaves flip, swap alone
void reset() {
fUsed = fUsed2 = fCoincidentUsed = 0;
fUsed = /* fUsed2 = fCoincidentUsed = */ 0;
fUnsortable = false;
}
@ -122,11 +116,16 @@ public:
SkASSERT(++fDepth < 16);
}
#if SK_DEBUG
int depth() const {
return fDepth;
}
#endif
_Point fPt[9];
double fT[2][9];
double fCoincidentT[2][9];
int fUsed;
int fUsed2;
int fCoincidentUsed;
unsigned short fIsCoincident[2]; // bit arrays, one bit set for each coincident T
unsigned char fUsed;
bool fFlip;
bool fUnsortable;
#if SK_DEBUG
@ -134,9 +133,9 @@ public:
#endif
protected:
// used by addCoincident to remove ordinary intersections in range
void remove(double one, double two);
void remove(double one, double two, const _Point& startPt, const _Point& endPt);
private:
int fSwap;
bool fSwap;
};
#endif

Просмотреть файл

@ -107,7 +107,9 @@ int intersect() {
double cubicT = rootVals[index];
double lineT = findLineT(cubicT);
if (pinTs(cubicT, lineT)) {
intersections.insert(cubicT, lineT);
_Point pt;
xy_at_t(line, lineT, pt.x, pt.y);
intersections.insert(cubicT, lineT, pt);
}
}
return intersections.fUsed;
@ -125,12 +127,12 @@ int horizontalIntersect(double axisIntercept, double left, double right, bool fl
double rootVals[3];
int roots = horizontalIntersect(axisIntercept, rootVals);
for (int index = 0; index < roots; ++index) {
double x;
_Point pt;
double cubicT = rootVals[index];
xy_at_t(cubic, cubicT, x, *(double*) NULL);
double lineT = (x - left) / (right - left);
xy_at_t(cubic, cubicT, pt.x, pt.y);
double lineT = (pt.x - left) / (right - left);
if (pinTs(cubicT, lineT)) {
intersections.insert(cubicT, lineT);
intersections.insert(cubicT, lineT, pt);
}
}
if (flipped) {
@ -151,12 +153,12 @@ int verticalIntersect(double axisIntercept, double top, double bottom, bool flip
double rootVals[3];
int roots = verticalIntersect(axisIntercept, rootVals);
for (int index = 0; index < roots; ++index) {
double y;
_Point pt;
double cubicT = rootVals[index];
xy_at_t(cubic, cubicT, *(double*) NULL, y);
double lineT = (y - top) / (bottom - top);
xy_at_t(cubic, cubicT, pt.x, pt.y);
double lineT = (pt.y - top) / (bottom - top);
if (pinTs(cubicT, lineT)) {
intersections.insert(cubicT, lineT);
intersections.insert(cubicT, lineT, pt);
}
}
if (flipped) {
@ -172,7 +174,7 @@ void addEndPoints()
for (int cIndex = 0; cIndex < 4; cIndex += 3) {
for (int lIndex = 0; lIndex < 2; lIndex++) {
if (cubic[cIndex] == line[lIndex]) {
intersections.insert(cIndex >> 1, lIndex);
intersections.insert(cIndex >> 1, lIndex, line[lIndex]);
}
}
}
@ -185,10 +187,10 @@ void addHorizontalEndPoints(double left, double right, double y)
continue;
}
if (cubic[cIndex].x == left) {
intersections.insert(cIndex >> 1, 0);
intersections.insert(cIndex >> 1, 0, cubic[cIndex]);
}
if (cubic[cIndex].x == right) {
intersections.insert(cIndex >> 1, 1);
intersections.insert(cIndex >> 1, 1, cubic[cIndex]);
}
}
}
@ -200,10 +202,10 @@ void addVerticalEndPoints(double top, double bottom, double x)
continue;
}
if (cubic[cIndex].y == top) {
intersections.insert(cIndex >> 1, 0);
intersections.insert(cIndex >> 1, 0, cubic[cIndex]);
}
if (cubic[cIndex].y == bottom) {
intersections.insert(cIndex >> 1, 1);
intersections.insert(cIndex >> 1, 1, cubic[cIndex]);
}
}
}

Просмотреть файл

@ -7,6 +7,7 @@
#include "CurveIntersection.h"
#include "Intersections.h"
#include "LineIntersection.h"
#include "LineUtilities.h"
/* Determine the intersection point of two lines. This assumes the lines are not parallel,
and that that the lines are infinite.
@ -25,13 +26,21 @@ void lineIntersect(const _Line& a, const _Line& b, _Point& p) {
p.y = (term1 * byLen - ayLen * term2) / denom;
}
static int computePoints(const _Line& a, int used, Intersections& i) {
i.fPt[0] = xy_at_t(a, i.fT[0][0]);
if ((i.fUsed = used) == 2) {
i.fPt[1] = xy_at_t(a, i.fT[0][1]);
}
return i.fUsed;
}
/*
Determine the intersection point of two line segments
Return FALSE if the lines don't intersect
from: http://paulbourke.net/geometry/lineline2d/
*/
int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]) {
int intersect(const _Line& a, const _Line& b, Intersections& i) {
double axLen = a[1].x - a[0].x;
double ayLen = a[1].y - a[0].y;
double bxLen = b[1].x - b[0].x;
@ -57,13 +66,10 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
if (mayNotOverlap) {
return 0;
}
if (aRange) {
aRange[0] = numerA;
}
if (bRange) {
bRange[0] = numerB;
}
return 1;
i.fT[0][0] = numerA;
i.fT[1][0] = numerB;
i.fPt[0] = xy_at_t(a, numerA);
return computePoints(a, 1, i);
}
/* See if the axis intercepts match:
ay - ax * ayLen / axLen == by - bx * ayLen / axLen
@ -84,8 +90,6 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
aPtr = &a[0].y;
bPtr = &b[0].y;
}
SkASSERT(aRange);
SkASSERT(bRange);
double a0 = aPtr[0];
double a1 = aPtr[2];
double b0 = bPtr[0];
@ -98,27 +102,27 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
if (!between(b0, a0, b1)) {
return 0;
}
aRange[0] = aRange[1] = 0;
i.fT[0][0] = i.fT[0][1] = 0;
} else {
double at0 = (a0 - b0) / aDenom;
double at1 = (a0 - b1) / aDenom;
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
return 0;
}
aRange[0] = SkTMax(SkTMin(at0, 1.0), 0.0);
aRange[1] = SkTMax(SkTMin(at1, 1.0), 0.0);
i.fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
i.fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
}
double bDenom = b0 - b1;
if (approximately_zero(bDenom)) {
bRange[0] = bRange[1] = 0;
i.fT[1][0] = i.fT[1][1] = 0;
} else {
int bIn = aDenom * bDenom < 0;
bRange[bIn] = SkTMax(SkTMin((b0 - a0) / bDenom, 1.0), 0.0);
bRange[!bIn] = SkTMax(SkTMin((b0 - a1) / bDenom, 1.0), 0.0);
i.fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / bDenom, 1.0), 0.0);
i.fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / bDenom, 1.0), 0.0);
}
bool second = fabs(aRange[0] - aRange[1]) > FLT_EPSILON;
SkASSERT((fabs(bRange[0] - bRange[1]) <= FLT_EPSILON) ^ second);
return 1 + second;
bool second = fabs(i.fT[0][0] - i.fT[0][1]) > FLT_EPSILON;
SkASSERT((fabs(i.fT[1][0] - i.fT[1][1]) <= FLT_EPSILON) ^ second);
return computePoints(a, 1 + second, i);
}
int horizontalIntersect(const _Line& line, double y, double tRange[2]) {
@ -219,7 +223,7 @@ int horizontalIntersect(const _Line& line, double left, double right,
> FLT_EPSILON;
SkASSERT((fabs(intersections.fT[1][0] - intersections.fT[1][1])
<= FLT_EPSILON) ^ second);
return 1 + second;
return computePoints(line, 1 + second, intersections);
#endif
break;
}
@ -229,7 +233,7 @@ int horizontalIntersect(const _Line& line, double left, double right,
intersections.fT[1][index] = 1 - intersections.fT[1][index];
}
}
return result;
return computePoints(line, result, intersections);
}
static int verticalIntersect(const _Line& line, double x, double tRange[2]) {
@ -308,7 +312,7 @@ int verticalIntersect(const _Line& line, double top, double bottom,
> FLT_EPSILON;
SkASSERT((fabs(intersections.fT[1][0] - intersections.fT[1][1])
<= FLT_EPSILON) ^ second);
return 1 + second;
return computePoints(line, 1 + second, intersections);
#endif
break;
}
@ -318,7 +322,7 @@ int verticalIntersect(const _Line& line, double top, double bottom,
intersections.fT[1][index] = 1 - intersections.fT[1][index];
}
}
return result;
return computePoints(line, result, intersections);
}
// from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.py

Просмотреть файл

@ -7,13 +7,13 @@
#ifndef LineIntersection_DEFINE
#define LineIntersection_DEFINE
#include "DataTypes.h"
#include "Intersections.h"
int horizontalIntersect(const _Line& line, double y, double tRange[2]);
int horizontalLineIntersect(const _Line& line, double left, double right,
double y, double tRange[2]);
void lineIntersect(const _Line& a, const _Line& b, _Point& p);
int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]);
int intersect(const _Line& a, const _Line& b, Intersections&);
bool testIntersect(const _Line& a, const _Line& b);
int verticalLineIntersect(const _Line& line, double top, double bottom,
double x, double tRange[2]);

Просмотреть файл

@ -39,20 +39,20 @@ void LineIntersection_Test() {
for (index = firstLineIntersectionTest; index < tests_count; ++index) {
const _Line& line1 = tests[index][0];
const _Line& line2 = tests[index][1];
double t1[2], t2[2];
int pts = intersect(line1, line2, t1, t2);
Intersections ts;
int pts = intersect(line1, line2, ts);
if (!pts) {
printf("%s [%zu] no intersection found\n", __FUNCTION__, index);
}
for (int i = 0; i < pts; ++i) {
_Point result1, result2;
xy_at_t(line1, t1[i], result1.x, result1.y);
xy_at_t(line2, t2[i], result2.x, result2.y);
xy_at_t(line1, ts.fT[0][i], result1.x, result1.y);
xy_at_t(line2, ts.fT[1][i], result2.x, result2.y);
if (!result1.approximatelyEqual(result2)) {
if (pts == 1) {
printf("%s [%zu] not equal\n", __FUNCTION__, index);
} else {
xy_at_t(line2, t2[i ^ 1], result2.x, result2.y);
xy_at_t(line2, ts.fT[1][i ^ 1], result2.x, result2.y);
if (!result1.approximatelyEqual(result2)) {
printf("%s [%zu] not equal\n", __FUNCTION__, index);
}
@ -63,8 +63,8 @@ void LineIntersection_Test() {
for (index = firstNoIntersectionTest; index < noIntersect_count; ++index) {
const _Line& line1 = noIntersect[index][0];
const _Line& line2 = noIntersect[index][1];
double t1[2], t2[2];
int pts = intersect(line1, line2, t1, t2);
Intersections ts;
int pts = intersect(line1, line2, ts);
if (pts) {
printf("%s [%zu] no intersection expected\n", __FUNCTION__, index);
}

Просмотреть файл

@ -135,7 +135,9 @@ int intersect() {
double quadT = rootVals[index];
double lineT = findLineT(quadT);
if (pinTs(quadT, lineT)) {
intersections.insert(quadT, lineT);
_Point pt;
xy_at_t(line, lineT, pt.x, pt.y);
intersections.insert(quadT, lineT, pt);
}
}
return intersections.fUsed;
@ -156,12 +158,12 @@ int horizontalIntersect(double axisIntercept, double left, double right, bool fl
double rootVals[2];
int roots = horizontalIntersect(axisIntercept, rootVals);
for (int index = 0; index < roots; ++index) {
double x;
_Point pt;
double quadT = rootVals[index];
xy_at_t(quad, quadT, x, *(double*) NULL);
double lineT = (x - left) / (right - left);
xy_at_t(quad, quadT, pt.x, pt.y);
double lineT = (pt.x - left) / (right - left);
if (pinTs(quadT, lineT)) {
intersections.insert(quadT, lineT);
intersections.insert(quadT, lineT, pt);
}
}
if (flipped) {
@ -185,12 +187,12 @@ int verticalIntersect(double axisIntercept, double top, double bottom, bool flip
double rootVals[2];
int roots = verticalIntersect(axisIntercept, rootVals);
for (int index = 0; index < roots; ++index) {
double y;
_Point pt;
double quadT = rootVals[index];
xy_at_t(quad, quadT, *(double*) NULL, y);
double lineT = (y - top) / (bottom - top);
xy_at_t(quad, quadT, pt.x, pt.y);
double lineT = (pt.y - top) / (bottom - top);
if (pinTs(quadT, lineT)) {
intersections.insert(quadT, lineT);
intersections.insert(quadT, lineT, pt);
}
}
if (flipped) {
@ -207,7 +209,7 @@ void addEndPoints()
for (int qIndex = 0; qIndex < 3; qIndex += 2) {
for (int lIndex = 0; lIndex < 2; lIndex++) {
if (quad[qIndex] == line[lIndex]) {
intersections.insert(qIndex >> 1, lIndex);
intersections.insert(qIndex >> 1, lIndex, line[lIndex]);
}
}
}
@ -220,10 +222,10 @@ void addHorizontalEndPoints(double left, double right, double y)
continue;
}
if (quad[qIndex].x == left) {
intersections.insert(qIndex >> 1, 0);
intersections.insert(qIndex >> 1, 0, quad[qIndex]);
}
if (quad[qIndex].x == right) {
intersections.insert(qIndex >> 1, 1);
intersections.insert(qIndex >> 1, 1, quad[qIndex]);
}
}
}
@ -235,10 +237,10 @@ void addVerticalEndPoints(double top, double bottom, double x)
continue;
}
if (quad[qIndex].y == top) {
intersections.insert(qIndex >> 1, 0);
intersections.insert(qIndex >> 1, 0, quad[qIndex]);
}
if (quad[qIndex].y == bottom) {
intersections.insert(qIndex >> 1, 1);
intersections.insert(qIndex >> 1, 1, quad[qIndex]);
}
}
}

Просмотреть файл

@ -125,3 +125,9 @@ void xy_at_t(const _Line& line, double t, double& x, double& y) {
y = one_t * line[0].y + t * line[1].y;
}
}
_Point xy_at_t(const _Line& line, double t) {
double one_t = 1 - t;
_Point result = { one_t * line[0].x + t * line[1].x, one_t * line[0].y + t * line[1].y };
return result;
}

Просмотреть файл

@ -12,6 +12,7 @@ double is_left(const _Line& line, const _Point& pt);
void sub_divide(const _Line& src, double t1, double t2, _Line& dst);
double t_at(const _Line&, const _Point& );
void xy_at_t(const _Line& , double t, double& x, double& y);
_Point xy_at_t(const _Line& , double t);
enum x_at_flags {
kFindTopMin = 1,

Просмотреть файл

@ -0,0 +1,354 @@
#include <ctype.h>
#include "SkPath.h"
#include "SkParse.h"
#include "SkPoint.h"
#include "SkUtils.h"
#define QUADRATIC_APPROXIMATION 0
const char logoStr[] =
"<path fill=\"#0081C6\""
"d=\"M440.51,289.479c1.623,1.342,5.01,4.164,5.01,9.531c0,5.223-2.965,7.697-5.93,10.024"
"c-0.918,0.916-1.977,1.907-1.977,3.462c0,1.551,1.059,2.397,1.834,3.035l2.545,1.973c3.105,2.613,5.928,5.016,5.928,9.889"
"c0,6.635-6.426,13.341-18.566,13.341c-10.238,0-15.178-4.87-15.178-10.097c0-2.543,1.268-6.139,5.438-8.613"
"c4.373-2.682,10.307-3.033,13.482-3.249c-0.99-1.271-2.119-2.61-2.119-4.798c0-1.199,0.355-1.907,0.707-2.754"
"c-0.779,0.07-1.553,0.141-2.26,0.141c-7.482,0-11.719-5.579-11.719-11.082c0-3.247,1.484-6.851,4.518-9.461"
"c4.025-3.318,8.824-3.883,12.639-3.883h14.541l-4.518,2.541H440.51z"
"M435.494,320.826c-0.562-0.072-0.916-0.072-1.619-0.072"
"c-0.637,0-4.451,0.143-7.416,1.132c-1.553,0.564-6.07,2.257-6.07,7.271c0,5.013,4.873,8.615,12.426,8.615"
"c6.775,0,10.379-3.253,10.379-7.624C443.193,326.54,440.863,324.64,435.494,320.826z"
"M437.543,307.412"
"c1.623-1.627,1.764-3.883,1.764-5.154c0-5.083-3.035-12.99-8.893-12.99c-1.838,0-3.812,0.918-4.945,2.331"
"c-1.199,1.483-1.551,3.387-1.551,5.225c0,4.729,2.754,12.565,8.826,12.565C434.508,309.389,436.41,308.543,437.543,307.412z\"/>"
"<path fill=\"#FFD200\""
"d=\"M396.064,319.696c-11.206,0-17.198-8.739-17.198-16.636c0-9.233,7.542-17.126,18.258-17.126"
"c10.357,0,16.844,8.104,16.844,16.635C413.969,310.884,407.557,319.696,396.064,319.696z"
"M404.873,313.987"
"c1.695-2.257,2.119-5.074,2.119-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.326,0-4.652,0.918-6.342,2.399"
"c-2.749,2.465-3.245,5.566-3.245,8.599c0,6.977,3.454,18.463,11.984,18.463C400.436,317.58,403.256,316.242,404.873,313.987z\"/>"
"<path fill=\"#ED174F\""
"d=\"M357.861,319.696c-11.207,0-17.199-8.739-17.199-16.636c0-9.233,7.544-17.126,18.258-17.126"
"c10.359,0,16.845,8.104,16.845,16.635C375.764,310.884,369.351,319.696,357.861,319.696z"
"M366.671,313.987"
"c1.693-2.257,2.116-5.074,2.116-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.325,0-4.652,0.918-6.344,2.399"
"c-2.749,2.465-3.241,5.566-3.241,8.599c0,6.977,3.452,18.463,11.983,18.463C362.234,317.58,365.053,316.242,366.671,313.987z\"/>"
"<path fill=\"#0081C6\""
"d=\"M335.278,318.591l-10.135,2.339c-4.111,0.638-7.795,1.204-11.69,1.204"
"c-19.56,0-26.998-14.386-26.998-25.654c0-13.746,10.558-26.498,28.629-26.498c3.827,0,7.51,0.564,10.839,1.486"
"c5.316,1.488,7.796,3.331,9.355,4.394l-5.883,5.599l-2.479,0.565l1.771-2.837c-2.408-2.336-6.805-6.658-15.164-6.658"
"c-11.196,0-19.63,8.507-19.63,20.906c0,13.319,9.638,25.861,25.084,25.861c4.539,0,6.874-0.918,9-1.771v-11.407l-10.698,0.566"
"l5.667-3.047h15.023l-1.841,1.77c-0.5,0.424-0.567,0.57-0.71,1.133c-0.073,0.64-0.141,2.695-0.141,3.403V318.591z\"/>"
"<path fill=\"#49A942\""
"d=\"M462.908,316.552c-2.342-0.214-2.832-0.638-2.832-3.401v-0.782v-39.327c0.014-0.153,0.025-0.31,0.041-0.457"
"c0.283-2.479,0.992-2.903,3.189-4.182h-10.135l-5.316,2.552h5.418v0.032l-0.004-0.024v41.406v2.341"
"c0,1.416-0.281,1.629-1.912,3.753H463.9l2.623-1.557C465.318,316.763,464.113,316.692,462.908,316.552z\"/>"
"<path fill=\"#ED174F\""
"d=\"M491.742,317.203c-0.771,0.422-1.547,0.916-2.318,1.268c-2.326,1.055-4.719,1.336-6.83,1.336"
"c-2.25,0-5.77-0.143-9.361-2.744c-4.992-3.521-7.176-9.572-7.176-14.851c0-10.906,8.869-16.255,16.115-16.255"
"c2.533,0,5.141,0.633,7.252,1.972c3.516,2.318,4.43,5.344,4.922,6.963l-16.535,6.688l-5.422,0.422"
"c1.758,8.938,7.812,14.145,14.498,14.145c3.59,0,6.193-1.266,8.586-2.461L491.742,317.203z"
"M485.129,296.229"
"c1.336-0.493,2.039-0.914,2.039-1.899c0-2.812-3.166-6.053-6.967-6.053c-2.818,0-8.094,2.183-8.094,9.783"
"c0,1.197,0.141,2.464,0.213,3.73L485.129,296.229z\"/>"
"<path fill=\"#77787B\""
"d=\"M498.535,286.439v4.643h-0.564v-4.643h-1.537v-0.482h3.637v0.482H498.535z\"/>"
"<path fill=\"#77787B\""
"d=\"M504.863,291.082v-4.687h-0.023l-1.432,4.687h-0.439l-1.443-4.687h-0.02v4.687h-0.512v-5.125h0.877"
"l1.307,4.143h0.018l1.285-4.143h0.891v5.125H504.863z\"/>"
;
size_t logoStrLen = sizeof(logoStr);
#if QUADRATIC_APPROXIMATION
////////////////////////////////////////////////////////////////////////////////////
//functions to approximate a cubic using two quadratics
// midPt sets the first argument to be the midpoint of the other two
// it is used by quadApprox
static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b)
{
dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY));
}
// quadApprox - makes an approximation, which we hope is faster
static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
{
//divide the cubic up into two cubics, then convert them into quadratics
//define our points
SkPoint c,j,k,l,m,n,o,p,q, mid;
fPath.getLastPt(&c);
midPt(j, p0, c);
midPt(k, p0, p1);
midPt(l, p1, p2);
midPt(o, j, k);
midPt(p, k, l);
midPt(q, o, p);
//compute the first half
m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY));
n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY));
midPt(mid,m,n);
fPath.quadTo(mid,q);
c = q;
//compute the second half
m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY));
n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY));
midPt(mid,m,n);
fPath.quadTo(mid,p2);
}
#endif
static inline bool is_between(int c, int min, int max)
{
return (unsigned)(c - min) <= (unsigned)(max - min);
}
static inline bool is_ws(int c)
{
return is_between(c, 1, 32);
}
static inline bool is_digit(int c)
{
return is_between(c, '0', '9');
}
static inline bool is_sep(int c)
{
return is_ws(c) || c == ',';
}
static const char* skip_ws(const char str[])
{
SkASSERT(str);
while (is_ws(*str))
str++;
return str;
}
static const char* skip_sep(const char str[])
{
SkASSERT(str);
while (is_sep(*str))
str++;
return str;
}
static const char* find_points(const char str[], SkPoint value[], int count,
bool isRelative, SkPoint* relative)
{
str = SkParse::FindScalars(str, &value[0].fX, count * 2);
if (isRelative) {
for (int index = 0; index < count; index++) {
value[index].fX += relative->fX;
value[index].fY += relative->fY;
}
}
return str;
}
static const char* find_scalar(const char str[], SkScalar* value,
bool isRelative, SkScalar relative)
{
str = SkParse::FindScalar(str, value);
if (isRelative)
*value += relative;
return str;
}
static void showPathContour(SkPath::Iter& iter) {
uint8_t verb;
SkPoint pts[4];
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
SkDebugf("path.moveTo(%1.9gf,%1.9gf);\n", pts[0].fX, pts[0].fY);
continue;
case SkPath::kLine_Verb:
SkDebugf("path.lineTo(%1.9gf,%1.9gf);\n", pts[1].fX, pts[1].fY);
break;
case SkPath::kQuad_Verb:
SkDebugf("path.quadTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
break;
case SkPath::kCubic_Verb:
SkDebugf("path.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
break;
case SkPath::kClose_Verb:
SkDebugf("path.close();\n");
break;
default:
SkDEBUGFAIL("bad verb");
return;
}
}
}
static void showPath(const SkPath& path) {
SkPath::Iter iter(path, true);
int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
if (rectCount > 0) {
SkTDArray<SkRect> rects;
SkTDArray<SkPath::Direction> directions;
rects.setCount(rectCount);
directions.setCount(rectCount);
path.rectContours(rects.begin(), directions.begin());
for (int contour = 0; contour < rectCount; ++contour) {
const SkRect& rect = rects[contour];
SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
}
return;
}
iter.setPath(path, true);
showPathContour(iter);
}
static const char* parsePath(const char* data) {
SkPath fPath;
SkPoint f = {0, 0};
SkPoint c = {0, 0};
SkPoint lastc = {0, 0};
SkPoint points[3];
char op = '\0';
char previousOp = '\0';
bool relative = false;
do {
data = skip_ws(data);
if (data[0] == '\0')
break;
char ch = data[0];
if (is_digit(ch) || ch == '-' || ch == '+') {
if (op == '\0') {
SkASSERT(0);
return 0;
}
}
else {
op = ch;
relative = false;
if (islower(op)) {
op = (char) toupper(op);
relative = true;
}
data++;
data = skip_sep(data);
}
switch (op) {
case 'M':
data = find_points(data, points, 1, relative, &c);
fPath.moveTo(points[0]);
op = 'L';
c = points[0];
break;
case 'L':
data = find_points(data, points, 1, relative, &c);
fPath.lineTo(points[0]);
c = points[0];
break;
case 'H': {
SkScalar x;
data = find_scalar(data, &x, relative, c.fX);
fPath.lineTo(x, c.fY);
c.fX = x;
}
break;
case 'V': {
SkScalar y;
data = find_scalar(data, &y, relative, c.fY);
fPath.lineTo(c.fX, y);
c.fY = y;
}
break;
case 'C':
data = find_points(data, points, 3, relative, &c);
goto cubicCommon;
case 'S':
data = find_points(data, &points[1], 2, relative, &c);
points[0] = c;
if (previousOp == 'C' || previousOp == 'S') {
points[0].fX -= lastc.fX - c.fX;
points[0].fY -= lastc.fY - c.fY;
}
cubicCommon:
// if (data[0] == '\0')
// return;
#if QUADRATIC_APPROXIMATION
quadApprox(fPath, points[0], points[1], points[2]);
#else //this way just does a boring, slow old cubic
fPath.cubicTo(points[0], points[1], points[2]);
#endif
//if we are using the quadApprox, lastc is what it would have been if we had used
//cubicTo
lastc = points[1];
c = points[2];
break;
case 'Q': // Quadratic Bezier Curve
data = find_points(data, points, 2, relative, &c);
goto quadraticCommon;
case 'T':
data = find_points(data, &points[1], 1, relative, &c);
points[0] = points[1];
if (previousOp == 'Q' || previousOp == 'T') {
points[0].fX = c.fX * 2 - lastc.fX;
points[0].fY = c.fY * 2 - lastc.fY;
}
quadraticCommon:
fPath.quadTo(points[0], points[1]);
lastc = points[0];
c = points[1];
break;
case 'Z':
fPath.close();
#if 0 // !!! still a bug?
if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
c.fX -= SkScalar.Epsilon; // !!! enough?
fPath.moveTo(c);
fPath.lineTo(f);
fPath.close();
}
#endif
c = f;
op = '\0';
break;
case '~': {
SkPoint args[2];
data = find_points(data, args, 2, false, NULL);
fPath.moveTo(args[0].fX, args[0].fY);
fPath.lineTo(args[1].fX, args[1].fY);
}
break;
default:
SkASSERT(0);
return 0;
}
if (previousOp == 0)
f = c;
previousOp = op;
} while (data[0] != '"');
showPath(fPath);
return data;
}
const char pathPrefix[] = "<path fill=\"";
void parseSVG();
void parseSVG() {
const char* data = logoStr;
const char* dataEnd = logoStr + logoStrLen - 1;
while (data < dataEnd) {
SkASSERT(strncmp(data, pathPrefix, sizeof(pathPrefix) - 1) == 0);
data += sizeof(pathPrefix) - 1;
SkDebugf("paint.setColor(0xFF%c%c%c%c%c%c);\n", data[1], data[2], data[3], data[4],
data[5], data[6]);
data += 8;
SkASSERT(strncmp(data, "d=\"", 3) == 0);
data += 3;
SkDebugf("path.reset();\n");
data = parsePath(data);
SkDebugf("canvas->drawPath(path, paint);\n");
SkASSERT(strncmp(data, "\"/>", 3) == 0);
data += 3;
}
}

Просмотреть файл

@ -0,0 +1,9 @@
/*
* LogoPlay.h
* shapeops_edge
*
* Created by Cary Clark on 2/6/13.
* Copyright 2013 __MyCompanyName__. All rights reserved.
*
*/

Просмотреть файл

@ -8,11 +8,6 @@
#include "CurveUtilities.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)
@ -31,12 +26,11 @@ void _Rect::setBounds(const Quadratic& quad) {
add(quad[2]);
double tValues[2];
int roots = 0;
if (!isBoundedByEndPoints(quad[0].x, quad[1].x, quad[2].x)) {
if (!between(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]);
if (!between(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;

Просмотреть файл

@ -59,7 +59,8 @@ static int findRoots(const QuadImplicitForm& i, const Quadratic& q2, double root
return quarticRootsReal(t4, t3, t2, t1, t0, roots);
}
static void addValidRoots(const double roots[4], const int count, const int side, Intersections& i) {
static int addValidRoots(const double roots[4], const int count, double valid[4]) {
int result = 0;
int index;
for (index = 0; index < count; ++index) {
if (!approximately_zero_or_more(roots[index]) || !approximately_one_or_less(roots[index])) {
@ -71,8 +72,9 @@ static void addValidRoots(const double roots[4], const int count, const int side
} else if (approximately_greater_than_one(t)) {
t = 1;
}
i.insertOne(t, side);
valid[result++] = t;
}
return result;
}
static bool onlyEndPtsInCommon(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
@ -106,7 +108,7 @@ static bool onlyEndPtsInCommon(const Quadratic& q1, const Quadratic& q2, Interse
for (int i1 = 0; i1 < 3; i1 += 2) {
for (int i2 = 0; i2 < 3; i2 += 2) {
if (q1[i1] == q2[i2]) {
i.insert(i1 >> 1, i2 >> 1);
i.insert(i1 >> 1, i2 >> 1, q1[i1]);
}
}
}
@ -147,10 +149,10 @@ static bool addIntercept(const Quadratic& q1, const Quadratic& q2, double tMin,
}
_Point pt2;
xy_at_t(q1, rootTs.fT[0][0], pt2.x, pt2.y);
if (!pt2.approximatelyEqual(mid)) {
if (!pt2.approximatelyEqualHalf(mid)) {
return false;
}
i.add(rootTs.fT[0][0], tMid);
i.insertSwap(rootTs.fT[0][0], tMid, pt2);
return true;
}
@ -281,11 +283,11 @@ static void relaxedIsLinear(const Quadratic& q1, const Quadratic& q2, Intersecti
Intersections firstI, secondI;
relaxedIsLinear(pair.first(), rounder, firstI);
for (int index = 0; index < firstI.used(); ++index) {
i.insert(firstI.fT[0][index] * 0.5, firstI.fT[1][index]);
i.insert(firstI.fT[0][index] * 0.5, firstI.fT[1][index], firstI.fPt[index]);
}
relaxedIsLinear(pair.second(), rounder, secondI);
for (int index = 0; index < secondI.used(); ++index) {
i.insert(0.5 + secondI.fT[0][index] * 0.5, secondI.fT[1][index]);
i.insert(0.5 + secondI.fT[0][index] * 0.5, secondI.fT[1][index], secondI.fPt[index]);
}
}
if (m2 < m1) {
@ -358,59 +360,60 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
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.addCoincident(t, 0);
i.insertCoincident(t, 0, q2[0]);
}
if ((t = axialIntersect(q1, q2[2], useVertical)) >= 0) {
i.addCoincident(t, 1);
i.insertCoincident(t, 1, q2[2]);
}
useVertical = fabs(q2[0].x - q2[2].x) < fabs(q2[0].y - q2[2].y);
if ((t = axialIntersect(q2, q1[0], useVertical)) >= 0) {
i.addCoincident(0, t);
i.insertCoincident(0, t, q1[0]);
}
if ((t = axialIntersect(q2, q1[2], useVertical)) >= 0) {
i.addCoincident(1, t);
i.insertCoincident(1, t, q1[2]);
}
SkASSERT(i.fCoincidentUsed <= 2);
return i.fCoincidentUsed > 0;
SkASSERT(i.coincidentUsed() <= 2);
return i.coincidentUsed() > 0;
}
double roots1[4], roots2[4];
int index;
bool useCubic = q1[0] == q2[0] || q1[0] == q2[2] || q1[2] == q2[0];
double roots1[4];
int rootCount = findRoots(i2, q1, roots1, useCubic);
// OPTIMIZATION: could short circuit here if all roots are < 0 or > 1
double roots1Copy[4];
int r1Count = addValidRoots(roots1, rootCount, roots1Copy);
_Point pts1[4];
for (index = 0; index < r1Count; ++index) {
xy_at_t(q1, roots1Copy[index], pts1[index].x, pts1[index].y);
}
double roots2[4];
int rootCount2 = findRoots(i1, q2, roots2, useCubic);
addValidRoots(roots1, rootCount, 0, i);
addValidRoots(roots2, rootCount2, 1, i);
if (i.insertBalanced() && i.fUsed <= 1) {
if (i.fUsed == 1) {
_Point xy1, xy2;
xy_at_t(q1, i.fT[0][0], xy1.x, xy1.y);
xy_at_t(q2, i.fT[1][0], xy2.x, xy2.y);
if (!xy1.approximatelyEqual(xy2)) {
--i.fUsed;
--i.fUsed2;
double roots2Copy[4];
int r2Count = addValidRoots(roots2, rootCount2, roots2Copy);
_Point pts2[4];
for (index = 0; index < r2Count; ++index) {
xy_at_t(q2, roots2Copy[index], pts2[index].x, pts2[index].y);
}
if (r1Count == r2Count && r1Count <= 1) {
if (r1Count == 1) {
if (pts1[0].approximatelyEqualHalf(pts2[0])) {
i.insert(roots1Copy[0], roots2Copy[0], pts1[0]);
}
}
return i.intersected();
}
_Point pts[4];
int closest[4];
double dist[4];
int index, ndex2;
for (ndex2 = 0; ndex2 < i.fUsed2; ++ndex2) {
xy_at_t(q2, i.fT[1][ndex2], pts[ndex2].x, pts[ndex2].y);
}
bool foundSomething = false;
for (index = 0; index < i.fUsed; ++index) {
_Point xy;
xy_at_t(q1, i.fT[0][index], xy.x, xy.y);
for (index = 0; index < r1Count; ++index) {
dist[index] = DBL_MAX;
closest[index] = -1;
for (ndex2 = 0; ndex2 < i.fUsed2; ++ndex2) {
if (!pts[ndex2].approximatelyEqual(xy)) {
for (int ndex2 = 0; ndex2 < r2Count; ++ndex2) {
if (!pts2[ndex2].approximatelyEqualHalf(pts1[index])) {
continue;
}
double dx = pts[ndex2].x - xy.x;
double dy = pts[ndex2].y - xy.y;
double dx = pts2[ndex2].x - pts1[index].x;
double dy = pts2[ndex2].y - pts1[index].y;
double distance = dx * dx + dy * dy;
if (dist[index] <= distance) {
continue;
@ -431,18 +434,15 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
;
}
}
if (i.fUsed && i.fUsed2 && !foundSomething) {
if (r1Count && r2Count && !foundSomething) {
relaxedIsLinear(q1, q2, i);
return i.intersected();
}
double roots1Copy[4], roots2Copy[4];
memcpy(roots1Copy, i.fT[0], i.fUsed * sizeof(double));
memcpy(roots2Copy, i.fT[1], i.fUsed2 * sizeof(double));
int used = 0;
do {
double lowest = DBL_MAX;
int lowestIndex = -1;
for (index = 0; index < i.fUsed; ++index) {
for (index = 0; index < r1Count; ++index) {
if (closest[index] < 0) {
continue;
}
@ -454,11 +454,10 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
if (lowestIndex < 0) {
break;
}
i.fT[0][used] = roots1Copy[lowestIndex];
i.fT[1][used] = roots2Copy[closest[lowestIndex]];
i.insert(roots1Copy[lowestIndex], roots2Copy[closest[lowestIndex]],
pts1[lowestIndex]);
closest[lowestIndex] = -1;
} while (++used < i.fUsed);
i.fUsed = i.fUsed2 = used;
} while (++used < r1Count);
i.fFlip = false;
return i.intersected();
}

Просмотреть файл

@ -29,10 +29,8 @@ static void standardTestCases() {
printf("[%d] quad2 order=%d\n", (int) index, order2);
}
if (order1 == 3 && order2 == 3) {
Intersections intersections, intersections2;
intersect(reduce1, reduce2, intersections);
intersect2(reduce1, reduce2, intersections2);
SkASSERT(intersections.used() == intersections2.used());
Intersections intersections;
intersect2(reduce1, reduce2, intersections);
if (intersections.intersected()) {
for (int pt = 0; pt < intersections.used(); ++pt) {
double tt1 = intersections.fT[0][pt];
@ -49,10 +47,6 @@ static void standardTestCases() {
printf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
__FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
}
tt1 = intersections2.fT[0][pt];
SkASSERT(approximately_equal(intersections.fT[0][pt], tt1));
tt2 = intersections2.fT[1][pt];
SkASSERT(approximately_equal(intersections.fT[1][pt], tt2));
}
}
}
@ -60,6 +54,20 @@ static void standardTestCases() {
}
static const Quadratic testSet[] = {
{{0, 0}, {0.51851851851851849, 1.0185185185185186}, {1.2592592592592591, 1.9259259259259258}},
{{1.2592592592592593, 1.9259259259259265}, {0.51851851851851893, 1.0185185185185195}, {0, 0}},
{{1.93281168,2.58856757}, {2.38543691,2.7096125}, {2.51967352,2.34531784}},
{{2.51967352,2.34531784}, {2.65263731,2.00639194}, {3.1212119,1.98608967}},
{{2.09544533,2.51981963}, {2.33331524,2.25252128}, {2.92003302,2.39442311}},
{{0.924337655,1.94072717}, {1.25185043,1.52836494}, {1.71793901,1.06149951}},
{{0.940798831,1.67439357}, {1.25988251,1.39778567}, {1.71791672,1.06650313}},
{{0.924337655,1.94072717}, {1.39158994,1.32418496}, {2.14967426,0.687365435}},
{{0.940798831,1.67439357}, {1.48941875,1.16280321}, {2.47884711,0.60465921}},
{{1.7465749139282332,1.9930452039527999}, {1.8320006564080331,1.859481345189089}, {1.8731035127758437,1.6344055934266613}},
{{1.8731035127758437,1.6344055934266613}, {1.89928170345231,1.5006405518943067}, {1.9223833226085514,1.3495796165215643}},
{{1.74657491,1.9930452}, {1.87407679,1.76762853}, {1.92238332,1.34957962}},
@ -149,8 +157,6 @@ static const Quadratic testSet[] = {
const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
#define ONE_OFF_DEBUG 1
static void oneOffTest1(size_t outer, size_t inner) {
const Quadratic& quad1 = testSet[outer];
const Quadratic& quad2 = testSet[inner];
@ -186,10 +192,7 @@ static void oneOffTest1(size_t outer, size_t inner) {
}
void QuadraticIntersection_OneOffTest() {
oneOffTest1(0, 3);
oneOffTest1(0, 4);
oneOffTest1(1, 3);
oneOffTest1(1, 4);
oneOffTest1(0, 1);
}
static void oneOffTests() {
@ -216,6 +219,7 @@ static void coincidentTest() {
Intersections intersections2;
intersect2(quad1, quad2, intersections2);
SkASSERT(intersections2.coincidentUsed() == 2);
SkASSERT(intersections2.used() == 2);
for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
double tt1 = intersections2.fT[0][pt];
double tt2 = intersections2.fT[1][pt];
@ -268,12 +272,12 @@ static void pointFinder(const Quadratic& q1, const Quadratic& q2) {
static void hullIntersect(const Quadratic& q1, const Quadratic& q2) {
SkDebugf("%s", __FUNCTION__);
double aRange[2], bRange[2];
Intersections ts;
for (int i1 = 0; i1 < 3; ++i1) {
_Line l1 = {q1[i1], q1[(i1 + 1) % 3]};
for (int i2 = 0; i2 < 3; ++i2) {
_Line l2 = {q2[i2], q2[(i2 + 1) % 3]};
if (intersect(l1, l2, aRange, bRange)) {
if (intersect(l1, l2, ts)) {
SkDebugf(" [%d,%d]", i1, i2);
}
}

Просмотреть файл

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "CubicUtilities.h"
#include "Extrema.h"
#include "QuadraticUtilities.h"
#include "TriangleUtilities.h"
@ -45,6 +46,27 @@ bool point_in_hull(const Quadratic& quad, const _Point& pt) {
return pointInTriangle((const Triangle&) quad, pt);
}
_Point top(const Quadratic& quad, double startT, double endT) {
Quadratic sub;
sub_divide(quad, startT, endT, sub);
_Point topPt = sub[0];
if (topPt.y > sub[2].y || (topPt.y == sub[2].y && topPt.x > sub[2].x)) {
topPt = sub[2];
}
if (!between(sub[0].y, sub[1].y, sub[2].y)) {
double extremeT;
if (findExtrema(sub[0].y, sub[1].y, sub[2].y, &extremeT)) {
extremeT = startT + (endT - startT) * extremeT;
_Point test;
xy_at_t(quad, extremeT, test.x, test.y);
if (topPt.y > test.y || (topPt.y == test.y && topPt.x > test.x)) {
topPt = test;
}
}
}
return topPt;
}
/*
Numeric Solutions (5.6) suggests to solve the quadratic by computing
Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))

Просмотреть файл

@ -36,6 +36,7 @@ inline void set_abc(const double* quad, double& a, double& b, double& c) {
int quadraticRootsReal(double A, double B, double C, double t[2]);
int quadraticRootsValidT(const double A, const double B, const double C, double s[2]);
void sub_divide(const Quadratic& src, double t1, double t2, Quadratic& dst);
_Point top(const Quadratic& , double startT, double endT);
void xy_at_t(const Quadratic& , double t, double& x, double& y);
#endif

Просмотреть файл

@ -31,6 +31,7 @@ int gDebugMaxWindValue = SK_MaxS32;
#define APPROXIMATE_CUBICS 1
#define DEBUG_UNUSED 0 // set to expose unused functions
#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
#if FORCE_RELEASE || defined SK_RELEASE
@ -109,7 +110,7 @@ static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
Intersections& intersections) {
MAKE_CONST_LINE(aLine, a);
MAKE_CONST_LINE(bLine, b);
return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]);
return intersect(aLine, bLine, intersections);
}
static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
@ -136,7 +137,7 @@ static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
#else
intersect(aQuad, bQuad, intersections);
#endif
return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
return intersections.fUsed;
}
#if APPROXIMATE_CUBICS
@ -152,11 +153,11 @@ static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections&
MAKE_CONST_CUBIC(aCubic, a);
MAKE_CONST_CUBIC(bCubic, b);
#if APPROXIMATE_CUBICS
intersect2(aCubic, bCubic, intersections);
intersect3(aCubic, bCubic, intersections);
#else
intersect(aCubic, bCubic, intersections);
#endif
return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
return intersections.fUsed;
}
static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
@ -366,6 +367,31 @@ static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = {
CubicDYAtT
};
static SkPoint LineDXDYAtT(const SkPoint a[2], double ) {
return a[1] - a[0];
}
static SkPoint QuadDXDYAtT(const SkPoint a[3], double t) {
MAKE_CONST_QUAD(quad, a);
_Point pt;
dxdy_at_t(quad, t, pt);
return pt.asSkPoint();
}
static SkPoint CubicDXDYAtT(const SkPoint a[4], double t) {
MAKE_CONST_CUBIC(cubic, a);
_Point pt;
dxdy_at_t(cubic, t, pt);
return pt.asSkPoint();
}
static SkPoint (* const SegmentDXDYAtT[])(const SkPoint [], double ) = {
NULL,
LineDXDYAtT,
QuadDXDYAtT,
CubicDXDYAtT
};
static void LineSubDivide(const SkPoint a[2], double startT, double endT,
SkPoint sub[2]) {
MAKE_CONST_LINE(aLine, a);
@ -428,6 +454,25 @@ static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cub
sub_divide(aCubic, startT, endT, dst);
}
static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) {
MAKE_CONST_QUAD(quad, a);
_Point topPt = top(quad, startT, endT);
return topPt.asSkPoint();
}
static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) {
MAKE_CONST_CUBIC(cubic, a);
_Point topPt = top(cubic, startT, endT);
return topPt.asSkPoint();
}
static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = {
NULL,
NULL,
QuadTop,
CubicTop
};
#if DEBUG_UNUSED
static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
SkRect& bounds) {
@ -819,7 +864,7 @@ public:
nextC = 3;
#if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
if (dx() == 0 && dy() == 0) {
SkDebugf("*** %s cubic is line\n");
SkDebugf("*** %s cubic is line\n", __FUNCTION__);
fTangent1.cubicEndPoints(fCurvePart, 0, 3);
}
#endif
@ -1261,31 +1306,50 @@ public:
return false;
}
void activeLeftTop(SkPoint& result) const {
SkPoint activeLeftTop(bool onlySortable, int* firstT) const {
SkASSERT(!done());
SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
int count = fTs.count();
result.fX = result.fY = SK_ScalarMax;
// see if either end is not done since we want smaller Y of the pair
bool lastDone = true;
bool lastUnsortable = false;
double lastT = -1;
for (int index = 0; index < count; ++index) {
const Span& span = fTs[index];
if (span.fUnsortableStart | lastUnsortable) {
if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
goto next;
}
if (!span.fDone | !lastDone) {
const SkPoint& xy = xyAtT(index);
if (result.fY < xy.fY) {
goto next;
if (span.fDone && lastDone) {
goto next;
}
if (approximately_negative(span.fT - lastT)) {
goto next;
}
{
const SkPoint& xy = xyAtT(&span);
if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
topPt = xy;
if (firstT) {
*firstT = index;
}
}
if (result.fY == xy.fY && result.fX < xy.fX) {
goto next;
if (fVerb != SkPath::kLine_Verb && !lastDone) {
SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT);
if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
&& topPt.fX > curveTop.fX)) {
topPt = curveTop;
if (firstT) {
*firstT = index;
}
}
}
result = xy;
lastT = span.fT;
}
next:
lastDone = span.fDone;
lastUnsortable = span.fUnsortableEnd;
}
return topPt;
}
bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
@ -1397,7 +1461,8 @@ public:
fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
xyAtT(tIndexStart).fY);
#endif
addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false);
addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false,
fTs[tIndexStart].fPt);
}
if (nextT < 1 && fTs[tIndex].fWindValue) {
#if DEBUG_CONCIDENT
@ -1406,7 +1471,7 @@ public:
fTs[tIndex].fT, xyAtT(tIndex).fX,
xyAtT(tIndex).fY);
#endif
addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false);
addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt);
}
} else {
SkASSERT(!other.fTs[oIndexStart].fWindValue);
@ -1443,11 +1508,12 @@ public:
do {
++tIndex;
} while (!approximately_negative(tStart - fTs[tIndex].fT));
SkPoint ptStart = fTs[tIndex].fPt;
do {
++oIndex;
} while (!approximately_negative(oStart - other.fTs[oIndex].fT));
if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) {
addTPair(tStart, other, oStart, false);
addTPair(tStart, other, oStart, false, ptStart);
}
tStart = fTs[tIndex].fT;
oStart = other.fTs[oIndex].fT;
@ -1457,6 +1523,7 @@ public:
nextT = fTs[++tIndex].fT;
} while (approximately_negative(nextT - tStart));
tStart = nextT;
ptStart = fTs[tIndex].fPt;
do {
nextT = other.fTs[++oIndex].fT;
} while (approximately_negative(nextT - oStart));
@ -1464,7 +1531,7 @@ public:
if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) {
break;
}
addTPair(tStart, other, oStart, false);
addTPair(tStart, other, oStart, false, ptStart);
} while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart));
}
@ -1563,7 +1630,7 @@ public:
// resolve overlapping ts when considering coincidence later
// add non-coincident intersection. Resulting edges are sorted in T.
int addT(double newT, Segment* other) {
int addT(double newT, Segment* other, const SkPoint& pt) {
// FIXME: in the pathological case where there is a ton of intercepts,
// binary search?
int insertedAt = -1;
@ -1597,7 +1664,7 @@ public:
}
span->fT = newT;
span->fOther = other;
span->fPt.fX = SK_ScalarNaN;
span->fPt = pt;
span->fWindSum = SK_MinS32;
span->fOppSum = SK_MinS32;
span->fWindValue = 1;
@ -1733,8 +1800,8 @@ public:
}
}
int addUnsortableT(double newT, Segment* other, bool start) {
int result = addT(newT, other);
int addUnsortableT(double newT, Segment* other, bool start, const SkPoint& pt) {
int result = addT(newT, other, pt);
Span* span = &fTs[result];
if (start) {
if (result > 0) {
@ -1838,7 +1905,7 @@ public:
// FIXME: this doesn't prevent the same span from being added twice
// fix in caller, SkASSERT here?
void addTPair(double t, Segment& other, double otherT, bool borrowWind) {
void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) {
int tCount = fTs.count();
for (int tIndex = 0; tIndex < tCount; ++tIndex) {
const Span& span = fTs[tIndex];
@ -1858,8 +1925,8 @@ public:
SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
__FUNCTION__, fID, t, other.fID, otherT);
#endif
int insertedAt = addT(t, &other);
int otherInsertedAt = other.addT(otherT, this);
int insertedAt = addT(t, &other, pt);
int otherInsertedAt = other.addT(otherT, this, pt);
addOtherT(insertedAt, otherT, otherInsertedAt);
other.addOtherT(otherInsertedAt, t, insertedAt);
matchWindingValue(insertedAt, t, borrowWind);
@ -2188,6 +2255,14 @@ public:
bool done(const Angle* angle) const {
return done(SkMin32(angle->start(), angle->end()));
}
SkPoint dxdy(int index) const {
return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT);
}
SkScalar dy(int index) const {
return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT);
}
bool equalPoints(int greaterTIndex, int lesserTIndex) {
SkASSERT(greaterTIndex >= lesserTIndex);
@ -2696,8 +2771,7 @@ public:
}
}
// start here;
// either:
// FIXME: either:
// a) mark spans with either end unsortable as done, or
// b) rewrite findTop / findTopSegment / findTopContour to iterate further
// when encountering an unsortable span
@ -2710,29 +2784,7 @@ public:
// topmost tangent from y-min to first pt is closer to horizontal
SkASSERT(!done());
int firstT = -1;
SkPoint topPt;
topPt.fY = SK_ScalarMax;
int count = fTs.count();
// see if either end is not done since we want smaller Y of the pair
bool lastDone = true;
bool lastUnsortable = false;
for (int index = 0; index < count; ++index) {
const Span& span = fTs[index];
if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
goto next;
}
if (!span.fDone | !lastDone) {
const SkPoint& intercept = xyAtT(&span);
if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY
&& topPt.fX > intercept.fX)) {
topPt = intercept;
firstT = index;
}
}
next:
lastDone = span.fDone;
lastUnsortable = span.fUnsortableEnd;
}
SkPoint topPt = activeLeftTop(onlySortable, &firstT);
SkASSERT(firstT >= 0);
// sort the edges to find the leftmost
int step = 1;
@ -2767,6 +2819,13 @@ public:
tIndex = angle->end();
endIndex = angle->start();
} while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
if (leftSegment->verb() >= SkPath::kQuad_Verb) {
SkScalar dyE = leftSegment->dy(endIndex);
SkScalar dyS = leftSegment->dy(tIndex);
if (dyE < 0 && dyS > 0) {
SkTSwap(tIndex, endIndex);
}
}
SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny);
return leftSegment;
}
@ -4152,6 +4211,7 @@ struct Coincidence {
Contour* fContours[2];
int fSegments[2];
double fTs[2][2];
SkPoint fPts[2];
};
class Contour {
@ -4176,20 +4236,12 @@ public:
coincidence.fContours[1] = other;
coincidence.fSegments[0] = index;
coincidence.fSegments[1] = otherIndex;
if (fSegments[index].verb() == SkPath::kLine_Verb &&
other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) {
// FIXME: coincident lines use legacy Ts instead of coincident Ts
coincidence.fTs[swap][0] = ts.fT[0][0];
coincidence.fTs[swap][1] = ts.fT[0][1];
coincidence.fTs[!swap][0] = ts.fT[1][0];
coincidence.fTs[!swap][1] = ts.fT[1][1];
} else if (fSegments[index].verb() >= SkPath::kQuad_Verb &&
other->fSegments[otherIndex].verb() >= SkPath::kQuad_Verb) {
coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1];
}
coincidence.fTs[swap][0] = ts.fT[0][0];
coincidence.fTs[swap][1] = ts.fT[0][1];
coincidence.fTs[!swap][0] = ts.fT[1][0];
coincidence.fTs[!swap][1] = ts.fT[1][1];
coincidence.fPts[0] = ts.fPt[0].asSkPoint();
coincidence.fPts[1] = ts.fPt[1].asSkPoint();
}
void addCross(const Contour* crosser) {
@ -4221,13 +4273,14 @@ public:
return fSegments.count();
}
int addT(int segIndex, double newT, Contour* other, int otherIndex) {
int addT(int segIndex, double newT, Contour* other, int otherIndex, const SkPoint& pt) {
containsIntercepts();
return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]);
return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex], pt);
}
int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start) {
return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start);
int addUnsortableT(int segIndex, double newT, Contour* other, int otherIndex, bool start,
const SkPoint& pt) {
return fSegments[segIndex].addUnsortableT(newT, &other->fSegments[otherIndex], start, pt);
}
const Bounds& bounds() const {
@ -4340,11 +4393,11 @@ public:
// make sure startT and endT have t entries
if (startT > 0 || oEndT < 1
|| thisOne.isMissing(startT) || other.isMissing(oEndT)) {
thisOne.addTPair(startT, other, oEndT, true);
thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
}
if (oStartT > 0 || endT < 1
|| thisOne.isMissing(endT) || other.isMissing(oStartT)) {
other.addTPair(oStartT, thisOne, endT, true);
other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
}
if (!thisOne.done() && !other.done()) {
thisOne.addTCancel(startT, endT, other, oStartT, oEndT);
@ -4352,11 +4405,11 @@ public:
} else {
if (startT > 0 || oStartT > 0
|| thisOne.isMissing(startT) || other.isMissing(oStartT)) {
thisOne.addTPair(startT, other, oStartT, true);
thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
}
if (endT < 1 || oEndT < 1
|| thisOne.isMissing(endT) || other.isMissing(oEndT)) {
other.addTPair(oEndT, thisOne, endT, true);
other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
}
if (!thisOne.done() && !other.done()) {
thisOne.addTCoincident(startT, endT, other, oStartT, oEndT);
@ -4411,20 +4464,20 @@ public:
// make sure startT and endT have t entries
if (startT > 0 || oEndT < 1
|| thisOne.isMissing(startT) || other.isMissing(oEndT)) {
thisOne.addTPair(startT, other, oEndT, true);
thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]);
}
if (oStartT > 0 || endT < 1
|| thisOne.isMissing(endT) || other.isMissing(oStartT)) {
other.addTPair(oStartT, thisOne, endT, true);
other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]);
}
} else {
if (startT > 0 || oStartT > 0
|| thisOne.isMissing(startT) || other.isMissing(oStartT)) {
thisOne.addTPair(startT, other, oStartT, true);
thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]);
}
if (endT < 1 || oEndT < 1
|| thisOne.isMissing(endT) || other.isMissing(oEndT)) {
other.addTPair(oEndT, thisOne, endT, true);
other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]);
}
}
#if DEBUG_CONCIDENT
@ -4554,8 +4607,7 @@ public:
continue;
}
fDone = false;
SkPoint testXY;
testSegment->activeLeftTop(testXY);
SkPoint testXY = testSegment->activeLeftTop(true, NULL);
if (topStart) {
if (testXY.fY < topLeft.fY) {
continue;
@ -4908,12 +4960,12 @@ public:
// be nearly equal, any problems caused by this should be taken care
// of later.
// On the edge or out of range values are negative; add 2 to get end
int addT(double newT, const Work& other) {
return fContour->addT(fIndex, newT, other.fContour, other.fIndex);
int addT(double newT, const Work& other, const SkPoint& pt) {
return fContour->addT(fIndex, newT, other.fContour, other.fIndex, pt);
}
int addUnsortableT(double newT, const Work& other, bool start) {
return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start);
int addUnsortableT(double newT, const Work& other, bool start, const SkPoint& pt) {
return fContour->addUnsortableT(fIndex, newT, other.fContour, other.fIndex, start, pt);
}
bool advance() {
@ -5031,9 +5083,9 @@ protected:
};
#if DEBUG_ADD_INTERSECTING_TS
static void debugShowLineIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
return;
static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn,
const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n",
__FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY,
@ -5041,27 +5093,24 @@ static void debugShowLineIntersection(int pts, const Work& wt,
wn.pts()[1].fX, wn.pts()[1].fY);
return;
}
SkPoint wtOutPt, wnOutPt;
LineXYAtT(wt.pts(), wtTs[0], &wtOutPt);
LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY);
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
wt.pts()[1].fX, wt.pts()[1].fY, i.fPt[0].x, i.fPt[0].y);
if (pts == 2) {
SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", i.fT[0][1], i.fPt[1].x, i.fPt[1].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY);
if (pts == 2) {
SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
SkDebugf(" wnTs[1]=%1.9g", i.fT[1][1]);
}
SkDebugf("\n");
}
static void debugShowQuadLineIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
const Work& wn, const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
" (%1.9g,%1.9g %1.9g,%1.9g)\n",
@ -5070,31 +5119,25 @@ static void debugShowQuadLineIntersection(int pts, const Work& wt,
wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
return;
}
SkPoint wtOutPt, wnOutPt;
QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
wtOutPt.fX, wtOutPt.fY);
if (pts == 2) {
QuadXYAtT(wt.pts(), wtTs[1], &wtOutPt);
SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
i.fPt[0].x, i.fPt[0].y);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index],
i.fPt[index].x, i.fPt[index].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY);
if (pts == 2) {
LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)", i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
}
SkDebugf("\n");
}
// FIXME: show more than two intersection points
static void debugShowQuadIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
const Work& wn, const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
" (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
@ -5104,29 +5147,26 @@ static void debugShowQuadIntersection(int pts, const Work& wt,
wn.pts()[2].fX, wn.pts()[2].fY );
return;
}
SkPoint wtOutPt, wnOutPt;
QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt);
QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY,
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", __FUNCTION__,
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY,
wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY,
wtOutPt.fX, wtOutPt.fY);
if (pts == 2) {
SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
i.fPt[0].x, i.fPt[0].y);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
i.fPt[index].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY,
wnOutPt.fX, wnOutPt.fY);
if (pts == 2) {
SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY,
wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
}
SkDebugf("\n");
}
static void debugShowCubicLineIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
const Work& wn, const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
" (%1.9g,%1.9g %1.9g,%1.9g)\n",
@ -5135,31 +5175,27 @@ static void debugShowCubicLineIntersection(int pts, const Work& wt,
wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
return;
}
SkPoint wtOutPt, wnOutPt;
CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
LineXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
wtOutPt.fX, wtOutPt.fY);
if (pts == 2) {
CubicXYAtT(wt.pts(), wtTs[1], &wtOutPt);
SkDebugf(" wtTs[1]=%1.9g (%1.9g,%1.9g)", wtTs[1], wtOutPt.fX, wtOutPt.fY);
i.fPt[0].x, i.fPt[0].y);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
i.fPt[index].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wtTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
wnOutPt.fX, wnOutPt.fY);
if (pts == 2) {
LineXYAtT(wn.pts(), wnTs[1], &wnOutPt);
SkDebugf(" wnTs[1]=%1.9g (%1.9g,%1.9g)", wnTs[1], wnOutPt.fX, wnOutPt.fY);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g)",
i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
}
SkDebugf("\n");
}
// FIXME: show more than two intersection points
static void debugShowCubicQuadIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
const Work& wn, const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
" (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
@ -5169,30 +5205,28 @@ static void debugShowCubicQuadIntersection(int pts, const Work& wt,
wn.pts()[2].fX, wn.pts()[2].fY );
return;
}
SkPoint wtOutPt, wnOutPt;
CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
wtOutPt.fX, wtOutPt.fY);
if (pts == 2) {
SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
i.fPt[0].x, i.fPt[0].y);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
i.fPt[index].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
wn.pts()[2].fX, wn.pts()[2].fY,
wnOutPt.fX, wnOutPt.fY);
if (pts == 2) {
SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
wn.pts()[2].fX, wn.pts()[2].fY);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[1][index]);
}
SkDebugf("\n");
}
// FIXME: show more than two intersection points
static void debugShowCubicIntersection(int pts, const Work& wt,
const Work& wn, const double wtTs[2], const double wnTs[2]) {
const Work& wn, const Intersections& i) {
SkASSERT(i.used() == pts);
if (!pts) {
SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)"
" (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n",
@ -5202,50 +5236,43 @@ static void debugShowCubicIntersection(int pts, const Work& wt,
wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY );
return;
}
SkPoint wtOutPt, wnOutPt;
CubicXYAtT(wt.pts(), wtTs[0], &wtOutPt);
CubicXYAtT(wn.pts(), wnTs[0], &wnOutPt);
SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
__FUNCTION__,
wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
i.fT[0][0], wt.pts()[0].fX, wt.pts()[0].fY, wt.pts()[1].fX, wt.pts()[1].fY,
wt.pts()[2].fX, wt.pts()[2].fY, wt.pts()[3].fX, wt.pts()[3].fY,
wtOutPt.fX, wtOutPt.fY);
if (pts == 2) {
SkDebugf(" wtTs[1]=%1.9g", wtTs[1]);
i.fPt[0].x, i.fPt[0].y);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wtTs[%d]=%1.9g (%1.9g,%1.9g)", index, i.fT[0][index], i.fPt[index].x,
i.fPt[index].y);
}
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)",
wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY,
wnOutPt.fX, wnOutPt.fY);
if (pts == 2) {
SkDebugf(" wnTs[1]=%1.9g", wnTs[1]);
SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)",
i.fT[1][0], wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY,
wn.pts()[2].fX, wn.pts()[2].fY, wn.pts()[3].fX, wn.pts()[3].fY);
for (int index = 1; index < pts; ++index) {
SkDebugf(" wnTs[%d]=%1.9g", index, i.fT[0][index]);
}
SkDebugf("\n");
}
#else
static void debugShowLineIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) {
}
static void debugShowQuadLineIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) {
}
static void debugShowQuadIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) {
}
static void debugShowCubicLineIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowCubicLineIntersection(int , const Work& , const Work& ,
const Intersections& ) {
}
static void debugShowCubicQuadIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowCubicQuadIntersection(int , const Work& , const Work& ,
const Intersections& ) {
}
static void debugShowCubicIntersection(int , const Work& ,
const Work& , const double [2], const double [2]) {
static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) {
}
#endif
@ -5284,8 +5311,7 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kLine_Segment: {
pts = HLineIntersect(wn.pts(), wt.left(),
wt.right(), wt.y(), wt.xFlipped(), ts);
debugShowLineIntersection(pts, wt, wn,
ts.fT[1], ts.fT[0]);
debugShowLineIntersection(pts, wt, wn, ts);
break;
}
case Work::kQuad_Segment: {
@ -5296,7 +5322,7 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kCubic_Segment: {
pts = HCubicIntersect(wn.pts(), wt.left(),
wt.right(), wt.y(), wt.xFlipped(), ts);
debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
debugShowCubicLineIntersection(pts, wn, wt, ts);
break;
}
default:
@ -5311,8 +5337,7 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kLine_Segment: {
pts = VLineIntersect(wn.pts(), wt.top(),
wt.bottom(), wt.x(), wt.yFlipped(), ts);
debugShowLineIntersection(pts, wt, wn,
ts.fT[1], ts.fT[0]);
debugShowLineIntersection(pts, wt, wn, ts);
break;
}
case Work::kQuad_Segment: {
@ -5323,7 +5348,7 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kCubic_Segment: {
pts = VCubicIntersect(wn.pts(), wt.top(),
wt.bottom(), wt.x(), wt.yFlipped(), ts);
debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
debugShowCubicLineIntersection(pts, wn, wt, ts);
break;
}
default:
@ -5335,32 +5360,28 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kHorizontalLine_Segment:
pts = HLineIntersect(wt.pts(), wn.left(),
wn.right(), wn.y(), wn.xFlipped(), ts);
debugShowLineIntersection(pts, wt, wn,
ts.fT[1], ts.fT[0]);
debugShowLineIntersection(pts, wt, wn, ts);
break;
case Work::kVerticalLine_Segment:
pts = VLineIntersect(wt.pts(), wn.top(),
wn.bottom(), wn.x(), wn.yFlipped(), ts);
debugShowLineIntersection(pts, wt, wn,
ts.fT[1], ts.fT[0]);
debugShowLineIntersection(pts, wt, wn, ts);
break;
case Work::kLine_Segment: {
pts = LineIntersect(wt.pts(), wn.pts(), ts);
debugShowLineIntersection(pts, wt, wn,
ts.fT[1], ts.fT[0]);
debugShowLineIntersection(pts, wt, wn, ts);
break;
}
case Work::kQuad_Segment: {
swap = true;
pts = QuadLineIntersect(wn.pts(), wt.pts(), ts);
debugShowQuadLineIntersection(pts, wn, wt,
ts.fT[0], ts.fT[1]);
debugShowQuadLineIntersection(pts, wn, wt, ts);
break;
}
case Work::kCubic_Segment: {
swap = true;
pts = CubicLineIntersect(wn.pts(), wt.pts(), ts);
debugShowCubicLineIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
debugShowCubicLineIntersection(pts, wn, wt, ts);
break;
}
default:
@ -5379,25 +5400,23 @@ static bool addIntersectTs(Contour* test, Contour* next) {
break;
case Work::kLine_Segment: {
pts = QuadLineIntersect(wt.pts(), wn.pts(), ts);
debugShowQuadLineIntersection(pts, wt, wn,
ts.fT[0], ts.fT[1]);
debugShowQuadLineIntersection(pts, wt, wn, ts);
break;
}
case Work::kQuad_Segment: {
pts = QuadIntersect(wt.pts(), wn.pts(), ts);
debugShowQuadIntersection(pts, wt, wn,
ts.fT[0], ts.fT[1]);
debugShowQuadIntersection(pts, wt, wn, ts);
break;
}
case Work::kCubic_Segment: {
#if APPROXIMATE_CUBICS
swap = true;
pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts);
debugShowCubicQuadIntersection(pts, wn, wt, ts.fT[0], ts.fT[1]);
debugShowCubicQuadIntersection(pts, wn, wt, ts);
#else
wt.promoteToCubic();
pts = CubicIntersect(wt.cubic(), wn.pts(), ts);
debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicIntersection(pts, wt, wn, ts);
#endif
break;
}
@ -5410,31 +5429,32 @@ static bool addIntersectTs(Contour* test, Contour* next) {
case Work::kHorizontalLine_Segment:
pts = HCubicIntersect(wt.pts(), wn.left(),
wn.right(), wn.y(), wn.xFlipped(), ts);
debugShowCubicLineIntersection(pts, wt, wn, ts);
break;
case Work::kVerticalLine_Segment:
pts = VCubicIntersect(wt.pts(), wn.top(),
wn.bottom(), wn.x(), wn.yFlipped(), ts);
debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicLineIntersection(pts, wt, wn, ts);
break;
case Work::kLine_Segment: {
pts = CubicLineIntersect(wt.pts(), wn.pts(), ts);
debugShowCubicLineIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicLineIntersection(pts, wt, wn, ts);
break;
}
case Work::kQuad_Segment: {
#if APPROXIMATE_CUBICS
pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts);
debugShowCubicQuadIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicQuadIntersection(pts, wt, wn, ts);
#else
wn.promoteToCubic();
pts = CubicIntersect(wt.pts(), wn.cubic(), ts);
debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicIntersection(pts, wt, wn, ts);
#endif
break;
}
case Work::kCubic_Segment: {
pts = CubicIntersect(wt.pts(), wn.pts(), ts);
debugShowCubicIntersection(pts, wt, wn, ts.fT[0], ts.fT[1]);
debugShowCubicIntersection(pts, wt, wn, ts);
break;
}
default:
@ -5455,9 +5475,10 @@ static bool addIntersectTs(Contour* test, Contour* next) {
for (int pt = 0; pt < ts.used(); ++pt) {
// FIXME: if unsortable, the other points to the original. This logic is
// untested downstream.
int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start);
SkPoint point = ts.fPt[pt].asSkPoint();
int testTAt = wt.addUnsortableT(ts.fT[swap][pt], wt, start, point);
wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt);
testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip);
testTAt = wn.addUnsortableT(ts.fT[!swap][pt], wn, start ^ ts.fFlip, point);
wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt);
start ^= true;
}
@ -5471,7 +5492,8 @@ static bool addIntersectTs(Contour* test, Contour* next) {
}
if (wn.segmentType() >= Work::kQuad_Segment
&& wt.segmentType() >= Work::kQuad_Segment
&& ts.coincidentUsed() == 2) {
&& ts.fIsCoincident[0]) {
SkASSERT(ts.coincidentUsed() == 2);
wt.addCoincident(wn, ts, swap);
continue;
}
@ -5480,8 +5502,9 @@ static bool addIntersectTs(Contour* test, Contour* next) {
for (int pt = 0; pt < pts; ++pt) {
SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
int testTAt = wt.addT(ts.fT[swap][pt], wn);
int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
SkPoint point = ts.fPt[pt].asSkPoint();
int testTAt = wt.addT(ts.fT[swap][pt], wn, point);
int nextTAt = wn.addT(ts.fT[!swap][pt], wt, point);
wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
}

Просмотреть файл

@ -3629,12 +3629,160 @@ static void cubicOp7d() {
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp8d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,5, 1,0, 4,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,4, 1,0, 5,0);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp9d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,6, 1,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,2, 1,0, 6,1);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void quadOp9d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.quadTo(1,6, 1.5f,1);
path.quadTo(1.5f,0.5f, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.quadTo(1,2, 1.4f,1);
pathB.quadTo(3,0.4f, 6,1);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void lineOp9d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.lineTo(1,6);
path.lineTo(1.5f,1);
path.lineTo(1.8f,0.8f);
path.lineTo(2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.lineTo(1,2);
pathB.lineTo(1.4f,1);
pathB.lineTo(3,0.4f);
pathB.lineTo(6,1);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp1i() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,2, 1,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,2, 1,0, 2,1);
pathB.close();
testShapeOp(path, pathB, kIntersect_Op);
}
static void cubicOp10d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,3, 1,0, 4,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,4, 1,0, 3,1);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp11d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(3,4, 1,0, 5,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,5, 1,0, 4,3);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp12d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,6, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 1,0, 6,1);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp13d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(4,5, 1,0, 5,3);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(3,5, 1,0, 5,4);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp14d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,2, 2,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,2);
pathB.cubicTo(1,2, 1,0, 2,0);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void (*firstTest)() = 0;
static struct {
void (*fun)();
const char* str;
} tests[] = {
TEST(cubicOp14d),
TEST(cubicOp13d),
TEST(cubicOp12d),
TEST(cubicOp11d),
TEST(cubicOp10d),
TEST(cubicOp1i),
TEST(cubicOp9d),
TEST(quadOp9d),
TEST(lineOp9d),
TEST(cubicOp8d),
TEST(cubicOp7d),
TEST(cubicOp6d),
TEST(cubicOp5d),
@ -4162,11 +4310,11 @@ static struct {
static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
static void (*firstBinaryTest)() = testOp8d;
static void (*firstBinaryTest)() = 0;
static bool skipAll = false;
static bool runBinaryTestsFirst = false;
static bool runReverse = false;
static bool runReverse = true;
static void (*stopTest)() = 0;
void SimplifyNew_Test() {

Просмотреть файл

@ -300,6 +300,17 @@ path.close();
testSimplifyx(path);
</div>
<div id="testLine5">
path.moveTo(3,0);
path.lineTo(6,2);
path.lineTo(0,2);
path.close();
path.moveTo(3,0);
path.lineTo(6,2);
path.lineTo(0,2);
path.close();
</div>
<div id="testLine6">
SkPath path, simple;
path.moveTo(0,0);
@ -3405,11 +3416,139 @@ path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction);
pathB.close();
</div>
<div id="cubicOp8d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,5, 1,0, 4,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,4, 1,0, 5,0);
pathB.close();
</div>
<div id="cubicOp9d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,6, 1,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,2, 1,0, 6,1);
pathB.close();
</div>
<div id="quadOp9d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.quadTo(1,6, 1.5f,1);
path.quadTo(1.5f,0.8f, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.quadTo(1,2, 1.4f,1);
pathB.quadTo(3,0.4f, 6,1);
pathB.close();
</div>
<div id="lineOp9d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.lineTo(1,6);
path.lineTo(1.5f,1);
path.lineTo(1.8f,0.8f);
path.lineTo(2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.lineTo(1,2);
pathB.lineTo(1.4f,1);
pathB.lineTo(3,0.4f);
pathB.lineTo(6,1);
pathB.close();
</div>
<div id="cubicOp1i">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,2, 1,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,2, 1,0, 2,1);
pathB.close();
</div>
<div id="cubicOp10d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,3, 1,0, 4,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,4, 1,0, 3,1);
pathB.close();
</div>
<div id="cubicOp11d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(3,4, 1,0, 5,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(1,5, 1,0, 4,3);
pathB.close();
</div>
<div id="cubicOp12d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(1,6, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 1,0, 6,1);
pathB.close();
</div>
<div id="cubicOp13d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(4,5, 1,0, 5,3);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(3,5, 1,0, 5,4);
pathB.close();
</div>
<div id="cubicOp14d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,2, 2,0, 2,1);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,2);
pathB.cubicTo(1,2, 1,0, 2,0);
pathB.close();
</div>
</div>
<script type="text/javascript">
var testDivs = [
cubicOp14d,
cubicOp13d,
cubicOp12d,
cubicOp11d,
cubicOp10d,
cubicOp1i,
lineOp9d,
quadOp9d,
cubicOp9d,
cubicOp8d,
cubicOp7d,
cubicOp6d,
cubicOp5d,
@ -3644,6 +3783,8 @@ var testDivs = [
testLine9,
testLine7b,
testLine7,
testLine6,
testLine5,
testSimplifyQuadratic21,
testSimplifyQuadratic20,
testSimplifyQuadratic19,

Просмотреть файл

@ -1888,11 +1888,110 @@ quad=(1.20573276,0.813456177 1.2679289,0.830085346 1.33333333,0.851851852)
{{x = 1.8746447406062119, y = 1.636550924974228}, {x = 2.7045030849246219, y = 1.7649927124767357}, {x = 4, y = 3}}
</div>
<div id="cubicOp8">
{{0,1}, {0,5}, {1,0}, {4,0}},
{{0,1}, {0,4}, {1,0}, {5,0}},
{{0,1}, {-0.00421781142,2.47981485}, {0.214213168,2.53784857}},
{{0.214213168,2.53784857}, {0.432644147,2.59588228}, {0.924337655,1.94072717}},
{{0.924337655,1.94072717}, {1.39158994,1.32418496}, {2.14967426,0.687365435}},
{{2.14967426,0.687365435}, {2.90775858,0.0505459108}, {4,0}},
{{0,1}, {-0.00720132722,2.05525633}, {0.206394399,2.10503282}},
{{0.206394399,2.10503282}, {0.419990125,2.15480931}, {0.940798831,1.67439357}},
{{0.940798831,1.67439357}, {1.48941875,1.16280321}, {2.47884711,0.60465921}},
{{2.47884711,0.60465921}, {3.46827548,0.0465152042}, {5,0}},
</div>
<div id="cubicOp8a">
{{x = 0.92433765471479945, y = 1.9407271660071879}, {x = 1.2518504275349398, y = 1.5283649441281617}, {x = 1.7179390069715588, y = 1.0614995059145118}}
{{x = 0.94079883097732186, y = 1.6743935703752681}, {x = 1.2598825072629554, y = 1.3977856697533602}, {x = 1.7179167190286528, y = 1.0665031295527474}}
</div>
<div id="cubicOp9d">
{{0,1}, {1,2}, {1,0}, {6,1}},
{{0,1}, {1,6}, {1,0}, {2,1}},
</div>
<div id="cubicOp11d">
Cubic cubic1 = {{0,1}, {3,4}, {1,0}, {5,1}};
Cubic cubic2 = {{0,1}, {1,5}, {1,0}, {4,3}};
{{0,1}, {1.10659493,2.10239153}, {1.50615334,2.12918252}},
{{1.50615334,2.12918252}, {1.90571174,2.15597351}, {2.1530827,1.71245386}},
{{2.1530827,1.71245386}, {2.39265628,1.2948736}, {2.98481198,0.986316183}},
{{2.98481198,0.986316183}, {3.57696768,0.677758769}, {5,1}},
{{0,1}, {0.351042317,2.40055211}, {0.610765407,2.56687524}},
{{0.610765407,2.56687524}, {0.870488497,2.73319838}, {1.21251591,2.40319262}},
{{1.21251591,2.40319262}, {1.57068059,2.04916077}, {2.21702741,1.98363478}},
{{2.21702741,1.98363478}, {2.86337424,1.91810879}, {4,3}},
</div>
<div id="cubicOp12d">
{{0, 1}, {1, 6}, {1, 0}, {1, 0}},
{{0, 1}, {0, 1}, {1, 0}, {6, 1}},
{{0,1}, {0.298,2.466}, {0.488,2.816}},
{{0.488,2.816}, {0.678,3.166}, {0.784,2.808}},
{{0.784,2.808}, {0.89,2.45}, {0.936,1.792}},
{{0.936,1.792}, {0.982,1.134}, {0.992,0.584}},
{{0.992,0.584}, {1.002,0.034}, {1,0}},
{{0,1}, {-0.0277777778,0.972222222}, {0.444444444,0.777777778}},
{{0.444444444,0.777777778}, {0.916666667,0.583333333}, {2.22222222,0.555555556}},
{{2.22222222,0.555555556}, {3.52777778,0.527777778}, {6,1}},
</div>
<div id="cubicOp13d">
{{0,1}, {4,5}, {1,0}, {5,3}},
{{0,1}, {3,5}, {1,0}, {5,4}},
{{0,1}, {1.48018645,2.46752265}, {1.93281168,2.58856757}},
{{1.93281168,2.58856757}, {2.38543691,2.7096125}, {2.51967352,2.34531784}},
{{2.51967352,2.34531784}, {2.65263731,2.00639194}, {3.1212119,1.98608967}},
{{3.1212119,1.98608967}, {3.5897865,1.96578739}, {5,3}},
{{0,1}, {1.05556321,2.39540407}, {1.46049052,2.58073968}},
{{1.46049052,2.58073968}, {1.86541784,2.76607529}, {2.09544533,2.51981963}},
{{2.09544533,2.51981963}, {2.33331524,2.25252128}, {2.92003302,2.39442311}},
{{2.92003302,2.39442311}, {3.5067508,2.53632493}, {5,4}},
</div>
<div id="cubicTest4">
{{x = 0, y = 1}, {x = 4, y = 5}, {x = 1, y = 0}, {x = 5, y = 3}}
{{x = 0, y = 1}, {x = 1, y = 6}, {x = 1, y = 0}, {x = 2, y = 0}}
</div>
<div id="cubicTest5">
{{x = 0, y = 1}, {x = 1, y = 6}, {x = 1, y = 0}, {x = 1, y = 0}}
{{x = 0, y = 1}, {x = 1, y = 6}, {x = 1, y = 0}, {x = 2, y = 1}}
</div>
<div id="cubicTest6">
{{x = 0, y = 1}, {x = 4, y = 5}, {x = 1, y = 0}, {x = 5, y = 3}}
{{x = 4, y = 4}, {x = 3, y = 4}, {x = 1, y = 2}, {x = 0, y = 0}}
</div>
<div id="cubicTest7">
{{x = 0, y = 1}, {x = 1.9274705288631189e-19, y = 1.0000000000000002}, {x = 0.0017190297609673323, y = 0.99828097023903239}, {x = 0.0053709083094631276, y = 0.99505672974365911}}
</div>
</div>
<script type="text/javascript">
var testDivs = [
cubicTest7,
cubicTest6,
cubicTest5,
cubicTest4,
cubicOp13d,
cubicOp12d,
cubicOp11d,
cubicOp9d,
cubicOp8a,
cubicOp8,
cubicOp7b,
cubicOp7a,
cubicOp7,

Просмотреть файл

@ -19,6 +19,7 @@
'../experimental/Intersection/CubicBezierClip.cpp',
'../experimental/Intersection/CubicBezierClip_Test.cpp',
'../experimental/Intersection/CubicBounds.cpp',
'../experimental/Intersection/CubicConvexHull.cpp',
'../experimental/Intersection/CubicIntersection.cpp',
'../experimental/Intersection/CubicIntersection_Test.cpp',
'../experimental/Intersection/CubicIntersection_TestData.cpp',