| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkIntersections.h" | 7 #include "SkIntersections.h" |
| 8 #include "SkPathOpsCubic.h" | 8 #include "SkPathOpsCubic.h" |
| 9 #include "SkPathOpsLine.h" | 9 #include "SkPathOpsLine.h" |
| 10 | 10 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 , fLine(l) | 86 , fLine(l) |
| 87 , fIntersections(i) | 87 , fIntersections(i) |
| 88 , fAllowNear(true) { | 88 , fAllowNear(true) { |
| 89 i->setMax(3); | 89 i->setMax(3); |
| 90 } | 90 } |
| 91 | 91 |
| 92 void allowNear(bool allow) { | 92 void allowNear(bool allow) { |
| 93 fAllowNear = allow; | 93 fAllowNear = allow; |
| 94 } | 94 } |
| 95 | 95 |
| 96 void checkCoincident() { |
| 97 int last = fIntersections->used() - 1; |
| 98 for (int index = 0; index < last; ) { |
| 99 double cubicMidT = ((*fIntersections)[0][index] + (*fIntersections)[
0][index + 1]) / 2; |
| 100 SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); |
| 101 double t = fLine.nearPoint(cubicMidPt, NULL); |
| 102 if (t < 0) { |
| 103 ++index; |
| 104 continue; |
| 105 } |
| 106 if (fIntersections->isCoincident(index)) { |
| 107 fIntersections->removeOne(index); |
| 108 --last; |
| 109 } else if (fIntersections->isCoincident(index + 1)) { |
| 110 fIntersections->removeOne(index + 1); |
| 111 --last; |
| 112 } else { |
| 113 fIntersections->setCoincident(index++); |
| 114 } |
| 115 fIntersections->setCoincident(index); |
| 116 } |
| 117 } |
| 118 |
| 96 // see parallel routine in line quadratic intersections | 119 // see parallel routine in line quadratic intersections |
| 97 int intersectRay(double roots[3]) { | 120 int intersectRay(double roots[3]) { |
| 98 double adj = fLine[1].fX - fLine[0].fX; | 121 double adj = fLine[1].fX - fLine[0].fX; |
| 99 double opp = fLine[1].fY - fLine[0].fY; | 122 double opp = fLine[1].fY - fLine[0].fY; |
| 100 SkDCubic c; | 123 SkDCubic c; |
| 101 for (int n = 0; n < 4; ++n) { | 124 for (int n = 0; n < 4; ++n) { |
| 102 c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine
[0].fX) * opp; | 125 c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine
[0].fX) * opp; |
| 103 } | 126 } |
| 104 double A, B, C, D; | 127 double A, B, C, D; |
| 105 SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); | 128 SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 124 addExactEndPoints(); | 147 addExactEndPoints(); |
| 125 if (fAllowNear) { | 148 if (fAllowNear) { |
| 126 addNearEndPoints(); | 149 addNearEndPoints(); |
| 127 } | 150 } |
| 128 double rootVals[3]; | 151 double rootVals[3]; |
| 129 int roots = intersectRay(rootVals); | 152 int roots = intersectRay(rootVals); |
| 130 for (int index = 0; index < roots; ++index) { | 153 for (int index = 0; index < roots; ++index) { |
| 131 double cubicT = rootVals[index]; | 154 double cubicT = rootVals[index]; |
| 132 double lineT = findLineT(cubicT); | 155 double lineT = findLineT(cubicT); |
| 133 SkDPoint pt; | 156 SkDPoint pt; |
| 134 if (pinTs(&cubicT, &lineT, &pt, kPointUninitialized)) { | 157 if (pinTs(&cubicT, &lineT, &pt, kPointUninitialized) && uniqueAnswer
(cubicT, pt)) { |
| 135 #if ONE_OFF_DEBUG | |
| 136 SkDPoint cPt = fCubic.ptAtT(cubicT); | |
| 137 SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__
, pt.fX, pt.fY, | |
| 138 cPt.fX, cPt.fY); | |
| 139 #endif | |
| 140 for (int inner = 0; inner < fIntersections->used(); ++inner) { | |
| 141 if (fIntersections->pt(inner) != pt) { | |
| 142 continue; | |
| 143 } | |
| 144 double existingCubicT = (*fIntersections)[0][inner]; | |
| 145 if (cubicT == existingCubicT) { | |
| 146 goto skipInsert; | |
| 147 } | |
| 148 // check if midway on cubic is also same point. If so, disca
rd this | |
| 149 double cubicMidT = (existingCubicT + cubicT) / 2; | |
| 150 SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); | |
| 151 if (cubicMidPt.approximatelyEqual(pt)) { | |
| 152 goto skipInsert; | |
| 153 } | |
| 154 } | |
| 155 fIntersections->insert(cubicT, lineT, pt); | 158 fIntersections->insert(cubicT, lineT, pt); |
| 156 skipInsert: | |
| 157 ; | |
| 158 } | 159 } |
| 159 } | 160 } |
| 161 checkCoincident(); |
| 160 return fIntersections->used(); | 162 return fIntersections->used(); |
| 161 } | 163 } |
| 162 | 164 |
| 163 static int HorizontalIntersect(const SkDCubic& c, double axisIntercept, doub
le roots[3]) { | 165 static int HorizontalIntersect(const SkDCubic& c, double axisIntercept, doub
le roots[3]) { |
| 164 double A, B, C, D; | 166 double A, B, C, D; |
| 165 SkDCubic::Coefficients(&c[0].fY, &A, &B, &C, &D); | 167 SkDCubic::Coefficients(&c[0].fY, &A, &B, &C, &D); |
| 166 D -= axisIntercept; | 168 D -= axisIntercept; |
| 167 int count = SkDCubic::RootsValidT(A, B, C, D, roots); | 169 int count = SkDCubic::RootsValidT(A, B, C, D, roots); |
| 168 for (int index = 0; index < count; ++index) { | 170 for (int index = 0; index < count; ++index) { |
| 169 SkDPoint calcPt = c.ptAtT(roots[index]); | 171 SkDPoint calcPt = c.ptAtT(roots[index]); |
| 170 if (!approximately_equal(calcPt.fY, axisIntercept)) { | 172 if (!approximately_equal(calcPt.fY, axisIntercept)) { |
| 171 double extremeTs[6]; | 173 double extremeTs[6]; |
| 172 int extrema = SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c
[3].fY, extremeTs); | 174 int extrema = SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c
[3].fY, extremeTs); |
| 173 count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubi
c::kYAxis, roots); | 175 count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubi
c::kYAxis, roots); |
| 174 break; | 176 break; |
| 175 } | 177 } |
| 176 } | 178 } |
| 177 return count; | 179 return count; |
| 178 } | 180 } |
| 179 | 181 |
| 180 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { | 182 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { |
| 181 addExactHorizontalEndPoints(left, right, axisIntercept); | 183 addExactHorizontalEndPoints(left, right, axisIntercept); |
| 182 if (fAllowNear) { | 184 if (fAllowNear) { |
| 183 addNearHorizontalEndPoints(left, right, axisIntercept); | 185 addNearHorizontalEndPoints(left, right, axisIntercept); |
| 184 } | 186 } |
| 185 double roots[3]; | 187 double roots[3]; |
| 186 int count = HorizontalIntersect(fCubic, axisIntercept, roots); | 188 int count = HorizontalIntersect(fCubic, axisIntercept, roots); |
| 187 for (int index = 0; index < count; ++index) { | 189 for (int index = 0; index < count; ++index) { |
| 188 double cubicT = roots[index]; | 190 double cubicT = roots[index]; |
| 189 SkDPoint pt; | 191 SkDPoint pt = { fCubic.ptAtT(cubicT).fX, axisIntercept }; |
| 190 pt.fX = fCubic.ptAtT(cubicT).fX; | |
| 191 pt.fY = axisIntercept; | |
| 192 double lineT = (pt.fX - left) / (right - left); | 192 double lineT = (pt.fX - left) / (right - left); |
| 193 if (pinTs(&cubicT, &lineT, &pt, kPointInitialized)) { | 193 if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(c
ubicT, pt)) { |
| 194 fIntersections->insert(cubicT, lineT, pt); | 194 fIntersections->insert(cubicT, lineT, pt); |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 if (flipped) { | 197 if (flipped) { |
| 198 fIntersections->flip(); | 198 fIntersections->flip(); |
| 199 } | 199 } |
| 200 checkCoincident(); |
| 200 return fIntersections->used(); | 201 return fIntersections->used(); |
| 201 } | 202 } |
| 202 | 203 |
| 204 bool uniqueAnswer(double cubicT, const SkDPoint& pt) { |
| 205 for (int inner = 0; inner < fIntersections->used(); ++inner) { |
| 206 if (fIntersections->pt(inner) != pt) { |
| 207 continue; |
| 208 } |
| 209 double existingCubicT = (*fIntersections)[0][inner]; |
| 210 if (cubicT == existingCubicT) { |
| 211 return false; |
| 212 } |
| 213 // check if midway on cubic is also same point. If so, discard t
his |
| 214 double cubicMidT = (existingCubicT + cubicT) / 2; |
| 215 SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); |
| 216 if (cubicMidPt.approximatelyEqual(pt)) { |
| 217 return false; |
| 218 } |
| 219 } |
| 220 #if ONE_OFF_DEBUG |
| 221 SkDPoint cPt = fCubic.ptAtT(cubicT); |
| 222 SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt
.fX, pt.fY, |
| 223 cPt.fX, cPt.fY); |
| 224 #endif |
| 225 return true; |
| 226 } |
| 227 |
| 203 static int VerticalIntersect(const SkDCubic& c, double axisIntercept, double
roots[3]) { | 228 static int VerticalIntersect(const SkDCubic& c, double axisIntercept, double
roots[3]) { |
| 204 double A, B, C, D; | 229 double A, B, C, D; |
| 205 SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); | 230 SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); |
| 206 D -= axisIntercept; | 231 D -= axisIntercept; |
| 207 int count = SkDCubic::RootsValidT(A, B, C, D, roots); | 232 int count = SkDCubic::RootsValidT(A, B, C, D, roots); |
| 208 for (int index = 0; index < count; ++index) { | 233 for (int index = 0; index < count; ++index) { |
| 209 SkDPoint calcPt = c.ptAtT(roots[index]); | 234 SkDPoint calcPt = c.ptAtT(roots[index]); |
| 210 if (!approximately_equal(calcPt.fX, axisIntercept)) { | 235 if (!approximately_equal(calcPt.fX, axisIntercept)) { |
| 211 double extremeTs[6]; | 236 double extremeTs[6]; |
| 212 int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c
[3].fX, extremeTs); | 237 int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c
[3].fX, extremeTs); |
| 213 count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubi
c::kXAxis, roots); | 238 count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubi
c::kXAxis, roots); |
| 214 break; | 239 break; |
| 215 } | 240 } |
| 216 } | 241 } |
| 217 return count; | 242 return count; |
| 218 } | 243 } |
| 219 | 244 |
| 220 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { | 245 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { |
| 221 addExactVerticalEndPoints(top, bottom, axisIntercept); | 246 addExactVerticalEndPoints(top, bottom, axisIntercept); |
| 222 if (fAllowNear) { | 247 if (fAllowNear) { |
| 223 addNearVerticalEndPoints(top, bottom, axisIntercept); | 248 addNearVerticalEndPoints(top, bottom, axisIntercept); |
| 224 } | 249 } |
| 225 double roots[3]; | 250 double roots[3]; |
| 226 int count = VerticalIntersect(fCubic, axisIntercept, roots); | 251 int count = VerticalIntersect(fCubic, axisIntercept, roots); |
| 227 for (int index = 0; index < count; ++index) { | 252 for (int index = 0; index < count; ++index) { |
| 228 double cubicT = roots[index]; | 253 double cubicT = roots[index]; |
| 229 SkDPoint pt; | 254 SkDPoint pt = { axisIntercept, fCubic.ptAtT(cubicT).fY }; |
| 230 pt.fX = axisIntercept; | |
| 231 pt.fY = fCubic.ptAtT(cubicT).fY; | |
| 232 double lineT = (pt.fY - top) / (bottom - top); | 255 double lineT = (pt.fY - top) / (bottom - top); |
| 233 if (pinTs(&cubicT, &lineT, &pt, kPointInitialized)) { | 256 if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(c
ubicT, pt)) { |
| 234 fIntersections->insert(cubicT, lineT, pt); | 257 fIntersections->insert(cubicT, lineT, pt); |
| 235 } | 258 } |
| 236 } | 259 } |
| 237 if (flipped) { | 260 if (flipped) { |
| 238 fIntersections->flip(); | 261 fIntersections->flip(); |
| 239 } | 262 } |
| 263 checkCoincident(); |
| 240 return fIntersections->used(); | 264 return fIntersections->used(); |
| 241 } | 265 } |
| 242 | 266 |
| 243 protected: | 267 protected: |
| 244 | 268 |
| 245 void addExactEndPoints() { | 269 void addExactEndPoints() { |
| 246 for (int cIndex = 0; cIndex < 4; cIndex += 3) { | 270 for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
| 247 double lineT = fLine.exactPoint(fCubic[cIndex]); | 271 double lineT = fLine.exactPoint(fCubic[cIndex]); |
| 248 if (lineT < 0) { | 272 if (lineT < 0) { |
| 249 continue; | 273 continue; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 if (!approximately_one_or_less(*lineT)) { | 359 if (!approximately_one_or_less(*lineT)) { |
| 336 return false; | 360 return false; |
| 337 } | 361 } |
| 338 if (!approximately_zero_or_more(*lineT)) { | 362 if (!approximately_zero_or_more(*lineT)) { |
| 339 return false; | 363 return false; |
| 340 } | 364 } |
| 341 double cT = *cubicT = SkPinT(*cubicT); | 365 double cT = *cubicT = SkPinT(*cubicT); |
| 342 double lT = *lineT = SkPinT(*lineT); | 366 double lT = *lineT = SkPinT(*lineT); |
| 343 SkDPoint lPt = fLine.ptAtT(lT); | 367 SkDPoint lPt = fLine.ptAtT(lT); |
| 344 SkDPoint cPt = fCubic.ptAtT(cT); | 368 SkDPoint cPt = fCubic.ptAtT(cT); |
| 345 if (!lPt.moreRoughlyEqual(cPt)) { | 369 if (!lPt.roughlyEqual(cPt)) { |
| 346 return false; | 370 return false; |
| 347 } | 371 } |
| 348 // FIXME: if points are roughly equal but not approximately equal, need
to do | 372 // FIXME: if points are roughly equal but not approximately equal, need
to do |
| 349 // a binary search like quad/quad intersection to find more precise t va
lues | 373 // a binary search like quad/quad intersection to find more precise t va
lues |
| 350 if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT
!= 1)) { | 374 if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT
!= 1)) { |
| 351 *pt = lPt; | 375 *pt = lPt; |
| 352 } else if (ptSet == kPointUninitialized) { | 376 } else if (ptSet == kPointUninitialized) { |
| 353 *pt = cPt; | 377 *pt = cPt; |
| 354 } | 378 } |
| 355 SkPoint gridPt = pt->asSkPoint(); | 379 SkPoint gridPt = pt->asSkPoint(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 } | 418 } |
| 395 | 419 |
| 396 int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { | 420 int SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { |
| 397 LineCubicIntersections c(cubic, line, this); | 421 LineCubicIntersections c(cubic, line, this); |
| 398 fUsed = c.intersectRay(fT[0]); | 422 fUsed = c.intersectRay(fT[0]); |
| 399 for (int index = 0; index < fUsed; ++index) { | 423 for (int index = 0; index < fUsed; ++index) { |
| 400 fPt[index] = cubic.ptAtT(fT[0][index]); | 424 fPt[index] = cubic.ptAtT(fT[0][index]); |
| 401 } | 425 } |
| 402 return fUsed; | 426 return fUsed; |
| 403 } | 427 } |
| OLD | NEW |