46 /* huge circle with radius ~ 2E9 only needs 12 subdivision levels */ |
46 /* huge circle with radius ~ 2E9 only needs 12 subdivision levels */ |
47 static final int REC_LIMIT = 16; |
47 static final int REC_LIMIT = 16; |
48 static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 |
48 static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 |
49 static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT); |
49 static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT); |
50 |
50 |
|
51 static final float EPS = 1e-6f; |
|
52 |
51 // More than 24 bits of mantissa means we can no longer accurately |
53 // More than 24 bits of mantissa means we can no longer accurately |
52 // measure the number of times cycled through the dash array so we |
54 // measure the number of times cycled through the dash array so we |
53 // punt and override the phase to just be 0 past that point. |
55 // punt and override the phase to just be 0 past that point. |
54 static final float MAX_CYCLES = 16000000.0f; |
56 static final float MAX_CYCLES = 16000000.0f; |
55 |
57 |
268 } |
270 } |
269 } |
271 } |
270 |
272 |
271 private void emitSeg(float[] buf, int off, int type) { |
273 private void emitSeg(float[] buf, int off, int type) { |
272 switch (type) { |
274 switch (type) { |
|
275 case 4: |
|
276 out.lineTo(buf[off], buf[off + 1]); |
|
277 return; |
273 case 8: |
278 case 8: |
274 out.curveTo(buf[off ], buf[off + 1], |
279 out.curveTo(buf[off ], buf[off + 1], |
275 buf[off + 2], buf[off + 3], |
280 buf[off + 2], buf[off + 3], |
276 buf[off + 4], buf[off + 5]); |
281 buf[off + 4], buf[off + 5]); |
277 return; |
282 return; |
278 case 6: |
283 case 6: |
279 out.quadTo(buf[off ], buf[off + 1], |
284 out.quadTo(buf[off ], buf[off + 1], |
280 buf[off + 2], buf[off + 3]); |
285 buf[off + 2], buf[off + 3]); |
281 return; |
286 return; |
282 case 4: |
|
283 out.lineTo(buf[off], buf[off + 1]); |
|
284 return; |
|
285 default: |
287 default: |
286 } |
288 } |
287 } |
289 } |
288 |
290 |
289 private void emitFirstSegments() { |
291 private void emitFirstSegments() { |
360 if (orCode != 0) { |
362 if (orCode != 0) { |
361 final int sideCode = outcode0 & outcode1; |
363 final int sideCode = outcode0 & outcode1; |
362 |
364 |
363 // basic rejection criteria: |
365 // basic rejection criteria: |
364 if (sideCode == 0) { |
366 if (sideCode == 0) { |
365 // ovelap clip: |
367 // overlap clip: |
366 if (subdivide) { |
368 if (subdivide) { |
367 // avoid reentrance |
369 // avoid reentrance |
368 subdivide = false; |
370 subdivide = false; |
369 // subdivide curve => callback with subdivided parts: |
371 // subdivide curve => callback with subdivided parts: |
370 boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1, |
372 boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1, |
415 |
417 |
416 int _idx = idx; |
418 int _idx = idx; |
417 boolean _dashOn = dashOn; |
419 boolean _dashOn = dashOn; |
418 float _phase = phase; |
420 float _phase = phase; |
419 |
421 |
420 float leftInThisDashSegment, d; |
422 float leftInThisDashSegment, rem; |
421 |
423 |
422 while (true) { |
424 while (true) { |
423 d = _dash[_idx]; |
425 leftInThisDashSegment = _dash[_idx] - _phase; |
424 leftInThisDashSegment = d - _phase; |
426 rem = len - leftInThisDashSegment; |
425 |
427 |
426 if (len <= leftInThisDashSegment) { |
428 if (rem <= EPS) { |
427 _curCurvepts[0] = x1; |
429 _curCurvepts[0] = x1; |
428 _curCurvepts[1] = y1; |
430 _curCurvepts[1] = y1; |
429 |
431 |
430 goTo(_curCurvepts, 0, 4, _dashOn); |
432 goTo(_curCurvepts, 0, 4, _dashOn); |
431 |
433 |
432 // Advance phase within current dash segment |
434 // Advance phase within current dash segment |
433 _phase += len; |
435 _phase += len; |
434 |
436 |
435 // TODO: compare float values using epsilon: |
437 // compare values using epsilon: |
436 if (len == leftInThisDashSegment) { |
438 if (Math.abs(rem) <= EPS) { |
437 _phase = 0.0f; |
439 _phase = 0.0f; |
438 _idx = (_idx + 1) % _dashLen; |
440 _idx = (_idx + 1) % _dashLen; |
439 _dashOn = !_dashOn; |
441 _dashOn = !_dashOn; |
440 } |
442 } |
441 break; |
443 break; |
442 } |
444 } |
443 |
445 |
444 if (_phase == 0.0f) { |
446 _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; |
445 _curCurvepts[0] = cx0 + d * cx; |
447 _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; |
446 _curCurvepts[1] = cy0 + d * cy; |
|
447 } else { |
|
448 _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; |
|
449 _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; |
|
450 } |
|
451 |
448 |
452 goTo(_curCurvepts, 0, 4, _dashOn); |
449 goTo(_curCurvepts, 0, 4, _dashOn); |
453 |
450 |
454 len -= leftInThisDashSegment; |
451 len = rem; |
455 // Advance to next dash segment |
452 // Advance to next dash segment |
456 _idx = (_idx + 1) % _dashLen; |
453 _idx = (_idx + 1) % _dashLen; |
457 _dashOn = !_dashOn; |
454 _dashOn = !_dashOn; |
458 _phase = 0.0f; |
455 _phase = 0.0f; |
459 } |
456 } |
505 final long iterations = fullcycles * _dashLen; |
502 final long iterations = fullcycles * _dashLen; |
506 _idx = (int) (iterations + _idx) % _dashLen; |
503 _idx = (int) (iterations + _idx) % _dashLen; |
507 _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L; |
504 _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L; |
508 } |
505 } |
509 |
506 |
510 float leftInThisDashSegment, d; |
507 float leftInThisDashSegment, rem; |
511 |
508 |
512 while (true) { |
509 while (true) { |
513 d = _dash[_idx]; |
510 leftInThisDashSegment = _dash[_idx] - _phase; |
514 leftInThisDashSegment = d - _phase; |
511 rem = len - leftInThisDashSegment; |
515 |
512 |
516 if (len <= leftInThisDashSegment) { |
513 if (rem <= EPS) { |
517 // Advance phase within current dash segment |
514 // Advance phase within current dash segment |
518 _phase += len; |
515 _phase += len; |
519 |
516 |
520 // TODO: compare float values using epsilon: |
517 // compare values using epsilon: |
521 if (len == leftInThisDashSegment) { |
518 if (Math.abs(rem) <= EPS) { |
522 _phase = 0.0f; |
519 _phase = 0.0f; |
523 _idx = (_idx + 1) % _dashLen; |
520 _idx = (_idx + 1) % _dashLen; |
524 _dashOn = !_dashOn; |
521 _dashOn = !_dashOn; |
525 } |
522 } |
526 break; |
523 break; |
527 } |
524 } |
528 |
525 |
529 len -= leftInThisDashSegment; |
526 len = rem; |
530 // Advance to next dash segment |
527 // Advance to next dash segment |
531 _idx = (_idx + 1) % _dashLen; |
528 _idx = (_idx + 1) % _dashLen; |
532 _dashOn = !_dashOn; |
529 _dashOn = !_dashOn; |
533 _phase = 0.0f; |
530 _phase = 0.0f; |
534 } |
531 } |
578 } |
575 } |
579 |
576 |
580 goTo(_curCurvepts, curCurveoff + 2, type, _dashOn); |
577 goTo(_curCurvepts, curCurveoff + 2, type, _dashOn); |
581 |
578 |
582 _phase += _li.lastSegLen(); |
579 _phase += _li.lastSegLen(); |
583 if (_phase >= _dash[_idx]) { |
580 |
|
581 // compare values using epsilon: |
|
582 if (_phase + EPS >= _dash[_idx]) { |
584 _phase = 0.0f; |
583 _phase = 0.0f; |
585 _idx = (_idx + 1) % _dashLen; |
584 _idx = (_idx + 1) % _dashLen; |
586 _dashOn = !_dashOn; |
585 _dashOn = !_dashOn; |
587 } |
586 } |
588 // Save local state: |
587 // Save local state: |
937 if (orCode != 0) { |
936 if (orCode != 0) { |
938 final int sideCode = outcode0 & outcode1 & outcode2 & outcode3; |
937 final int sideCode = outcode0 & outcode1 & outcode2 & outcode3; |
939 |
938 |
940 // basic rejection criteria: |
939 // basic rejection criteria: |
941 if (sideCode == 0) { |
940 if (sideCode == 0) { |
942 // ovelap clip: |
941 // overlap clip: |
943 if (subdivide) { |
942 if (subdivide) { |
944 // avoid reentrance |
943 // avoid reentrance |
945 subdivide = false; |
944 subdivide = false; |
946 // subdivide curve => callback with subdivided parts: |
945 // subdivide curve => callback with subdivided parts: |
947 boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1, x2, y2, x3, y3, |
946 boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1, x2, y2, x3, y3, |
1023 if (orCode != 0) { |
1022 if (orCode != 0) { |
1024 final int sideCode = outcode0 & outcode1 & outcode2; |
1023 final int sideCode = outcode0 & outcode1 & outcode2; |
1025 |
1024 |
1026 // basic rejection criteria: |
1025 // basic rejection criteria: |
1027 if (sideCode == 0) { |
1026 if (sideCode == 0) { |
1028 // ovelap clip: |
1027 // overlap clip: |
1029 if (subdivide) { |
1028 if (subdivide) { |
1030 // avoid reentrance |
1029 // avoid reentrance |
1031 subdivide = false; |
1030 subdivide = false; |
1032 // subdivide curve => call lineTo() with subdivided curves: |
1031 // subdivide curve => call lineTo() with subdivided curves: |
1033 boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1, |
1032 boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1, |