Revert "Intersection calc cleanup."
This reverts commit 1b016d50b9
.
Reason for revert: Breaking polygon inset code.
Original change's description:
> Intersection calc cleanup.
>
> * Fixes some bugs in compute_intersection
> * Adds an intersection check that doesn't need to compute the exact pt
> * Make some of the variable names consistent
> * General floating point tweaks
>
> Bug: skia:
> Change-Id: Ib2fb8bee39b5d9c635d62e606fe826b7efe64dfa
> Reviewed-on: https://skia-review.googlesource.com/145532
> Commit-Queue: Jim Van Verth <jvanverth@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>
TBR=jvanverth@google.com,brianosman@google.com
Change-Id: I9515e3e8bfea146ebd9c1628f1b963f1557b8a89
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/145900
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
430424bd74
commit
47d9ee455d
@ -22,15 +22,13 @@ struct OffsetSegment {
|
||||
SkVector fV;
|
||||
};
|
||||
|
||||
constexpr SkScalar kCrossTolerance = SK_ScalarNearlyZero * SK_ScalarNearlyZero;
|
||||
|
||||
// Computes perpDot for point p compared to segment defined by origin p0 and vector v.
|
||||
// Computes perpDot for point p compared to segment defined by origin s0 and vector v0.
|
||||
// A positive value means the point is to the left of the segment,
|
||||
// negative is to the right, 0 is collinear.
|
||||
static int compute_side(const SkPoint& p0, const SkVector& v, const SkPoint& p) {
|
||||
SkVector w = p - p0;
|
||||
SkScalar perpDot = v.cross(w);
|
||||
if (!SkScalarNearlyZero(perpDot, kCrossTolerance)) {
|
||||
static int compute_side(const SkPoint& s0, const SkVector& v0, const SkPoint& p) {
|
||||
SkVector v1 = p - s0;
|
||||
SkScalar perpDot = v0.cross(v1);
|
||||
if (!SkScalarNearlyZero(perpDot)) {
|
||||
return ((perpDot > 0) ? 1 : -1);
|
||||
}
|
||||
|
||||
@ -52,7 +50,7 @@ int SkGetPolygonWinding(const SkPoint* polygonVerts, int polygonSize) {
|
||||
quadArea += v0.cross(v1);
|
||||
v0 = v1;
|
||||
}
|
||||
if (SkScalarNearlyZero(quadArea, kCrossTolerance)) {
|
||||
if (SkScalarNearlyZero(quadArea)) {
|
||||
return 0;
|
||||
}
|
||||
// 1 == ccw, -1 == cw
|
||||
@ -65,7 +63,7 @@ inline void compute_offset(SkScalar d, const SkPoint& polyPoint, int side,
|
||||
SkScalar dsq = d * d;
|
||||
SkVector dP = outerTangentIntersect - polyPoint;
|
||||
SkScalar dPlenSq = SkPointPriv::LengthSqd(dP);
|
||||
if (SkScalarNearlyZero(dPlenSq, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) {
|
||||
if (SkScalarNearlyZero(dPlenSq)) {
|
||||
v->set(0, 0);
|
||||
} else {
|
||||
SkScalar discrim = SkScalarSqrt(dPlenSq - dsq);
|
||||
@ -120,10 +118,13 @@ bool SkOffsetSegment(const SkPoint& p0, const SkPoint& p1, SkScalar d0, SkScalar
|
||||
return true;
|
||||
}
|
||||
|
||||
// check interval to see if intersection is in segment
|
||||
static inline bool outside_interval(SkScalar numer, SkScalar denom, bool denomPositive) {
|
||||
return (denomPositive && (numer < 0 || numer > denom)) ||
|
||||
(!denomPositive && (numer > 0 || numer < denom));
|
||||
// compute fraction of d along v
|
||||
static inline SkScalar compute_param(const SkVector& v, const SkVector& d) {
|
||||
if (SkScalarNearlyZero(v.fX)) {
|
||||
return d.fY / v.fY;
|
||||
} else {
|
||||
return d.fX / v.fX;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the intersection 'p' between segments s0 and s1, if any.
|
||||
@ -133,23 +134,21 @@ static bool compute_intersection(const OffsetSegment& s0, const OffsetSegment& s
|
||||
SkPoint* p, SkScalar* s, SkScalar* t) {
|
||||
const SkVector& v0 = s0.fV;
|
||||
const SkVector& v1 = s1.fV;
|
||||
SkVector w = s1.fP0 - s0.fP0;
|
||||
SkScalar denom = v0.cross(v1);
|
||||
bool denomPositive = (denom > 0);
|
||||
SkScalar sNumer, tNumer;
|
||||
if (SkScalarNearlyZero(denom, kCrossTolerance)) {
|
||||
SkVector d = s1.fP0 - s0.fP0;
|
||||
SkScalar perpDot = v0.cross(v1);
|
||||
SkScalar localS, localT;
|
||||
if (SkScalarNearlyZero(perpDot)) {
|
||||
// segments are parallel, but not collinear
|
||||
if (!SkScalarNearlyZero(w.cross(v0), kCrossTolerance) ||
|
||||
!SkScalarNearlyZero(w.cross(v1), kCrossTolerance)) {
|
||||
if (!SkScalarNearlyZero(d.cross(v0)) || !SkScalarNearlyZero(d.cross(v1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for zero-length segments
|
||||
// Check for degenerate segments
|
||||
if (!SkPointPriv::CanNormalize(v0.fX, v0.fY)) {
|
||||
// Both are zero-length
|
||||
// Both are degenerate
|
||||
if (!SkPointPriv::CanNormalize(v1.fX, v1.fY)) {
|
||||
// Check if they're the same point
|
||||
if (!SkPointPriv::CanNormalize(w.fX, w.fY)) {
|
||||
if (!SkPointPriv::CanNormalize(d.fX, d.fY)) {
|
||||
*p = s0.fP0;
|
||||
*s = 0;
|
||||
*t = 0;
|
||||
@ -158,19 +157,17 @@ static bool compute_intersection(const OffsetSegment& s0, const OffsetSegment& s
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Otherwise project segment0's origin onto segment1
|
||||
tNumer = v1.dot(-w);
|
||||
denom = v1.length();
|
||||
if (outside_interval(tNumer, denom, true)) {
|
||||
// Otherwise project onto segment1
|
||||
localT = compute_param(v1, -d);
|
||||
if (localT < 0 || localT > SK_Scalar1) {
|
||||
return false;
|
||||
}
|
||||
sNumer = 0;
|
||||
localS = 0;
|
||||
} else {
|
||||
// Project segment1's endpoints onto segment0
|
||||
sNumer = v0.dot(w);
|
||||
denom = v0.length();
|
||||
tNumer = 0;
|
||||
if (outside_interval(sNumer, denom, true)) {
|
||||
localS = compute_param(v0, d);
|
||||
localT = 0;
|
||||
if (localS < 0 || localS > SK_Scalar1) {
|
||||
// The first endpoint doesn't lie on segment0
|
||||
// If segment1 is degenerate, then there's no collision
|
||||
if (!SkPointPriv::CanNormalize(v1.fX, v1.fY)) {
|
||||
@ -178,36 +175,32 @@ static bool compute_intersection(const OffsetSegment& s0, const OffsetSegment& s
|
||||
}
|
||||
|
||||
// Otherwise try the other one
|
||||
SkScalar oldSNumer = sNumer;
|
||||
sNumer = v0.dot(w + v1);
|
||||
tNumer = denom;
|
||||
if (outside_interval(sNumer, denom, true)) {
|
||||
SkScalar oldLocalS = localS;
|
||||
localS = compute_param(v0, d + v1);
|
||||
localT = SK_Scalar1;
|
||||
if (localS < 0 || localS > SK_Scalar1) {
|
||||
// it's possible that segment1's interval surrounds segment0
|
||||
// this is false if params have the same signs, and in that case no collision
|
||||
if (sNumer*oldSNumer > 0) {
|
||||
if (localS*oldLocalS > 0) {
|
||||
return false;
|
||||
}
|
||||
// otherwise project segment0's endpoint onto segment1 instead
|
||||
sNumer = 0;
|
||||
tNumer = v1.dot(-w);
|
||||
denom = v1.length();
|
||||
localS = 0;
|
||||
localT = compute_param(v1, -d);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sNumer = w.cross(v1);
|
||||
if (outside_interval(sNumer, denom, denomPositive)) {
|
||||
localS = d.cross(v1) / perpDot;
|
||||
if (localS < 0 || localS > SK_Scalar1) {
|
||||
return false;
|
||||
}
|
||||
tNumer = w.cross(v0);
|
||||
if (outside_interval(tNumer, denom, denomPositive)) {
|
||||
localT = d.cross(v0) / perpDot;
|
||||
if (localT < 0 || localT > SK_Scalar1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SkScalar localS = sNumer/denom;
|
||||
SkScalar localT = tNumer/denom;
|
||||
|
||||
*p = s0.fP0 + v0*localS;
|
||||
*s = localS;
|
||||
*t = localT;
|
||||
@ -306,14 +299,14 @@ struct OffsetEdge {
|
||||
const SkVector& v0 = s0.fV;
|
||||
const SkVector& v1 = s1.fV;
|
||||
|
||||
SkScalar denom = v0.cross(v1);
|
||||
if (SkScalarNearlyZero(denom, kCrossTolerance)) {
|
||||
SkScalar perpDot = v0.cross(v1);
|
||||
if (SkScalarNearlyZero(perpDot)) {
|
||||
// segments are parallel
|
||||
return SK_ScalarMax;
|
||||
}
|
||||
|
||||
SkVector d = s1.fP0 - s0.fP0;
|
||||
SkScalar localS = d.cross(v1) / denom;
|
||||
SkScalar localS = d.cross(v1) / perpDot;
|
||||
if (localS < 0) {
|
||||
localS = -localS;
|
||||
} else {
|
||||
@ -528,13 +521,6 @@ static bool left(const SkPoint& p0, const SkPoint& p1) {
|
||||
return p0.fX < p1.fX || (!(p0.fX > p1.fX) && p0.fY < p1.fY);
|
||||
}
|
||||
|
||||
// checks to see if a point that is collinear with a segment lies in the segment's range
|
||||
static bool in_segment(const SkPoint& p0, const SkVector& v, const SkPoint& p) {
|
||||
SkVector w = p - p0;
|
||||
SkScalar numer = w.dot(v);
|
||||
return (numer >= 0 && numer*numer <= v.dot(v));
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
static bool Left(const Vertex& qv0, const Vertex& qv1) {
|
||||
return left(qv0.fPosition, qv1.fPosition);
|
||||
@ -562,6 +548,7 @@ struct ActiveEdge {
|
||||
// returns true if "this" is above "that"
|
||||
bool above(const ActiveEdge& that) const {
|
||||
SkASSERT(this->fSegment.fP0.fX <= that.fSegment.fP0.fX);
|
||||
const SkScalar kTolerance = SK_ScalarNearlyZero * SK_ScalarNearlyZero;
|
||||
const SkVector& u = this->fSegment.fV;
|
||||
SkVector dv = that.fSegment.fP0 - this->fSegment.fP0;
|
||||
// The idea here is that if the vector between the origins of the two segments (dv)
|
||||
@ -569,9 +556,9 @@ struct ActiveEdge {
|
||||
// then we know that "this" is above that. If the result is clockwise we say it's below.
|
||||
if (this->fIndex0 != that.fIndex0) {
|
||||
SkScalar cross = dv.cross(u);
|
||||
if (cross > kCrossTolerance) {
|
||||
if (cross > kTolerance) {
|
||||
return true;
|
||||
} else if (cross < -kCrossTolerance) {
|
||||
} else if (cross < -kTolerance) {
|
||||
return false;
|
||||
}
|
||||
} else if (this->fIndex1 == that.fIndex1) {
|
||||
@ -587,9 +574,9 @@ struct ActiveEdge {
|
||||
// = old_dv + that.fV
|
||||
dv += that.fSegment.fV;
|
||||
SkScalar cross = dv.cross(u);
|
||||
if (cross > kCrossTolerance) {
|
||||
if (cross > kTolerance) {
|
||||
return true;
|
||||
} else if (cross < -kCrossTolerance) {
|
||||
} else if (cross < -kTolerance) {
|
||||
return false;
|
||||
}
|
||||
// If the previous check fails, the two segments are nearly collinear
|
||||
@ -612,50 +599,14 @@ struct ActiveEdge {
|
||||
}
|
||||
|
||||
bool intersect(const ActiveEdge& that) const {
|
||||
SkPoint intersection;
|
||||
SkScalar s, t;
|
||||
// check first to see if these edges are neighbors in the polygon
|
||||
if (this->fIndex0 == that.fIndex0 || this->fIndex1 == that.fIndex0 ||
|
||||
this->fIndex0 == that.fIndex1 || this->fIndex1 == that.fIndex1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't need the exact intersection point so we can do a simpler test here.
|
||||
const SkPoint& p0 = this->fSegment.fP0;
|
||||
const SkVector& v = this->fSegment.fV;
|
||||
SkPoint p1 = p0 + v;
|
||||
const SkPoint& q0 = that.fSegment.fP0;
|
||||
const SkVector& w = that.fSegment.fV;
|
||||
SkPoint q1 = q0 + w;
|
||||
|
||||
int side0 = compute_side(p0, v, q0);
|
||||
int side1 = compute_side(p0, v, q1);
|
||||
int side2 = compute_side(q0, w, p0);
|
||||
int side3 = compute_side(q0, w, p1);
|
||||
|
||||
// if each segment straddles the other (i.e., the endpoints have different sides)
|
||||
// then they intersect
|
||||
if (side0*side1 < 0 && side2*side3 < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check collinear cases
|
||||
// q0 lies on segment0's line, see if it's inside the segment
|
||||
if (side0 == 0 && in_segment(p0, v, q0)) {
|
||||
return true;
|
||||
}
|
||||
// q0 + w lies on segment0's line, see if it's inside the segment
|
||||
if (side1 == 0 && in_segment(p0, v, q1)) {
|
||||
return true;
|
||||
}
|
||||
// p0 lies on segment1's line, see if it's inside the segment
|
||||
if (side2 == 0 && in_segment(q0, w, p0)) {
|
||||
return true;
|
||||
}
|
||||
// p0 + v lies on segment0's line, see if it's inside the segment
|
||||
if (side3 == 0 && in_segment(q0, w, p1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return compute_intersection(this->fSegment, that.fSegment, &intersection, &s, &t);
|
||||
}
|
||||
|
||||
bool lessThan(const ActiveEdge& that) const {
|
||||
|
Loading…
Reference in New Issue
Block a user