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 "SkOpAngle.h" | 8 #include "SkOpAngle.h" |
9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
10 #include "SkPathOpsCurve.h" | 10 #include "SkPathOpsCurve.h" |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 SkOpAngle rhLonger = rh; | 113 SkOpAngle rhLonger = rh; |
114 if ((longer.lengthen(rh) | rhLonger.lengthen(*this)) // lengthen both | 114 if ((longer.lengthen(rh) | rhLonger.lengthen(*this)) // lengthen both |
115 && (fUnorderable || !longer.fUnorderable) | 115 && (fUnorderable || !longer.fUnorderable) |
116 && (rh.fUnorderable || !rhLonger.fUnorderable)) { | 116 && (rh.fUnorderable || !rhLonger.fUnorderable)) { |
117 #if DEBUG_ANGLE | 117 #if DEBUG_ANGLE |
118 bugOut.prepend(" "); | 118 bugOut.prepend(" "); |
119 #endif | 119 #endif |
120 return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonge
r); | 120 return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonge
r); |
121 } | 121 } |
122 } | 122 } |
| 123 SkPath::Verb verb = fSegment->verb(); |
| 124 SkPath::Verb rVerb = rh.fSegment->verb(); |
123 if (y_ry != 0) { // if they aren't coincident, look for a stable cross produ
ct | 125 if (y_ry != 0) { // if they aren't coincident, look for a stable cross produ
ct |
124 // at this point, y's are the same sign, neither is zero | 126 // at this point, y's are the same sign, neither is zero |
125 // and x's are the same sign, or one (or both) is zero | 127 // and x's are the same sign, or one (or both) is zero |
126 double x_ry = x * ry; | 128 double x_ry = x * ry; |
127 double rx_y = rx * y; | 129 double rx_y = rx * y; |
128 if (!fComputed && !rh.fComputed) { | 130 if (!fComputed && !rh.fComputed) { |
129 if (!AlmostEqualUlps(x_ry, rx_y)) { | 131 if (!SkDLine::NearRay(x, y, rx, ry) && x_ry != rx_y) { |
130 return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx
_y); | 132 return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx
_y); |
131 } | 133 } |
132 } else { | 134 } else { |
133 // if the vector was a result of subdividing a curve, see if it is s
table | 135 // if the vector was a result of subdividing a curve, see if it is s
table |
134 bool sloppy1 = x_ry < rx_y; | 136 bool sloppy1 = x_ry < rx_y; |
135 bool sloppy2 = !sloppy1; | 137 bool sloppy2 = !sloppy1; |
136 if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1)) | 138 if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1)) |
137 && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2)) | 139 && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2)) |
138 && sloppy1 != sloppy2) { | 140 && sloppy1 != sloppy2) { |
139 return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1); | 141 return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1); |
140 } | 142 } |
141 } | 143 } |
142 } | 144 } |
143 if (fSide * rh.fSide == 0) { | 145 if (fSide2 * rh.fSide2 == 0) { |
144 SkASSERT(fSide + rh.fSide != 0); // hitting this assert means coincidenc
e was undetected | 146 // SkASSERT(fSide2 + rh.fSide2 != 0); // hitting this assert means coinci
dence was undetected |
145 return COMPARE_RESULT("9 fSide * rh.fSide == 0 ...", fSide < rh.fSide); | 147 return COMPARE_RESULT("9a fSide2 * rh.fSide2 == 0 ...", fSide2 < rh.fSid
e2); |
146 } | 148 } |
147 // at this point, the initial tangent line is nearly coincident | 149 // at this point, the initial tangent line is nearly coincident |
148 // see if edges curl away from each other | 150 // see if edges curl away from each other |
149 if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_ze
ro(rh.fSide))) { | 151 if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_ze
ro(rh.fSide))) { |
150 return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide); | 152 return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide); |
151 } | 153 } |
152 if (fUnsortable || rh.fUnsortable) { | 154 if (fUnsortable || rh.fUnsortable) { |
153 // even with no solution, return a stable sort | 155 // even with no solution, return a stable sort |
154 return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh); | 156 return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh); |
155 } | 157 } |
156 SkPath::Verb verb = fSegment->verb(); | |
157 SkPath::Verb rVerb = rh.fSegment->verb(); | |
158 if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_ze
ro(x)) | 158 if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_ze
ro(x)) |
159 || (rVerb == SkPath::kLine_Verb | 159 || (rVerb == SkPath::kLine_Verb |
160 && approximately_zero(ry) && approximately_zero(rx))) { | 160 && approximately_zero(ry) && approximately_zero(rx))) { |
161 // See general unsortable comment below. This case can happen when | 161 // See general unsortable comment below. This case can happen when |
162 // one line has a non-zero change in t but no change in x and y. | 162 // one line has a non-zero change in t but no change in x and y. |
163 fUnsortable = true; | 163 fUnsortable = true; |
164 return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh); | 164 return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh); |
165 } | 165 } |
166 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) { | 166 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) { |
167 fUnsortable = true; | 167 fUnsortable = true; |
168 return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &r
h); | 168 return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &r
h); |
169 } | 169 } |
170 SkASSERT(verb >= SkPath::kQuad_Verb); | 170 SkASSERT(verb >= SkPath::kQuad_Verb); |
171 SkASSERT(rVerb >= SkPath::kQuad_Verb); | 171 SkASSERT(rVerb >= SkPath::kQuad_Verb); |
172 // FIXME: until I can think of something better, project a ray from the | 172 // FIXME: until I can think of something better, project a ray from the |
173 // end of the shorter tangent to midway between the end points | 173 // end of the shorter tangent to midway between the end points |
174 // through both curves and use the resulting angle to sort | 174 // through both curves and use the resulting angle to sort |
175 // FIXME: some of this setup can be moved to set() if it works, or cached if
it's expensive | 175 // FIXME: some of this setup can be moved to set() if it works, or cached if
it's expensive |
176 double len = fTangent1.normalSquared(); | 176 double len = fTangentPart.normalSquared(); |
177 double rlen = rh.fTangent1.normalSquared(); | 177 double rlen = rh.fTangentPart.normalSquared(); |
178 SkDLine ray; | 178 SkDLine ray; |
179 SkIntersections i, ri; | 179 SkIntersections i, ri; |
180 int roots, rroots; | 180 int roots, rroots; |
181 bool flip = false; | 181 bool flip = false; |
182 bool useThis; | 182 bool useThis; |
183 bool leftLessThanRight = fSide > 0; | 183 bool leftLessThanRight = fSide > 0; |
184 do { | 184 do { |
185 useThis = (len < rlen) ^ flip; | 185 useThis = (len < rlen) ^ flip; |
186 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; | 186 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; |
187 SkPath::Verb partVerb = useThis ? verb : rVerb; | 187 SkPath::Verb partVerb = useThis ? verb : rVerb; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 } | 262 } |
263 | 263 |
264 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) { | 264 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) { |
265 fSegment = segment; | 265 fSegment = segment; |
266 fStart = start; | 266 fStart = start; |
267 fEnd = end; | 267 fEnd = end; |
268 setSpans(); | 268 setSpans(); |
269 } | 269 } |
270 | 270 |
271 void SkOpAngle::setSpans() { | 271 void SkOpAngle::setSpans() { |
272 fUnorderable = false; | 272 fUnorderable = fSegment->isTiny(this); |
273 if (fSegment->verb() == SkPath::kLine_Verb) { | 273 fLastMarked = NULL; |
274 fUnsortable = false; | 274 fUnsortable = false; |
275 } else { | 275 const SkPoint* pts = fSegment->pts(); |
276 // if start-1 exists and is tiny, then start pt may have moved | 276 if (fSegment->verb() != SkPath::kLine_Verb) { |
277 int smaller = SkMin32(fStart, fEnd); | 277 fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart); |
278 int tinyCheck = smaller; | 278 fSegment->subDivide(fStart, fStart < fEnd ? fSegment->count() - 1 : 0, &
fCurveHalf); |
279 while (tinyCheck > 0 && fSegment->isTiny(tinyCheck - 1)) { | |
280 --tinyCheck; | |
281 } | |
282 if ((fUnsortable = smaller > 0 && tinyCheck == 0)) { | |
283 return; | |
284 } | |
285 int larger = SkMax32(fStart, fEnd); | |
286 tinyCheck = larger; | |
287 int max = fSegment->count() - 1; | |
288 while (tinyCheck < max && fSegment->isTiny(tinyCheck + 1)) { | |
289 ++tinyCheck; | |
290 } | |
291 if ((fUnsortable = larger < max && tinyCheck == max)) { | |
292 return; | |
293 } | |
294 } | 279 } |
295 fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart); | |
296 // FIXME: slight errors in subdivision cause sort trouble later on. As an ex
periment, try | 280 // FIXME: slight errors in subdivision cause sort trouble later on. As an ex
periment, try |
297 // rounding the curve part to float precision here | 281 // rounding the curve part to float precision here |
298 // fCurvePart.round(fSegment->verb()); | 282 // fCurvePart.round(fSegment->verb()); |
299 switch (fSegment->verb()) { | 283 switch (fSegment->verb()) { |
300 case SkPath::kLine_Verb: { | 284 case SkPath::kLine_Verb: { |
301 // OPTIMIZATION: for pure line compares, we never need fTangent1.c | 285 SkASSERT(fStart != fEnd); |
302 fTangent1.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart)); | 286 fCurvePart[0].set(pts[fStart > fEnd]); |
| 287 fCurvePart[1].set(pts[fStart < fEnd]); |
| 288 fComputed = false; |
| 289 // OPTIMIZATION: for pure line compares, we never need fTangentPart.c |
| 290 fTangentPart.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart)); |
303 fSide = 0; | 291 fSide = 0; |
| 292 fSide2 = 0; |
304 } break; | 293 } break; |
305 case SkPath::kQuad_Verb: { | 294 case SkPath::kQuad_Verb: { |
| 295 fSide2 = -fTangentHalf.quadPart(*SkTCast<SkDQuad*>(&fCurveHalf)); |
306 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); | 296 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); |
307 fTangent1.quadEndPoints(quad); | 297 fTangentPart.quadEndPoints(quad); |
308 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- c
ompare sign only | 298 fSide = -fTangentPart.pointDistance(fCurvePart[2]); // not normalized -
- compare sign only |
309 if (fComputed && dx() > 0 && approximately_zero(dy())) { | 299 if (fComputed && dx() > 0 && approximately_zero(dy())) { |
310 SkDCubic origCurve; // can't use segment's curve in place since it m
ay be flipped | 300 SkDCubic origCurve; // can't use segment's curve in place since it m
ay be flipped |
311 int last = fSegment->count() - 1; | 301 int last = fSegment->count() - 1; |
312 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last :
0, &origCurve); | 302 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last :
0, &origCurve); |
313 SkLineParameters origTan; | 303 SkLineParameters origTan; |
314 origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve)); | 304 origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve)); |
315 if ((fUnorderable = origTan.dx() <= 0 | 305 if (origTan.dx() <= 0 |
316 || (dy() != origTan.dy() && dy() * origTan.dy() <= 0))) { //
signs match? | 306 || (dy() != origTan.dy() && dy() * origTan.dy() <= 0)) { //
signs match? |
| 307 fUnorderable = true; |
317 return; | 308 return; |
318 } | 309 } |
319 } | 310 } |
320 } break; | 311 } break; |
321 case SkPath::kCubic_Verb: { | 312 case SkPath::kCubic_Verb: { |
322 fTangent1.cubicEndPoints(fCurvePart); | 313 double startT = fSegment->t(fStart); |
| 314 fSide2 = -fTangentHalf.cubicPart(fCurveHalf); |
| 315 fTangentPart.cubicEndPoints(fCurvePart); |
323 double testTs[4]; | 316 double testTs[4]; |
324 // OPTIMIZATION: keep inflections precomputed with cubic segment? | 317 // OPTIMIZATION: keep inflections precomputed with cubic segment? |
325 const SkPoint* pts = fSegment->pts(); | |
326 int testCount = SkDCubic::FindInflections(pts, testTs); | 318 int testCount = SkDCubic::FindInflections(pts, testTs); |
327 double startT = fSegment->t(fStart); | |
328 double endT = fSegment->t(fEnd); | 319 double endT = fSegment->t(fEnd); |
329 double limitT = endT; | 320 double limitT = endT; |
330 int index; | 321 int index; |
331 for (index = 0; index < testCount; ++index) { | 322 for (index = 0; index < testCount; ++index) { |
332 if (!between(startT, testTs[index], limitT)) { | 323 if (!between(startT, testTs[index], limitT)) { |
333 testTs[index] = -1; | 324 testTs[index] = -1; |
334 } | 325 } |
335 } | 326 } |
336 testTs[testCount++] = startT; | 327 testTs[testCount++] = startT; |
337 testTs[testCount++] = endT; | 328 testTs[testCount++] = endT; |
338 SkTQSort<double>(testTs, &testTs[testCount - 1]); | 329 SkTQSort<double>(testTs, &testTs[testCount - 1]); |
339 double bestSide = 0; | 330 double bestSide = 0; |
340 int testCases = (testCount << 1) - 1; | 331 int testCases = (testCount << 1) - 1; |
341 index = 0; | 332 index = 0; |
342 while (testTs[index] < 0) { | 333 while (testTs[index] < 0) { |
343 ++index; | 334 ++index; |
344 } | 335 } |
345 index <<= 1; | 336 index <<= 1; |
346 for (; index < testCases; ++index) { | 337 for (; index < testCases; ++index) { |
347 int testIndex = index >> 1; | 338 int testIndex = index >> 1; |
348 double testT = testTs[testIndex]; | 339 double testT = testTs[testIndex]; |
349 if (index & 1) { | 340 if (index & 1) { |
350 testT = (testT + testTs[testIndex + 1]) / 2; | 341 testT = (testT + testTs[testIndex + 1]) / 2; |
351 } | 342 } |
352 // OPTIMIZE: could avoid call for t == startT, endT | 343 // OPTIMIZE: could avoid call for t == startT, endT |
353 SkDPoint pt = dcubic_xy_at_t(pts, testT); | 344 SkDPoint pt = dcubic_xy_at_t(pts, testT); |
354 double testSide = fTangent1.pointDistance(pt); | 345 double testSide = fTangentPart.pointDistance(pt); |
355 if (fabs(bestSide) < fabs(testSide)) { | 346 if (fabs(bestSide) < fabs(testSide)) { |
356 bestSide = testSide; | 347 bestSide = testSide; |
357 } | 348 } |
358 } | 349 } |
359 fSide = -bestSide; // compare sign only | 350 fSide = -bestSide; // compare sign only |
| 351 SkASSERT(fSide == 0 || fSide2 != 0); |
360 if (fComputed && dx() > 0 && approximately_zero(dy())) { | 352 if (fComputed && dx() > 0 && approximately_zero(dy())) { |
361 SkDCubic origCurve; // can't use segment's curve in place since it m
ay be flipped | 353 SkDCubic origCurve; // can't use segment's curve in place since it m
ay be flipped |
362 int last = fSegment->count() - 1; | 354 int last = fSegment->count() - 1; |
363 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last :
0, &origCurve); | 355 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last :
0, &origCurve); |
364 SkLineParameters origTan; | 356 SkDCubicPair split = origCurve.chopAt(startT); |
365 origTan.cubicEndPoints(origCurve); | 357 SkLineParameters splitTan; |
366 if ((fUnorderable = origTan.dx() <= 0)) { | 358 splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first
()); |
| 359 if (splitTan.dx() <= 0) { |
| 360 fUnorderable = true; |
367 fUnsortable = fSegment->isTiny(this); | 361 fUnsortable = fSegment->isTiny(this); |
368 return; | 362 return; |
369 } | 363 } |
370 // if one is < 0 and the other is >= 0 | 364 // if one is < 0 and the other is >= 0 |
371 if ((fUnorderable = (dy() < 0) ^ (origTan.dy() < 0))) { | 365 if (dy() * splitTan.dy() < 0) { |
| 366 fUnorderable = true; |
372 fUnsortable = fSegment->isTiny(this); | 367 fUnsortable = fSegment->isTiny(this); |
373 return; | 368 return; |
374 } | 369 } |
375 SkDCubicPair split = origCurve.chopAt(startT); | |
376 SkLineParameters splitTan; | |
377 splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first
()); | |
378 if ((fUnorderable = splitTan.dx() <= 0)) { | |
379 fUnsortable = fSegment->isTiny(this); | |
380 return; | |
381 } | |
382 // if one is < 0 and the other is >= 0 | |
383 if ((fUnorderable = (dy() < 0) ^ (splitTan.dy() < 0))) { | |
384 fUnsortable = fSegment->isTiny(this); | |
385 return; | |
386 } | |
387 } | 370 } |
388 } break; | 371 } break; |
389 default: | 372 default: |
390 SkASSERT(0); | 373 SkASSERT(0); |
391 } | 374 } |
392 if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) { | 375 if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) { |
393 return; | 376 return; |
394 } | 377 } |
| 378 if (fSegment->verb() == SkPath::kLine_Verb) { |
| 379 return; |
| 380 } |
395 SkASSERT(fStart != fEnd); | 381 SkASSERT(fStart != fEnd); |
396 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 t
ype macro? | 382 int smaller = SkMin32(fStart, fEnd); |
397 for (int index = fStart; index != fEnd; index += step) { | 383 int larger = SkMax32(fStart, fEnd); |
398 #if 1 | 384 while (smaller < larger && fSegment->span(smaller).fTiny) { |
399 const SkOpSpan& thisSpan = fSegment->span(index); | 385 ++smaller; |
400 const SkOpSpan& nextSpan = fSegment->span(index + step); | 386 } |
401 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) { | 387 if (precisely_equal(fSegment->span(smaller).fT, fSegment->span(larger).fT))
{ |
402 continue; | 388 #if DEBUG_UNSORTABLE |
403 } | 389 SkPoint iPt = fSegment->xyAtT(fStart); |
404 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortabl
eEnd; | 390 SkPoint ePt = fSegment->xyAtT(fEnd); |
| 391 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n
", __FUNCTION__, |
| 392 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); |
| 393 #endif |
| 394 fUnsortable = true; |
| 395 return; |
| 396 } |
| 397 fUnsortable = fStart < fEnd ? fSegment->span(smaller).fUnsortableStart |
| 398 : fSegment->span(larger).fUnsortableEnd; |
405 #if DEBUG_UNSORTABLE | 399 #if DEBUG_UNSORTABLE |
406 if (fUnsortable) { | 400 if (fUnsortable) { |
407 SkPoint iPt = fSegment->xyAtT(index); | 401 SkPoint iPt = fSegment->xyAtT(smaller); |
408 SkPoint ePt = fSegment->xyAtT(index + step); | 402 SkPoint ePt = fSegment->xyAtT(larger); |
409 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __
FUNCTION__, | 403 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNC
TION__, |
410 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); | 404 smaller, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); |
411 } | 405 } |
412 #endif | 406 #endif |
413 return; | 407 return; |
414 #else | 408 } |
415 if ((*fSpans)[index].fUnsortableStart) { | 409 |
416 fUnsortable = true; | 410 #ifdef SK_DEBUG |
417 return; | 411 void SkOpAngle::dump() const { |
418 } | 412 SkDebugf("id=%d (%1.9g,%1.9g) start=%d (%1.9g) end=%d (%1.9g)\n", fSegment->
debugID(), |
| 413 fSegment->xAtT(fStart), fSegment->yAtT(fStart), fStart, fSegment->sp
an(fStart).fT, |
| 414 fEnd, fSegment->span(fEnd).fT); |
| 415 } |
419 #endif | 416 #endif |
420 } | |
421 #if 1 | |
422 #if DEBUG_UNSORTABLE | |
423 SkPoint iPt = fSegment->xyAtT(fStart); | |
424 SkPoint ePt = fSegment->xyAtT(fEnd); | |
425 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _
_FUNCTION__, | |
426 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); | |
427 #endif | |
428 fUnsortable = true; | |
429 #endif | |
430 } | |
OLD | NEW |