gfx/skia/trunk/src/pathops/SkDLineIntersection.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright 2012 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7 #include "SkIntersections.h"
michael@0 8 #include "SkPathOpsLine.h"
michael@0 9
michael@0 10 /* Determine the intersection point of two lines. This assumes the lines are not parallel,
michael@0 11 and that that the lines are infinite.
michael@0 12 From http://en.wikipedia.org/wiki/Line-line_intersection
michael@0 13 */
michael@0 14 SkDPoint SkIntersections::Line(const SkDLine& a, const SkDLine& b) {
michael@0 15 double axLen = a[1].fX - a[0].fX;
michael@0 16 double ayLen = a[1].fY - a[0].fY;
michael@0 17 double bxLen = b[1].fX - b[0].fX;
michael@0 18 double byLen = b[1].fY - b[0].fY;
michael@0 19 double denom = byLen * axLen - ayLen * bxLen;
michael@0 20 SkASSERT(denom);
michael@0 21 double term1 = a[1].fX * a[0].fY - a[1].fY * a[0].fX;
michael@0 22 double term2 = b[1].fX * b[0].fY - b[1].fY * b[0].fX;
michael@0 23 SkDPoint p;
michael@0 24 p.fX = (term1 * bxLen - axLen * term2) / denom;
michael@0 25 p.fY = (term1 * byLen - ayLen * term2) / denom;
michael@0 26 return p;
michael@0 27 }
michael@0 28
michael@0 29 void SkIntersections::cleanUpCoincidence() {
michael@0 30 SkASSERT(fUsed == 2);
michael@0 31 // both t values are good
michael@0 32 bool startMatch = fT[0][0] == 0 && (fT[1][0] == 0 || fT[1][0] == 1);
michael@0 33 bool endMatch = fT[0][1] == 1 && (fT[1][1] == 0 || fT[1][1] == 1);
michael@0 34 if (startMatch || endMatch) {
michael@0 35 removeOne(startMatch);
michael@0 36 return;
michael@0 37 }
michael@0 38 // either t value is good
michael@0 39 bool pStartMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1;
michael@0 40 bool pEndMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1;
michael@0 41 removeOne(pStartMatch || !pEndMatch);
michael@0 42 }
michael@0 43
michael@0 44 void SkIntersections::cleanUpParallelLines(bool parallel) {
michael@0 45 while (fUsed > 2) {
michael@0 46 removeOne(1);
michael@0 47 }
michael@0 48 if (fUsed == 2 && !parallel) {
michael@0 49 bool startMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1;
michael@0 50 bool endMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1;
michael@0 51 if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1])) {
michael@0 52 SkASSERT(startMatch || endMatch);
michael@0 53 removeOne(endMatch);
michael@0 54 }
michael@0 55 }
michael@0 56 }
michael@0 57
michael@0 58 void SkIntersections::computePoints(const SkDLine& line, int used) {
michael@0 59 fPt[0] = line.ptAtT(fT[0][0]);
michael@0 60 if ((fUsed = used) == 2) {
michael@0 61 fPt[1] = line.ptAtT(fT[0][1]);
michael@0 62 }
michael@0 63 }
michael@0 64
michael@0 65 int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) {
michael@0 66 fMax = 2;
michael@0 67 SkDVector aLen = a[1] - a[0];
michael@0 68 SkDVector bLen = b[1] - b[0];
michael@0 69 /* Slopes match when denom goes to zero:
michael@0 70 axLen / ayLen == bxLen / byLen
michael@0 71 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
michael@0 72 byLen * axLen == ayLen * bxLen
michael@0 73 byLen * axLen - ayLen * bxLen == 0 ( == denom )
michael@0 74 */
michael@0 75 double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX;
michael@0 76 SkDVector ab0 = a[0] - b[0];
michael@0 77 double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX;
michael@0 78 double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX;
michael@0 79 numerA /= denom;
michael@0 80 numerB /= denom;
michael@0 81 int used;
michael@0 82 if (!approximately_zero(denom)) {
michael@0 83 fT[0][0] = numerA;
michael@0 84 fT[1][0] = numerB;
michael@0 85 used = 1;
michael@0 86 } else {
michael@0 87 /* See if the axis intercepts match:
michael@0 88 ay - ax * ayLen / axLen == by - bx * ayLen / axLen
michael@0 89 axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
michael@0 90 axLen * ay - ax * ayLen == axLen * by - bx * ayLen
michael@0 91 */
michael@0 92 if (!AlmostEqualUlps(aLen.fX * a[0].fY - aLen.fY * a[0].fX,
michael@0 93 aLen.fX * b[0].fY - aLen.fY * b[0].fX)) {
michael@0 94 return fUsed = 0;
michael@0 95 }
michael@0 96 // there's no great answer for intersection points for coincident rays, but return something
michael@0 97 fT[0][0] = fT[1][0] = 0;
michael@0 98 fT[1][0] = fT[1][1] = 1;
michael@0 99 used = 2;
michael@0 100 }
michael@0 101 computePoints(a, used);
michael@0 102 return fUsed;
michael@0 103 }
michael@0 104
michael@0 105 // note that this only works if both lines are neither horizontal nor vertical
michael@0 106 int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
michael@0 107 fMax = 3; // note that we clean up so that there is no more than two in the end
michael@0 108 // see if end points intersect the opposite line
michael@0 109 double t;
michael@0 110 for (int iA = 0; iA < 2; ++iA) {
michael@0 111 if ((t = b.exactPoint(a[iA])) >= 0) {
michael@0 112 insert(iA, t, a[iA]);
michael@0 113 }
michael@0 114 }
michael@0 115 for (int iB = 0; iB < 2; ++iB) {
michael@0 116 if ((t = a.exactPoint(b[iB])) >= 0) {
michael@0 117 insert(t, iB, b[iB]);
michael@0 118 }
michael@0 119 }
michael@0 120 /* Determine the intersection point of two line segments
michael@0 121 Return FALSE if the lines don't intersect
michael@0 122 from: http://paulbourke.net/geometry/lineline2d/ */
michael@0 123 double axLen = a[1].fX - a[0].fX;
michael@0 124 double ayLen = a[1].fY - a[0].fY;
michael@0 125 double bxLen = b[1].fX - b[0].fX;
michael@0 126 double byLen = b[1].fY - b[0].fY;
michael@0 127 /* Slopes match when denom goes to zero:
michael@0 128 axLen / ayLen == bxLen / byLen
michael@0 129 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
michael@0 130 byLen * axLen == ayLen * bxLen
michael@0 131 byLen * axLen - ayLen * bxLen == 0 ( == denom )
michael@0 132 */
michael@0 133 double axByLen = axLen * byLen;
michael@0 134 double ayBxLen = ayLen * bxLen;
michael@0 135 // detect parallel lines the same way here and in SkOpAngle operator <
michael@0 136 // so that non-parallel means they are also sortable
michael@0 137 bool unparallel = fAllowNear ? NotAlmostEqualUlps(axByLen, ayBxLen)
michael@0 138 : NotAlmostDequalUlps(axByLen, ayBxLen);
michael@0 139 if (unparallel && fUsed == 0) {
michael@0 140 double ab0y = a[0].fY - b[0].fY;
michael@0 141 double ab0x = a[0].fX - b[0].fX;
michael@0 142 double numerA = ab0y * bxLen - byLen * ab0x;
michael@0 143 double numerB = ab0y * axLen - ayLen * ab0x;
michael@0 144 double denom = axByLen - ayBxLen;
michael@0 145 if (between(0, numerA, denom) && between(0, numerB, denom)) {
michael@0 146 fT[0][0] = numerA / denom;
michael@0 147 fT[1][0] = numerB / denom;
michael@0 148 computePoints(a, 1);
michael@0 149 }
michael@0 150 }
michael@0 151 if (fAllowNear || !unparallel) {
michael@0 152 for (int iA = 0; iA < 2; ++iA) {
michael@0 153 if ((t = b.nearPoint(a[iA])) >= 0) {
michael@0 154 insert(iA, t, a[iA]);
michael@0 155 }
michael@0 156 }
michael@0 157 for (int iB = 0; iB < 2; ++iB) {
michael@0 158 if ((t = a.nearPoint(b[iB])) >= 0) {
michael@0 159 insert(t, iB, b[iB]);
michael@0 160 }
michael@0 161 }
michael@0 162 }
michael@0 163 cleanUpParallelLines(!unparallel);
michael@0 164 SkASSERT(fUsed <= 2);
michael@0 165 return fUsed;
michael@0 166 }
michael@0 167
michael@0 168 static int horizontal_coincident(const SkDLine& line, double y) {
michael@0 169 double min = line[0].fY;
michael@0 170 double max = line[1].fY;
michael@0 171 if (min > max) {
michael@0 172 SkTSwap(min, max);
michael@0 173 }
michael@0 174 if (min > y || max < y) {
michael@0 175 return 0;
michael@0 176 }
michael@0 177 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
michael@0 178 return 2;
michael@0 179 }
michael@0 180 return 1;
michael@0 181 }
michael@0 182
michael@0 183 static double horizontal_intercept(const SkDLine& line, double y) {
michael@0 184 return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY));
michael@0 185 }
michael@0 186
michael@0 187 int SkIntersections::horizontal(const SkDLine& line, double y) {
michael@0 188 fMax = 2;
michael@0 189 int horizontalType = horizontal_coincident(line, y);
michael@0 190 if (horizontalType == 1) {
michael@0 191 fT[0][0] = horizontal_intercept(line, y);
michael@0 192 } else if (horizontalType == 2) {
michael@0 193 fT[0][0] = 0;
michael@0 194 fT[0][1] = 1;
michael@0 195 }
michael@0 196 return fUsed = horizontalType;
michael@0 197 }
michael@0 198
michael@0 199 int SkIntersections::horizontal(const SkDLine& line, double left, double right,
michael@0 200 double y, bool flipped) {
michael@0 201 fMax = 2;
michael@0 202 // see if end points intersect the opposite line
michael@0 203 double t;
michael@0 204 const SkDPoint leftPt = { left, y };
michael@0 205 if ((t = line.exactPoint(leftPt)) >= 0) {
michael@0 206 insert(t, (double) flipped, leftPt);
michael@0 207 }
michael@0 208 if (left != right) {
michael@0 209 const SkDPoint rightPt = { right, y };
michael@0 210 if ((t = line.exactPoint(rightPt)) >= 0) {
michael@0 211 insert(t, (double) !flipped, rightPt);
michael@0 212 }
michael@0 213 for (int index = 0; index < 2; ++index) {
michael@0 214 if ((t = SkDLine::ExactPointH(line[index], left, right, y)) >= 0) {
michael@0 215 insert((double) index, flipped ? 1 - t : t, line[index]);
michael@0 216 }
michael@0 217 }
michael@0 218 }
michael@0 219 int result = horizontal_coincident(line, y);
michael@0 220 if (result == 1 && fUsed == 0) {
michael@0 221 fT[0][0] = horizontal_intercept(line, y);
michael@0 222 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
michael@0 223 if (between(left, xIntercept, right)) {
michael@0 224 fT[1][0] = (xIntercept - left) / (right - left);
michael@0 225 if (flipped) {
michael@0 226 // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
michael@0 227 for (int index = 0; index < result; ++index) {
michael@0 228 fT[1][index] = 1 - fT[1][index];
michael@0 229 }
michael@0 230 }
michael@0 231 fPt[0].fX = xIntercept;
michael@0 232 fPt[0].fY = y;
michael@0 233 fUsed = 1;
michael@0 234 }
michael@0 235 }
michael@0 236 if (fAllowNear || result == 2) {
michael@0 237 if ((t = line.nearPoint(leftPt)) >= 0) {
michael@0 238 insert(t, (double) flipped, leftPt);
michael@0 239 }
michael@0 240 if (left != right) {
michael@0 241 const SkDPoint rightPt = { right, y };
michael@0 242 if ((t = line.nearPoint(rightPt)) >= 0) {
michael@0 243 insert(t, (double) !flipped, rightPt);
michael@0 244 }
michael@0 245 for (int index = 0; index < 2; ++index) {
michael@0 246 if ((t = SkDLine::NearPointH(line[index], left, right, y)) >= 0) {
michael@0 247 insert((double) index, flipped ? 1 - t : t, line[index]);
michael@0 248 }
michael@0 249 }
michael@0 250 }
michael@0 251 }
michael@0 252 cleanUpParallelLines(result == 2);
michael@0 253 return fUsed;
michael@0 254 }
michael@0 255
michael@0 256 static int vertical_coincident(const SkDLine& line, double x) {
michael@0 257 double min = line[0].fX;
michael@0 258 double max = line[1].fX;
michael@0 259 if (min > max) {
michael@0 260 SkTSwap(min, max);
michael@0 261 }
michael@0 262 if (!precisely_between(min, x, max)) {
michael@0 263 return 0;
michael@0 264 }
michael@0 265 if (AlmostEqualUlps(min, max)) {
michael@0 266 return 2;
michael@0 267 }
michael@0 268 return 1;
michael@0 269 }
michael@0 270
michael@0 271 static double vertical_intercept(const SkDLine& line, double x) {
michael@0 272 return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX));
michael@0 273 }
michael@0 274
michael@0 275 int SkIntersections::vertical(const SkDLine& line, double x) {
michael@0 276 fMax = 2;
michael@0 277 int verticalType = vertical_coincident(line, x);
michael@0 278 if (verticalType == 1) {
michael@0 279 fT[0][0] = vertical_intercept(line, x);
michael@0 280 } else if (verticalType == 2) {
michael@0 281 fT[0][0] = 0;
michael@0 282 fT[0][1] = 1;
michael@0 283 }
michael@0 284 return fUsed = verticalType;
michael@0 285 }
michael@0 286
michael@0 287 int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
michael@0 288 double x, bool flipped) {
michael@0 289 fMax = 2;
michael@0 290 // see if end points intersect the opposite line
michael@0 291 double t;
michael@0 292 SkDPoint topPt = { x, top };
michael@0 293 if ((t = line.exactPoint(topPt)) >= 0) {
michael@0 294 insert(t, (double) flipped, topPt);
michael@0 295 }
michael@0 296 if (top != bottom) {
michael@0 297 SkDPoint bottomPt = { x, bottom };
michael@0 298 if ((t = line.exactPoint(bottomPt)) >= 0) {
michael@0 299 insert(t, (double) !flipped, bottomPt);
michael@0 300 }
michael@0 301 for (int index = 0; index < 2; ++index) {
michael@0 302 if ((t = SkDLine::ExactPointV(line[index], top, bottom, x)) >= 0) {
michael@0 303 insert((double) index, flipped ? 1 - t : t, line[index]);
michael@0 304 }
michael@0 305 }
michael@0 306 }
michael@0 307 int result = vertical_coincident(line, x);
michael@0 308 if (result == 1 && fUsed == 0) {
michael@0 309 fT[0][0] = vertical_intercept(line, x);
michael@0 310 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
michael@0 311 if (between(top, yIntercept, bottom)) {
michael@0 312 fT[1][0] = (yIntercept - top) / (bottom - top);
michael@0 313 if (flipped) {
michael@0 314 // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [0].fY
michael@0 315 for (int index = 0; index < result; ++index) {
michael@0 316 fT[1][index] = 1 - fT[1][index];
michael@0 317 }
michael@0 318 }
michael@0 319 fPt[0].fX = x;
michael@0 320 fPt[0].fY = yIntercept;
michael@0 321 fUsed = 1;
michael@0 322 }
michael@0 323 }
michael@0 324 if (fAllowNear || result == 2) {
michael@0 325 if ((t = line.nearPoint(topPt)) >= 0) {
michael@0 326 insert(t, (double) flipped, topPt);
michael@0 327 }
michael@0 328 if (top != bottom) {
michael@0 329 SkDPoint bottomPt = { x, bottom };
michael@0 330 if ((t = line.nearPoint(bottomPt)) >= 0) {
michael@0 331 insert(t, (double) !flipped, bottomPt);
michael@0 332 }
michael@0 333 for (int index = 0; index < 2; ++index) {
michael@0 334 if ((t = SkDLine::NearPointV(line[index], top, bottom, x)) >= 0) {
michael@0 335 insert((double) index, flipped ? 1 - t : t, line[index]);
michael@0 336 }
michael@0 337 }
michael@0 338 }
michael@0 339 }
michael@0 340 cleanUpParallelLines(result == 2);
michael@0 341 return fUsed;
michael@0 342 }
michael@0 343
michael@0 344 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.py
michael@0 345 // 4 subs, 2 muls, 1 cmp
michael@0 346 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) {
michael@0 347 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX);
michael@0 348 }
michael@0 349
michael@0 350 // 16 subs, 8 muls, 6 cmps
michael@0 351 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) {
michael@0 352 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1])
michael@0 353 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]);
michael@0 354 }

mercurial