1 /* *****************************************************************************
2 Anti-Grain Geometry - Version 2.1 Lite
3 Copyright (C) 2002-2003 Maxim Shemanarev (McSeem)
4 D port, additional work: Ketmar Dark
6 Permission to copy, use, modify, sell and distribute this software
7 is granted provided this copyright notice appears in all copies.
8 This software is provided "as is" without express or implied
9 warranty, and with no claim as to its suitability for any purpose.
11 The author gratefully acknowleges the support of David Turner,
12 Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
13 libray - in producing this work. See http://www.freetype.org for details.
15 Initially the rendering algorithm was designed by David Turner and the
16 other authors of the FreeType library - see the above notice. I nearly
17 created a similar renderer, but still I was far from David's work.
18 I completely redesigned the original code and adapted it for Anti-Grain
19 ideas. Two functions - renderLine and renderScanLine are the core of
20 the algorithm - they calculate the exact coverage of each pixel cell
21 of the polygon. I left these functions almost as is, because there's
22 no way to improve the perfection - hats off to David and his group!
24 All other code is very different from the original.
25 ***************************************************************************** */
26 module iv
.egra
.gfx
.aggmini
;
30 private enum DisableCopyingMixin
= "@disable this (this); void opAssign() (in auto ref typeof(this)) { static assert(0, `assigning disabled`); }";
32 import iv
.egra
.gfx
.base
;
33 import iv
.egra
.gfx
.lowlevel
;
35 /* Bezier curve rasterizer.
37 * De Casteljau Bezier rasterizer is faster, but currently rasterizing curves with cusps sligtly wrong.
38 * It doesn't really matter in practice.
40 * AFD tesselator is somewhat slower, but does cusps better.
42 * McSeem rasterizer should have the best quality, bit it is the slowest method. Basically, you will
43 * never notice any visial difference (and this code is not really debugged), so you probably should
44 * not use it. It is there for further experiments.
46 public enum AGGTesselation
{
47 DeCasteljau
, /// default: standard well-known tesselation algorithm
48 AFD
, /// adaptive forward differencing
49 DeCasteljauMcSeem
, /// standard well-known tesselation algorithm, with improvements from Maxim Shemanarev; slowest one, but should give best results
52 // Default tesselator for Bezier curves.
53 //public __gshared AGGTesselation AGGDefaultTesselator = AGGTesselation.DeCasteljau;
56 // ////////////////////////////////////////////////////////////////////////// //
58 align(1) struct Cell
{
61 static uint packCoord (in int x
, in int y
) pure nothrow @safe @nogc { pragma(inline
, true); return (y
<<16)|
(x
&0xffff); }
68 public nothrow @trusted @nogc:
69 this (in int cx
, in int cy
, in int c
, in int a
) pure { pragma(inline
, true); packedCoord
= packCoord(cx
, cy
); cover
= c
; area
= a
; }
71 @property int x () const pure { pragma(inline
, true); return cast(short)(packedCoord
&0xffff); }
72 @property int y () const pure { pragma(inline
, true); return cast(short)(packedCoord
>>16); }
74 void setCover (in int c
, in int a
) { pragma(inline
, true); cover
= c
; area
= a
; }
75 void addCover (in int c
, in int a
) { pragma(inline
, true); cover
+= c
; area
+= a
; }
77 void setCoord (in int cx
, in int cy
) { pragma(inline
, true); packedCoord
= packCoord(cx
, cy
); }
79 void set (in int cx
, in int cy
, in int c
, in int a
) { pragma(inline
, true); packedCoord
= packCoord(cx
, cy
); cover
= c
; area
= a
; }
83 // ////////////////////////////////////////////////////////////////////////// //
84 /* An internal class that implements the main rasterization algorithm.
85 Used in the rasterizer. Should not be used direcly.
88 private nothrow @trusted @nogc:
91 CellBlockSize
= cast(uint)(1<<CellBlockShift
),
92 CellBlockMask
= cast(uint)(CellBlockSize
-1),
94 CellBlockLimit
= 1024U,
97 enum QSortThreshold
= 9;
113 Cell mCurCell
= Cell(0x7fff, 0x7fff, 0, 0);
118 int mMinX
= 0x7fffffff;
119 int mMinY
= 0x7fffffff;
120 int mMaxX
= -0x7fffffff;
121 int mMaxY
= -0x7fffffff;
122 uint mFlags
= SortRequired
;
125 void allocateBlock () {
126 import core
.stdc
.stdlib
: realloc
;
127 if (mCurBlock
>= mNumBlocks
) {
128 import core
.stdc
.string
: memset
;
129 if (mNumBlocks
>= mMaxBlocks
) {
130 Cell
** newCells
= cast(Cell
**)realloc(mCells
, (mMaxBlocks
+CellBlockPool
)*(Cell
*).sizeof
);
131 if (newCells
is null) assert(0, "out of memory");
133 mMaxBlocks
+= CellBlockPool
;
135 auto cc
= cast(Cell
*)realloc(null, Cell
.sizeof
*CellBlockSize
);
136 if (cc
is null) assert(0, "out of memory");
137 memset(cc
, 0, Cell
.sizeof
*CellBlockSize
);
138 //foreach (ref c; cc[0..CellBlockSize]) c = Cell.init;
139 mCells
[mNumBlocks
++] = cc
;
141 mCurCellPtr
= mCells
[mCurBlock
++];
145 mixin(DisableCopyingMixin
);
148 import core
.stdc
.stdlib
: free
;
151 Cell
** ptr
= mCells
+mNumBlocks
-1;
152 while (mNumBlocks
--) {
163 mCurCell
.set(0x7fff, 0x7fff, 0, 0);
164 mFlags |
= SortRequired
;
165 mFlags
&= ~NotClosed
;
172 void moveTo (in int x
, in int y
) {
173 if ((mFlags
&SortRequired
) == 0) reset();
174 if (mFlags
&NotClosed
) lineTo(mCloseX
, mCloseY
);
175 setCurCell(x
>>PolyBaseShift
, y
>>PolyBaseShift
);
180 void lineTo (in int x
, in int y
) {
181 if ((mFlags
&SortRequired
) && ((mCurX^x
)|
(mCurY^y
))) {
182 int c
= mCurX
>>PolyBaseShift
;
183 if (c
< mMinX
) mMinX
= c
;
185 if (c
> mMaxX
) mMaxX
= c
;
187 c
= x
>>PolyBaseShift
;
188 if (c
< mMinX
) mMinX
= c
;
190 if (c
> mMaxX
) mMaxX
= c
;
192 renderLine(mCurX
, mCurY
, x
, y
);
199 @property float currX () const pure { pragma(inline
, true); return cast(float)mCurX
/cast(float)PolyBaseSize
; }
200 @property float currY () const pure { pragma(inline
, true); return cast(float)mCurY
/cast(float)PolyBaseSize
; }
202 @property int minX () const pure { pragma(inline
, true); return mMinX
; }
203 @property int minY () const pure { pragma(inline
, true); return mMinY
; }
204 @property int maxX () const pure { pragma(inline
, true); return mMaxX
; }
205 @property int maxY () const pure { pragma(inline
, true); return mMaxY
; }
207 @property uint numCells () const pure { pragma(inline
, true); return mNumCells
; }
209 const(Cell
)** cells () {
210 if (mFlags
&NotClosed
) {
211 lineTo(mCloseX
, mCloseY
);
212 mFlags
&= ~NotClosed
;
214 // perform sort only the first time
215 if (mFlags
&SortRequired
) {
217 if (mNumCells
== 0) return null;
219 mFlags
&= ~SortRequired
;
221 return cast(const(Cell
)**)mSortedCells
;
226 if (mCurCell
.area|mCurCell
.cover
) {
227 if ((mNumCells
&CellBlockMask
) == 0) {
228 if (mNumBlocks
>= CellBlockLimit
) return;
231 *mCurCellPtr
++ = mCurCell
;
236 void setCurCell (in int x
, in int y
) {
237 if (mCurCell
.packedCoord
!= Cell
.packCoord(x
, y
)) {
239 mCurCell
.set(x
, y
, 0, 0);
243 void renderScanLine (in int ey
, in int x1
, int y1
, in int x2
, in int y2
) {
244 immutable int ex2
= x2
>>PolyBaseShift
;
246 // trivial case; happens often
252 int ex1
= x1
>>PolyBaseShift
;
253 immutable int fx1
= x1
&PolyBaseMask
;
254 immutable int fx2
= x2
&PolyBaseMask
;
256 // everything is located in a single cell: that is easy!
258 immutable int delta
= y2
-y1
;
259 mCurCell
.addCover(delta
, (fx1
+fx2
)*delta
);
263 // ok, we'll have to render a run of adjacent cells on the same scanline...
264 int p
= (PolyBaseSize
-fx1
)*(y2
-y1
);
265 int first
= PolyBaseSize
;
279 if (mod
< 0) { --delta
; mod
+= dx
; }
281 mCurCell
.addCover(delta
, (fx1
+first
)*delta
);
288 p
= PolyBaseSize
*(y2
-y1
+delta
);
291 if (rem
< 0) { --lift
; rem
+= dx
; }
296 if (mod
>= 0) { mod
-= dx
; ++delta
; }
297 mCurCell
.addCover(delta
, PolyBaseSize
*delta
);
305 mCurCell
.addCover(delta
, (fx2
+PolyBaseSize
-first
)*delta
);
308 void renderLine (in int x1
, in int y1
, in int x2
, in int y2
) {
309 int ey1
= y1
>>PolyBaseShift
;
310 immutable int ey2
= y2
>>PolyBaseShift
;
312 if (ey1
< mMinY
) mMinY
= ey1
;
313 if (ey1
+1 > mMaxY
) mMaxY
= ey1
+1;
314 if (ey2
< mMinY
) mMinY
= ey2
;
315 if (ey2
+1 > mMaxY
) mMaxY
= ey2
+1;
317 immutable int fy1
= y1
&PolyBaseMask
;
318 immutable int fy2
= y2
&PolyBaseMask
;
320 // everything is on a single scanline
322 renderScanLine(ey1
, x1
, fy1
, x2
, fy2
);
330 //int p, rem, mod, lift, delta, first, incr;
332 // vertical line: we have to calculate start and end cells,
333 // and then the common values of the area and coverage for
334 // all cells of the line. we know exactly there's only one
335 // cell, so, we don't have to call renderScanLine().
338 int ex
= x1
>>PolyBaseShift
;
339 int twoFx
= (x1
-(ex
<<PolyBaseShift
))<<1;
342 int first
= PolyBaseSize
;
343 if (dy
< 0) { first
= 0; incr
= -1; }
345 immutable int xFrom
= x1
;
347 //renderScanLine(ey1, xFrom, fy1, xFrom, first);
348 int delta
= first
-fy1
;
349 mCurCell
.addCover(delta
, twoFx
*delta
);
354 delta
= first
+first
-PolyBaseSize
;
357 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, first);
358 mCurCell
.setCover(delta
, area
);
362 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, fy2);
363 delta
= fy2
-PolyBaseSize
+first
;
364 mCurCell
.addCover(delta
, twoFx
*delta
);
368 // ok, we have to render several scanlines
369 int p
= (PolyBaseSize
-fy1
)*dx
;
370 int first
= PolyBaseSize
;
382 if (mod
< 0) { --delta
; mod
+= dy
; }
384 int xFrom
= x1
+delta
;
385 renderScanLine(ey1
, x1
, fy1
, xFrom
, first
);
388 setCurCell(xFrom
>>PolyBaseShift
, ey1
);
395 if (rem
< 0) { --lift
; rem
+= dy
; }
401 if (mod
>= 0) { mod
-= dy
; ++delta
; }
403 immutable int xTo
= xFrom
+delta
;
404 renderScanLine(ey1
, xFrom
, PolyBaseSize
-first
, xTo
, first
);
408 setCurCell(xFrom
>>PolyBaseShift
, ey1
);
412 renderScanLine(ey1
, xFrom
, PolyBaseSize
-first
, x2
, fy2
);
416 static void qsortCells (Cell
** start
, uint num
) {
417 static void swapCells (Cell
** a
, Cell
** b
) nothrow @trusted @nogc {
418 pragma(inline
, true);
424 static bool lessThan (Cell
** a
, Cell
** b
) nothrow @trusted @nogc pure { pragma(inline
, true); return ((**a
).packedCoord
< (**b
).packedCoord
); }
426 Cell
**[80] stack
= void;
436 immutable int len
= cast(int)(limit
-base
);
438 if (len
> QSortThreshold
) {
439 // we use base + len/2 as the pivot
440 auto pivot
= base
+len
/2;
441 swapCells(base
, pivot
);
446 // now ensure that *i <= *base <= *j
447 if (lessThan(j
, i
)) swapCells(i
, j
);
448 if (lessThan(base
, i
)) swapCells(base
, i
);
449 if (lessThan(j
, base
)) swapCells(base
, j
);
452 do { ++i
; } while (lessThan(i
, base
));
453 do { --j
; } while (lessThan(base
, j
));
460 // now, push the largest sub-array
461 if (j
-base
> limit
-i
) {
472 // the sub-array is small, perform insertion sort
475 for (; i
< limit
; j
= i
, ++i
) {
476 for (; lessThan(j
+1, j
); --j
) {
478 if (j
== base
) break;
481 if (top
> stack
.ptr
) {
493 if (mNumCells
== 0) return;
495 if (mNumCells
> mSortedSize
) {
496 import core
.stdc
.stdlib
: realloc
;
497 mSortedSize
= mNumCells
;
498 mSortedCells
= cast(Cell
**)realloc(mSortedCells
, (mNumCells
+1)*(Cell
*).sizeof
);
501 Cell
** sortedPtr
= mSortedCells
;
502 Cell
** blockPtr
= mCells
;
505 uint nb
= mNumCells
>>CellBlockShift
;
508 cellPtr
= *blockPtr
++;
509 uint i
= CellBlockSize
;
510 while (i
--) *sortedPtr
++ = cellPtr
++;
513 cellPtr
= *blockPtr
++;
514 uint i
= mNumCells
&CellBlockMask
;
515 while (i
--) *sortedPtr
++ = cellPtr
++;
516 mSortedCells
[mNumCells
] = null;
517 qsortCells(mSortedCells
, mNumCells
);
522 // ////////////////////////////////////////////////////////////////////////// //
523 /*This class is used to transfer data from class outline (or a similar one)
524 to the rendering buffer. It's organized very simple. The class stores
525 information of horizontal spans to render it into a pixel-map buffer.
526 Each span has initial X, length, and an array of bytes that determine the
527 alpha-values for each pixel. So, the restriction of using this class is 256
528 levels of Anti-Aliasing, which is quite enough for any practical purpose.
529 Before using this class you should know the minimal and maximal pixel
530 coordinates of your scanline. The protocol of using is:
532 2. addCell() / addSpan() - accumulate scanline. You pass Y-coordinate
533 into these functions in order to make scanline know the last Y. Before
534 calling addCell() / addSpan() you should check with method isReady(y)
535 if the last Y has changed. It also checks if the scanline is not empty.
536 When forming one scanline the next X coordinate must be always greater
537 than the last stored one, i.e. it works only with ordered coordinates.
538 3. If the current scanline isReady() you should render it and then call
539 resetSpans() before adding new cells/spans.
543 Scanline provides an iterator class that allows you to extract
544 the spans and the cover values for each pixel. Be aware that clipping
545 has not been done yet, so you should perform it yourself.
547 -------------------------------------------------------------------------
548 int baseX = sl.baseX; // base X. Should be added to the span's X
549 // "sl" is a const reference to the
550 // scanline passed in.
552 int y = sl.y; // Y-coordinate of the scanline
554 ************************************
555 ...Perform vertical clipping here...
556 ************************************
558 ubyte* row = mRBuf[y]; // the the address of the beginning of the current row
560 auto span = scanline.iterator;
562 uint spanCount = scanline.spanCount(); // number of spans; it's guaranteed that
563 // spanCount is always greater than 0
566 int x = span.next+baseX; // the beginning X of the span
568 const(ubyte)* covers = span.covers; // the array of the cover values
570 int pixelCount = span.pixelCount; // number of pixels of the span;
571 // always greater than 0, still we
572 // shoud use "int" instead of "uint"
573 // because it's more convenient for clipping
575 **************************************
576 ...Perform horizontal clipping here...
577 ...you have x, covers, and pixCount..
578 **************************************
580 ubyte* dst = row+x; // calculate the start address of the row;
581 // in this case we assume a simple
582 // grayscale image 1-byte per pixel
584 *dst++ = *covers++; // hypotetical rendering
585 } while (--pixelCount);
586 } while (--spanCount); // spanCount cannot be 0, so this loop is quite safe
587 ------------------------------------------------------------------------
589 The question is: why should we accumulate the whole scanline when we
590 could render just separate spans when they're ready?
591 That's because using the scaline is in general faster. When is consists
592 of more than one span the conditions for the processor cash system
593 are better, because switching between two different areas of memory
594 (that can be large ones) occures less frequently.
608 ubyte** mCurStartPtr
;
614 static struct Iterator
{
616 const(ubyte)* mCovers
;
617 const(ushort)* mCurCount
;
618 const(ubyte*)* mCurStartPtr
;
620 public nothrow @trusted @nogc:
621 mixin(DisableCopyingMixin
);
623 this (in ref ScanLine sl
) pure {
624 pragma(inline
, true);
625 mCovers
= sl
.mCovers
;
626 mCurCount
= sl
.mCounts
;
627 mCurStartPtr
= sl
.mStartPtrs
;
631 pragma(inline
, true);
634 return cast(int)(*mCurStartPtr
-mCovers
);
637 @property int pixelCount () const pure { pragma(inline
, true); return cast(int)(*mCurCount
); }
638 @property const(ubyte)* covers () const pure { pragma(inline
, true); return *mCurStartPtr
; }
641 public nothrow @trusted @nogc:
642 mixin(DisableCopyingMixin
);
645 import core
.stdc
.stdlib
: free
;
646 if (mCounts
!is null) free(mCounts
);
647 if (mStartPtrs
!is null) free(mStartPtrs
);
648 if (mCovers
!is null) free(mCovers
);
651 auto iterator () const pure { pragma(inline
, true); return Iterator(this); }
653 void reset (int minX
, int maxX
, int dx
=0, int dy
=0) {
654 uint maxLen
= maxX
-minX
+2;
655 if (maxLen
> mMaxLen
) {
656 import core
.stdc
.stdlib
: realloc
;
657 mCovers
= cast(ubyte*)realloc(mCovers
, maxLen
*mCovers
[0].sizeof
);
658 if (mCovers
is null) assert(0, "out of memory");
659 mStartPtrs
= cast(ubyte**)realloc(mStartPtrs
, mStartPtrs
[0].sizeof
*maxLen
);
660 if (mStartPtrs
is null) assert(0, "out of memory");
661 mCounts
= cast(ushort*)realloc(mCounts
, mCounts
[0].sizeof
*maxLen
);
662 if (mCounts
is null) assert(0, "out of memory");
671 mCurStartPtr
= mStartPtrs
;
676 pragma(inline
, true);
680 mCurStartPtr
= mStartPtrs
;
684 void addSpan (int x
, int y
, uint num
, uint cover
) {
685 import core
.stdc
.string
: memset
;
687 memset(mCovers
+x
, cover
, num
);
689 (*mCurCount
) += cast(ushort)num
;
691 *++mCurCount
= cast(ushort)num
;
692 *++mCurStartPtr
= mCovers
+x
;
699 void addCell (int x
, int y
, uint cover
) {
701 mCovers
[x
] = cast(ubyte)cover
;
706 *++mCurStartPtr
= mCovers
+x
;
713 @property bool isReady (int y
) const pure { pragma(inline
, true); return (mNumSpans
&& (y^mLastY
)); }
714 @property int baseX () const pure { pragma(inline
, true); return mMinX
+mDX
; }
715 @property int y () const pure { pragma(inline
, true); return mLastY
+mDY
; }
716 @property uint spanCount () const pure { pragma(inline
, true); return mNumSpans
; }
720 // ////////////////////////////////////////////////////////////////////////// //
721 /* This class template is used basically for rendering scanlines.
723 auto ras = Rasterizer();
731 ras.render(ren, Color(255, 127, 0));
733 public struct Renderer
{
734 public nothrow @trusted @nogc:
735 mixin(DisableCopyingMixin
);
737 static void render (in ref ScanLine sl
, in GxColor clr
, in ref GxRect clipRect
) {
738 if (clipRect
.size
.h
< 1 || clipRect
.size
.w
< 1 || sl
.y
< clipRect
.pos
.y || sl
.y
>= clipRect
.pos
.y
+clipRect
.size
.h
) return;
739 immutable GxColorU c
= GxColorU(clr
);
740 uint spanCount
= sl
.spanCount
;
741 immutable int baseX
= sl
.baseX
;
742 uint* row
= vglTexBuf
+cast(uint)sl
.y
*cast(uint)VBufWidth
;
743 auto span
= sl
.iterator
;
745 int x
= span
.next
+baseX
;
746 int pixelCount
= span
.pixelCount
;
748 if (clipRect
.clipHStripe(ref x
, sl
.y
, ref pixelCount
, &leftSkip
)) {
749 const(ubyte)* covers
= span
.covers
+leftSkip
;
750 memBlendColorCoverage(row
+x
, covers
, clr
, pixelCount
);
752 } while (--spanCount
);
757 // ////////////////////////////////////////////////////////////////////////// //
758 /* These constants determine the subpixel accuracy, to be more precise,
759 the number of bits of the fractional part of the coordinates.
760 The possible coordinate capacity in bits can be calculated by formula:
761 sizeof(int) * 8 - PolyBaseShift * 2, i.e, for 32-bit integers and
762 8-bits fractional part the capacity is 16 bits or [-32768...32767].
766 PolyBaseSize
= cast(uint)(1<<PolyBaseShift
),
767 PolyBaseMask
= cast(uint)(PolyBaseSize
-1),
771 int polyCoord (in float c
) pure nothrow @safe @nogc { pragma(inline
, true); return (cast(int)(c
*(PolyBaseSize
*2))+1)/2; }
773 int dbl2fix (in float c
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(int)(c
*PolyBaseSize
); }
774 float fix2dbl (in int c
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(float)c
/cast(float)PolyBaseSize
; }
777 // ////////////////////////////////////////////////////////////////////////// //
778 /* Polygon rasterizer that is used to render filled polygons with
779 high-quality Anti-Aliasing. Internally, by default, the class uses
780 integer coordinates in format 24.8, i.e. 24 bits for integer part
781 and 8 bits for fractional - see PolyBaseShift. This class can be
782 used in the following way:
784 1. fillRule = FillRule.EvenOdd; // optional
785 2. gamma() - optional.
787 4. moveTo(x, y) / lineTo(x, y) - make the polygon. One can create
788 more than one contour, but each contour must consist of at least 3
789 vertices, i.e. moveTo(x1, y1); lineTo(x2, y2); lineTo(x3, y3);
790 is the absolute minimum of vertices that define a triangle.
791 The algorithm does not check either the number of vertices nor
792 coincidence of their coordinates, but in the worst case it just
794 The orger of the vertices (clockwise or counterclockwise)
795 is important when using the non-zero filling rule (FillNonZero).
796 In this case the vertex order of all the contours must be the same
797 if you want your intersecting polygons to be without "holes".
798 You actually can use different vertices order. If the contours do not
799 intersect each other the order is not important anyway. If they do,
800 contours with the same vertex order will be rendered without "holes"
801 while the intersecting contours with different orders will have "holes".
803 fillRule() and gamma() can be called anytime before "sweeping".
805 public struct Rasterizer
{
806 public nothrow @trusted @nogc:
808 AAShift
= ScanLine
.AAShift
,
818 FillRule mFillingRule
= FillRule
.NonZero
;
819 ubyte[256] mGamma
= DefaultGamma
[];
822 mixin(DisableCopyingMixin
);
824 void reset () { mOutline
.reset(); }
826 @property FillRule
fillRule () const pure { pragma(inline
, true); return mFillingRule
; }
827 @property void fillRule (FillRule v
) { pragma(inline
, true); mFillingRule
= v
; }
829 void gamma (in float g
) {
830 foreach (immutable uint i
; 0..256) {
831 //import std.math : pow;
832 import core
.stdc
.math
: powf
;
833 mGamma
.ptr
[i
] = cast(ubyte)(powf(cast(float)i
/255.0f, g
)*255.0f);
837 void gamma (const(ubyte)[] g
) {
838 if (g
.length
!= 256) assert(0, "invalid gamma array");
839 mGamma
[] = g
[0..256];
842 @property float currX () const pure { pragma(inline
, true); return mOutline
.currX
; }
843 @property float currY () const pure { pragma(inline
, true); return mOutline
.currY
; }
845 void moveToFixed (int x
, int y
) {
846 if ((x
>>PolyBaseShift
) <= short.min
+8 ||
(x
>>PolyBaseShift
) >= short.max
-8 ||
847 (y
>>PolyBaseShift
) <= short.min
+8 ||
(y
>>PolyBaseShift
) >= short.max
-8) assert(0, "coordinates out of bounds");
848 mOutline
.moveTo(x
, y
);
851 void lineToFixed (int x
, int y
) {
852 if ((x
>>PolyBaseShift
) <= short.min
+8 ||
(x
>>PolyBaseShift
) >= short.max
-8 ||
853 (y
>>PolyBaseShift
) <= short.min
+8 ||
(y
>>PolyBaseShift
) >= short.max
-8) assert(0, "coordinates out of bounds");
854 mOutline
.lineTo(x
, y
);
857 void moveTo (in float x
, in float y
) { mOutline
.moveTo(polyCoord(x
), polyCoord(y
)); }
858 void lineTo (in float x
, in float y
) { mOutline
.lineTo(polyCoord(x
), polyCoord(y
)); }
860 @property int minX () const pure { pragma(inline
, true); return mOutline
.minX
; }
861 @property int minY () const pure { pragma(inline
, true); return mOutline
.minY
; }
862 @property int maxX () const pure { pragma(inline
, true); return mOutline
.maxX
; }
863 @property int maxY () const pure { pragma(inline
, true); return mOutline
.maxY
; }
865 private uint calculateAlpha (int area
) const pure {
866 int cover
= area
>>(PolyBaseShift
*2+1-AAShift
);
867 if (cover
< 0) cover
= -cover
;
868 if (mFillingRule
== FillRule
.EvenOdd
) {
870 if (cover
> AANum
) cover
= AA2Num
-cover
;
872 if (cover
> AAMask
) cover
= AAMask
;
876 void render (in ref GxRect clipRect
, in GxColor c
, int dx
=0, int dy
=0) {
877 const(Cell
)** cells
= mOutline
.cells();
878 if (mOutline
.numCells() == 0) return;
880 mScanline
.reset(mOutline
.minX
, mOutline
.maxX
, dx
, dy
);
883 const(Cell
)* curCell
= *cells
++;
886 const(Cell
)* startCell
= curCell
;
888 int coord
= curCell
.packedCoord
;
892 int area
= startCell
.area
;
893 cover
+= startCell
.cover
;
895 // accumulate all start cells
896 while ((curCell
= *cells
++) !is null) {
897 if (curCell
.packedCoord
!= coord
) break;
898 area
+= curCell
.area
;
899 cover
+= curCell
.cover
;
903 int alpha
= calculateAlpha((cover
<<(PolyBaseShift
+1))-area
);
905 if (mScanline
.isReady(y
)) {
906 Renderer
.render(mScanline
, c
, clipRect
);
907 mScanline
.resetSpans();
909 mScanline
.addCell(x
, y
, mGamma
[alpha
]);
917 int alpha
= calculateAlpha(cover
<<(PolyBaseShift
+1));
919 if (mScanline
.isReady(y
)) {
920 Renderer
.render(mScanline
, c
, clipRect
);
921 mScanline
.resetSpans();
923 mScanline
.addSpan(x
, y
, curCell
.x
-x
, mGamma
[alpha
]);
928 if (mScanline
.spanCount
) Renderer
.render(mScanline
, c
, clipRect
);
931 bool hitTest (int tx
, int ty
) {
932 const(Cell
)** cells
= mOutline
.cells();
933 if (mOutline
.numCells
== 0) return false;
936 const(Cell
)* curCell
= *cells
++;
939 const(Cell
)* startCell
= curCell
;
941 int coord
= curCell
.packedCoord
;
945 if (y
> ty
) return false;
947 int area
= startCell
.area
;
948 cover
+= startCell
.cover
;
950 while ((curCell
= *cells
++) !is null) {
951 if (curCell
.packedCoord
!= coord
) break;
952 area
+= curCell
.area
;
953 cover
+= curCell
.cover
;
957 int alpha
= calculateAlpha((cover
<<(PolyBaseShift
+1))-area
);
959 if (tx
== x
&& ty
== y
) return true;
964 if (curCell
is null) break;
967 int alpha
= calculateAlpha(cover
<<(PolyBaseShift
+1));
969 if (ty
== y
&& tx
>= x
&& tx
<= curCell
.x
) return true;
977 static immutable ubyte[256] DefaultGamma
= [
978 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8,
979 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18,
980 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28,
981 29, 29, 30, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37, 38,
982 39, 39, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49,
983 49, 50, 51, 51, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60,
984 60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 68, 68, 69, 70, 71, 71,
985 72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 83, 84,
986 85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
987 100,101,101,102,103,104,105,106,107,108,109,110,111,112,114,115,
988 116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,132,
989 134,135,136,137,139,140,141,142,144,145,146,147,149,150,151,153,
990 154,155,157,158,159,161,162,164,165,166,168,169,171,172,174,175,
991 177,178,180,181,183,184,186,188,189,191,192,194,195,197,199,200,
992 202,204,205,207,209,210,212,214,215,217,219,220,222,224,225,227,
993 229,230,232,234,236,237,239,241,242,244,246,248,249,251,253,255
998 // ////////////////////////////////////////////////////////////////////////// //
999 public alias AGGPoint
= AGGPointImpl
!float;
1001 public struct AGGPointImpl(T
) if (__traits(isIntegral
, T
) ||
__traits(isFloating
, T
)) {
1002 public nothrow @trusted @nogc:
1004 alias Me
= AGGPointImpl
!T
;
1007 static if (__traits(isFloating
, T
)) {
1015 // ////////////////////////////////////////////////////////////////////////// //
1016 public enum FillRule
{
1021 public enum LineCap
{
1027 public enum LineJoin
{
1035 public enum InnerJoin
{
1043 // ////////////////////////////////////////////////////////////////////////// //
1044 // some "fastgfx" backend
1045 public struct AGGDrawer
{
1047 static struct Vertex
{
1048 float x
, y
; // fixed point
1054 float tessTol
= 0.25f;
1055 float angleTol
= 0; // 0.0f -- angle tolerance for McSeem Bezier rasterizer
1056 float cuspLimit
= 0; // 0 -- cusp limit for McSeem Bezier rasterizer (0: real cusps)
1058 uint vtxcount
, vtxsize
;
1059 // default tesselator for Bezier curves.
1060 AGGTesselation tesselator
= AGGTesselation
.DeCasteljau
;
1062 nothrow @trusted @nogc:
1064 enum distTol
= cast(float)(1.0f/256.0f);
1065 enum KAPPA90
= 0.5522847493f; // length proportional to radius of a cubic bezier handle for 90deg arcs
1067 static bool ptEquals (in float x0
, in float y0
, in float x1
, in float y1
) pure {
1068 enum EPS
= cast(float)(1.0f/256.0f);
1069 static bool eq (in float a
, in float b
) pure nothrow @safe @nogc { immutable float df = a
-b
; return (df < 0.0f ?
(-df < EPS
) : (df < EPS
)); }
1070 return (eq(x0
, x1
) && eq(y0
, y1
));
1073 static float distPtSeg (in float x
, in float y
, in float px
, in float py
, in float qx
, in float qy
) pure nothrow @safe @nogc {
1074 immutable float pqx
= qx
-px
;
1075 immutable float pqy
= qy
-py
;
1078 immutable float d
= pqx
*pqx
+pqy
*pqy
;
1079 float t
= pqx
*dx
+pqy
*dy
;
1081 if (t
< 0) t
= 0; else if (t
> 1) t
= 1;
1087 static float cross() (in float dx0
, in float dy0
, in float dx1
, in float dy1
) pure { pragma(inline
, true); return (dx1
*dy0
-dx0
*dy1
); }
1088 static T
min(T
) (in T a
, in T b
) pure { pragma(inline
, true); return (a
< b ? a
: b
); }
1089 static T
max(T
) (in T a
, in T b
) pure { pragma(inline
, true); return (a
> b ? a
: b
); }
1090 static T
sign(T
) (in T a
) pure { pragma(inline
, true); return (a
>= cast(T
)0 ?
cast(T
)1 : cast(T
)(-1)); }
1092 static float normalize (float* x
, float* y
) nothrow @safe @nogc {
1093 import core
.stdc
.math
: sqrtf
;
1094 float d
= sqrtf((*x
)*(*x
)+(*y
)*(*y
));
1096 immutable float id
= 1.0f/d
;
1103 void addVertexIntr (in float fx
, in float fy
, bool asMove
=false) {
1104 //static bool eq (in float a, in float b) pure nothrow @safe @nogc { import std.math : abs; return (abs(a-b) < EPS); }
1105 if (vtxcount
> 0 && ptEquals(fx
, fy
, vtx
[vtxcount
-1].x
, vtx
[vtxcount
-1].y
)) {
1106 if (asMove
!= vtx
[vtxcount
-1].asmove
) return;
1108 if (vtxcount
+1 > vtxsize
) {
1109 import core
.stdc
.stdlib
: realloc
;
1110 uint newsz
= (vtxsize|
0xfff)+1;
1111 vtx
= cast(Vertex
*)realloc(vtx
, newsz
*Vertex
.sizeof
);
1112 if (vtx
is null) assert(0, "out of memory");
1115 if (asMove
&& vtxcount
> 0 && vtx
[vtxcount
-1].asmove
) --vtxcount
;
1116 vtx
[vtxcount
++] = Vertex(fx
, fy
, asMove
);
1119 void addVertex (in float fx
, in float fy
, bool asMove
=false) {
1120 pragma(inline
, true);
1121 if (vtxcount
== 0 && !asMove
) addVertexIntr(0, 0, true);
1122 addVertexIntr(fx
, fy
, asMove
);
1129 @property void lineCap (in LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
1130 @property void lineJoin (in LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
1131 @property void innerJoin (in InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
1133 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
1134 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
1135 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
1137 @property void width (in float w
) { pragma(inline
, true); mStroker
.width(w
); }
1138 @property void miterLimit (in float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
1139 @property void miterLimitTheta (in float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
1140 @property void innerMiterLimit (in float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
1141 @property void approximationScale (in float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
1143 @property float width () const pure { pragma(inline
, true); return mStroker
.width(); }
1144 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
1145 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
1146 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
1148 @property void shorten (in float s
) { pragma(inline
, true); mStroker
.shorten
= s
; }
1149 @property float shorten () const pure { pragma(inline
, true); return mStroker
.shorten
; }
1151 @property FillRule
fillRule () const pure { pragma(inline
, true); return rast
.fillRule
; }
1152 @property void fillRule (FillRule v
) { pragma(inline
, true); rast
.fillRule
= v
; }
1154 @property float currX () const pure { pragma(inline
, true); return (vtxcount
> 0 ? vtx
[vtxcount
-1].x
: 0.0f); }
1155 @property float currY () const pure { pragma(inline
, true); return (vtxcount
> 0 ? vtx
[vtxcount
-1].y
: 0.0f); }
1157 // ////////////////////////////////////////////////////////////////////////// //
1158 ref AGGDrawer
beginFrame () {
1160 //addVertex(0, 0, true);
1161 mStroker
.width
= 1.5f;
1166 ref AGGDrawer
cancelFrame () {
1168 //addVertex(0, 0, true);
1173 ref AGGDrawer
endFrame (in GxColor c
) {
1174 GxRect clipRect
= gxClipRect
;
1175 if (clipRect
.intersect(0, 0, VBufWidth
, VBufHeight
)) {
1176 rast
.render(clipRect
, c
);
1178 return beginFrame();
1181 ref AGGDrawer
beginPath () {
1182 pragma(inline
, true);
1187 ref AGGDrawer
closePath () {
1188 if (vtxcount
> 1 && !vtx
[vtxcount
-1].asmove
) {
1190 while (vp
> 0 && !vtx
[vp
-1].asmove
) --vp
;
1191 addVertex(vtx
[vp
-1].x
, vtx
[vp
-1].y
); // close it
1196 // starts new sub-path with specified point as first point
1197 ref AGGDrawer
moveTo (in float x
, in float y
) { pragma(inline
, true); addVertex(x
, y
, true); return this; }
1199 // adds line segment from the last point in the path to the specified point
1200 ref AGGDrawer
lineTo (in float x
, in float y
) { pragma(inline
, true); addVertex(x
, y
); return this; }
1202 // adds cubic bezier segment from last point in the path via two control points to the specified point
1203 ref AGGDrawer
bezierTo (in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
) {
1204 pragma(inline
, true);
1205 //tesselateBezierMcSeem(currX, currY, x2, y2, x3, y3, x4, y4, 0);
1206 tesselateBezier(currX
, currY
, x2
, y2
, x3
, y3
, x4
, y4
);
1210 // adds quadratic bezier segment from last point in the path via a control point to the specified point
1211 void quadTo (in float cx
, in float cy
, in float x
, in float y
) {
1212 immutable float x0
= currX
;
1213 immutable float y0
= currY
;
1215 x0
+2.0f/3.0f*(cx
-x0
), y0
+2.0f/3.0f*(cy
-y0
),
1216 x
+2.0f/3.0f*(cx
-x
), y
+2.0f/3.0f*(cy
-y
),
1221 // adds an arc segment at the corner defined by the last path point, and two specified points
1222 ref AGGDrawer
arcTo (in float x1
, in float y1
, in float x2
, in float y2
, in float radius
) {
1223 import core
.stdc
.math
: acosf
, tanf
, atan2f
;
1225 immutable float x0
= currX
;
1226 immutable float y0
= currY
;
1228 // handle degenerate cases
1229 if (ptEquals(x0
, y0
, x1
, y1
) ||
1230 ptEquals(x1
, y1
, x2
, y2
) ||
1231 distPtSeg(x1
, y1
, x0
, y0
, x2
, y2
) < distTol
*distTol ||
1238 // calculate tangential circle to lines (x0, y0)-(x1, y1) and (x1, y1)-(x2, y2)
1243 normalize(&dx0
, &dy0
);
1244 normalize(&dx1
, &dy1
);
1245 immutable float a
= acosf(dx0
*dx1
+dy0
*dy1
);
1246 immutable float d
= radius
/tanf(a
/2.0f);
1253 float cx
= void, cy
= void, a0
= void, a1
= void;
1255 if (cross(dx0
, dy0
, dx1
, dy1
) > 0.0f) {
1256 cx
= x1
+dx0
*d
+dy0
*radius
;
1257 cy
= y1
+dy0
*d
+-dx0
*radius
;
1258 a0
= atan2f(dx0
, -dy0
);
1259 a1
= atan2f(-dx1
, dy1
);
1261 //printf("CW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
1263 cx
= x1
+dx0
*d
+-dy0
*radius
;
1264 cy
= y1
+dy0
*d
+dx0
*radius
;
1265 a0
= atan2f(-dx0
, dy0
);
1266 a1
= atan2f(dx1
, -dy1
);
1268 //printf("CCW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
1271 return arc(dir
, cx
, cy
, radius
, a0
, a1
); // first is line
1275 // ////////////////////////////////////////////////////////////////////////// //
1278 //pragma(inline, true);
1279 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1280 if (vt
.asmove
) rast
.moveTo(vt
.x
, vt
.y
); else rast
.lineTo(vt
.x
, vt
.y
);
1286 //if (mStroker.width <= 1.0) { contour(); return; }
1287 mStroker
.removeAll();
1289 bool waitingLine
= true;
1290 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1291 mStroker
.addVertex(vt
.x
, vt
.y
, (vt
.asmove ? PathCommand
.MoveTo
: PathCommand
.LineTo
));
1293 mStroker
.addVertex(0, 0, PathCommand
.Stop
);
1298 auto cmd
= mStroker
.vertex(&x
, &y
);
1299 if (isStop(cmd
)) break;
1300 if (isMoveTo(cmd
)) { rast
.moveTo(x
, y
); continue; }
1301 if (isLineTo(cmd
)) { rast
.lineTo(x
, y
); continue; }
1302 if (isEndPoly(cmd
)) {
1304 if (is_close(cmd) && !first) {
1305 //writeln("s=(", sx, ",", sy, "); c=(", x, ",", y, ")");
1306 pts.add(PathPoint(sx, sy, false));
1318 ctr
.lineCap
= mStroker
.lineCap
;
1319 ctr
.lineJoin
= mStroker
.lineJoin
;
1320 ctr
.innerJoin
= mStroker
.innerJoin
;
1322 ctr
.width
= mStroker
.width
;
1323 ctr
.miterLimit
= mStroker
.miterLimit
;
1324 ctr
.innerMiterLimit
= mStroker
.innerMiterLimit
;
1325 ctr
.approximationScale
= mStroker
.approximationScale
;
1327 bool waitingLine
= true;
1328 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1329 ctr
.addVertex(vt
.x
, vt
.y
, (vt
.asmove ? PathCommand
.MoveTo
: PathCommand
.LineTo
));
1331 ctr
.addVertex(0, 0, PathCommand
.Stop
);
1336 auto cmd
= ctr
.vertex(&x
, &y
);
1337 if (isStop(cmd
)) break;
1338 if (isMoveTo(cmd
)) { rast
.moveTo(x
, y
); continue; }
1339 if (isLineTo(cmd
)) { rast
.lineTo(x
, y
); continue; }
1344 // ////////////////////////////////////////////////////////////////////////// //
1345 enum Winding
{ CW
, CCW
}
1347 /* Creates new circle arc shaped sub-path. The arc center is at (cx, cy), the arc radius is r,
1348 * and the arc is drawn from angle a0 to a1, and swept in direction dir (NVGWinding.CCW, or NVGWinding.CW).
1349 * Angles are specified in radians.
1351 * [mode] is: "original", "move", "line" -- first command will be like original NanoVega, MoveTo, or LineTo
1353 ref AGGDrawer
arc(string mode
="original") (Winding dir
, in float cx
, in float cy
, in float r
,
1354 in float a0
, in float a1
)
1356 static assert(mode
== "original" || mode
== "move" || mode
== "line");
1357 import core
.stdc
.math
: fabsf
, cosf
, sinf
;
1359 //int move = (ctx.ncommands > 0 ? Command.LineTo : Command.MoveTo);
1360 static if (mode
== "original") {
1361 bool asMove
= (vtxcount
== 0);
1362 } else static if (mode
== "move") {
1364 } else static if (mode
== "line") {
1365 enum asMove
= false;
1367 static assert(0, "wtf?!");
1372 if (dir
== Winding
.CW
) {
1373 if (fabsf(da) >= FLT_PI
*2.0f) {
1376 while (da < 0.0f) da += FLT_PI
*2.0f;
1379 if (fabsf(da) >= FLT_PI
*2.0f) {
1382 while (da > 0.0f) da -= FLT_PI
*2.0f;
1386 // Split arc into max 90 degree segments.
1387 immutable int ndivs
= max(1, min(cast(int)(fabsf(da)/(FLT_PI
*0.5f)+0.5f), 5));
1388 immutable float hda
= (da/cast(float)ndivs
)/2.0f;
1389 float kappa
= fabsf(4.0f/3.0f*(1.0f-cosf(hda
))/sinf(hda
));
1390 if (dir
== Winding
.CCW
) kappa
= -kappa
;
1393 float px
= 0, py
= 0, ptanx
= 0, ptany
= 0;
1394 foreach (int i
; 0..ndivs
+1) {
1395 immutable float a
= a0
+da*(i
/cast(float)ndivs
);
1396 immutable float dx
= cosf(a
);
1397 immutable float dy
= sinf(a
);
1398 immutable float x
= cx
+dx
*r
;
1399 immutable float y
= cy
+dy
*r
;
1400 immutable float tanx
= -dy
*r
*kappa
;
1401 immutable float tany
= dx
*r
*kappa
;
1404 addVertex(x
, y
, asMove
);
1406 bezierTo(px
+ptanx
, py
+ptany
, x
-tanx
, y
-tany
, x
, y
);
1417 // creates new rectangle shaped sub-path
1418 ref AGGDrawer
rect (in float x
, in float y
, in float w
, in float h
) {
1424 lineTo(x
, y
); // close it
1429 // creates new rounded rectangle shaped sub-path
1430 ref AGGDrawer
roundedRect (in float x
, in float y
, in float w
, in float h
, in float radius
) {
1431 return roundedRectVarying(x
, y
, w
, h
, radius
, radius
, radius
, radius
);
1434 // creates new rounded rectangle shaped sub-path
1435 // specify ellipse width and height to round corners according to it
1436 ref AGGDrawer
roundedRectEllipse (in float x
, in float y
, in float w
, in float h
, in float rw
, in float rh
) {
1437 if (rw
< 0.1f || rh
< 0.1f) return rect(x
, y
, w
, h
);
1440 bezierTo(x
+w
-rw
*(1.0f-KAPPA90
), y
, x
+w
, y
+rh
*(1.0f-KAPPA90
), x
+w
, y
+rh
);
1441 lineTo(x
+w
, y
+h
-rh
);
1442 bezierTo(x
+w
, y
+h
-rh
*(1.0f-KAPPA90
), x
+w
-rw
*(1.0f-KAPPA90
), y
+h
, x
+w
-rw
, y
+h
);
1444 bezierTo(x
+rw
*(1.0f-KAPPA90
), y
+h
, x
, y
+h
-rh
*(1.0f-KAPPA90
), x
, y
+h
-rh
);
1446 bezierTo(x
, y
+rh
*(1.0f-KAPPA90
), x
+rw
*(1.0f-KAPPA90
), y
, x
+rw
, y
);
1450 // creates new rounded rectangle shaped sub-path
1451 // this one allows you to specify different rounding radii for each corner
1452 ref AGGDrawer
roundedRectVarying (in float x
, in float y
, in float w
, in float h
,
1453 in float radTopLeft
, in float radTopRight
,
1454 in float radBottomRight
, in float radBottomLeft
)
1456 import core
.stdc
.math
: fabsf
;
1457 if (radTopLeft
< 0.1f && radTopRight
< 0.1f && radBottomRight
< 0.1f && radBottomLeft
< 0.1f) return rect(x
, y
, w
, h
);
1458 immutable float halfw
= fabsf(w
)*0.5f;
1459 immutable float halfh
= fabsf(h
)*0.5f;
1460 immutable float rxBL
= min(radBottomLeft
, halfw
)*sign(w
), ryBL
= min(radBottomLeft
, halfh
)*sign(h
);
1461 immutable float rxBR
= min(radBottomRight
, halfw
)*sign(w
), ryBR
= min(radBottomRight
, halfh
)*sign(h
);
1462 immutable float rxTR
= min(radTopRight
, halfw
)*sign(w
), ryTR
= min(radTopRight
, halfh
)*sign(h
);
1463 immutable float rxTL
= min(radTopLeft
, halfw
)*sign(w
), ryTL
= min(radTopLeft
, halfh
)*sign(h
);
1465 lineTo(x
, y
+h
-ryBL
);
1466 bezierTo(x
, y
+h
-ryBL
*(1.0f-KAPPA90
), x
+rxBL
*(1.0f-KAPPA90
), y
+h
, x
+rxBL
, y
+h
);
1467 lineTo(x
+w
-rxBR
, y
+h
);
1468 bezierTo(x
+w
-rxBR
*(1.0f-KAPPA90
), y
+h
, x
+w
, y
+h
-ryBR
*(1.0f-KAPPA90
), x
+w
, y
+h
-ryBR
);
1469 lineTo(x
+w
, y
+ryTR
);
1470 bezierTo(x
+w
, y
+ryTR
*(1.0f-KAPPA90
), x
+w
-rxTR
*(1.0f-KAPPA90
), y
, x
+w
-rxTR
, y
);
1472 bezierTo(x
+rxTL
*(1.0f-KAPPA90
), y
, x
, y
+ryTL
*(1.0f-KAPPA90
), x
, y
+ryTL
);
1476 // creates new ellipse shaped sub-path
1477 ref AGGDrawer
ellipse (in float cx
, in float cy
, in float rx
, in float ry
) {
1479 bezierTo(cx
-rx
, cy
+ry
*KAPPA90
, cx
-rx
*KAPPA90
, cy
+ry
, cx
, cy
+ry
);
1480 bezierTo(cx
+rx
*KAPPA90
, cy
+ry
, cx
+rx
, cy
+ry
*KAPPA90
, cx
+rx
, cy
);
1481 bezierTo(cx
+rx
, cy
-ry
*KAPPA90
, cx
+rx
*KAPPA90
, cy
-ry
, cx
, cy
-ry
);
1482 bezierTo(cx
-rx
*KAPPA90
, cy
-ry
, cx
-rx
, cy
-ry
*KAPPA90
, cx
-rx
, cy
);
1486 // creates new circle shaped sub-path
1487 ref AGGDrawer
circle (in float cx
, in float cy
, in float r
) {
1488 return ellipse(cx
, cy
, r
, r
);
1492 // ////////////////////////////////////////////////////////////////////////// //
1493 void tesselateBezierDCj (in float x1
, in float y1
, in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
, in int level
/*, in int type*/) {
1494 import core
.stdc
.math
: fabsf
;
1495 if (level
> 10) return;
1497 // check for collinear points, and use AFD tesselator on such curves (it is WAY faster for this case)
1499 if (level == 0 && ctx.tesselatortype == NVGTesselation.Combined) {
1500 static bool collinear (in float v0x, in float v0y, in float v1x, in float v1y, in float v2x, in float v2y) nothrow @trusted @nogc {
1501 immutable float cz = (v1x-v0x)*(v2y-v0y)-(v2x-v0x)*(v1y-v0y);
1502 return (fabsf(cz*cz) <= 0.01f); // arbitrary number, seems to work ok with NanoSVG output
1504 if (collinear(x1, y1, x2, y2, x3, y3) && collinear(x2, y2, x3, y3, x3, y4)) {
1505 //{ import core.stdc.stdio; printf("AFD fallback!\n"); }
1506 ctx.tesselateBezierAFD(x1, y1, x2, y2, x3, y3, x4, y4, type);
1512 immutable float x12
= (x1
+x2
)*0.5f;
1513 immutable float y12
= (y1
+y2
)*0.5f;
1514 immutable float x23
= (x2
+x3
)*0.5f;
1515 immutable float y23
= (y2
+y3
)*0.5f;
1516 immutable float x34
= (x3
+x4
)*0.5f;
1517 immutable float y34
= (y3
+y4
)*0.5f;
1518 immutable float x123
= (x12
+x23
)*0.5f;
1519 immutable float y123
= (y12
+y23
)*0.5f;
1521 immutable float dx
= x4
-x1
;
1522 immutable float dy
= y4
-y1
;
1523 immutable float d2
= fabsf(((x2
-x4
)*dy
-(y2
-y4
)*dx
));
1524 immutable float d3
= fabsf(((x3
-x4
)*dy
-(y3
-y4
)*dx
));
1526 if ((d2
+d3
)*(d2
+d3
) < tessTol
*(dx
*dx
+dy
*dy
)) {
1527 addVertex(x4
, y4
/*, type*/);
1531 immutable float x234
= (x23
+x34
)*0.5f;
1532 immutable float y234
= (y23
+y34
)*0.5f;
1533 immutable float x1234
= (x123
+x234
)*0.5f;
1534 immutable float y1234
= (y123
+y234
)*0.5f;
1536 // "taxicab" / "manhattan" check for flat curves
1537 if (fabsf(x1
+x3
-x2
-x2
)+fabsf(y1
+y3
-y2
-y2
)+fabsf(x2
+x4
-x3
-x3
)+fabsf(y2
+y4
-y3
-y3
) < tessTol
/4) {
1538 addVertex(x1234
, y1234
/*, type*/);
1542 tesselateBezierDCj(x1
, y1
, x12
, y12
, x123
, y123
, x1234
, y1234
, level
+1/*, 0*/);
1543 tesselateBezierDCj(x1234
, y1234
, x234
, y234
, x34
, y34
, x4
, y4
, level
+1/*, type*/);
1546 // ////////////////////////////////////////////////////////////////////////// //
1547 // based on the ideas and code of Maxim Shemanarev. Rest in Peace, bro!
1548 // see http://www.antigrain.com/research/adaptive_bezier/index.html
1549 void tesselateBezierMcSeem (in float x1
, in float y1
, in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
, in int level
/*, in int type*/) {
1550 //import std.math : atan2, PI;
1551 import core
.stdc
.math
: fabsf
, atan2f
;
1553 enum CollinearEPS
= 0.00000001f; // 0.00001f;
1554 enum AngleTolEPS
= 0.01f;
1556 static float distSquared (in float x1
, in float y1
, in float x2
, in float y2
) pure nothrow @safe @nogc {
1557 pragma(inline
, true);
1558 immutable float dx
= x2
-x1
;
1559 immutable float dy
= y2
-y1
;
1565 addVertex(x1, y1/*, 0*/);
1566 tesselateBezierMcSeem(x1, y1, x2, y2, x3, y3, x4, y4, 1/*, type*/);
1567 addVertex(x4, y4/*, type*/);
1572 if (level
>= 32) return; // recurse limit; practically, it should be never reached, but...
1574 // calculate all the mid-points of the line segments
1575 immutable float x12
= (x1
+x2
)*0.5f;
1576 immutable float y12
= (y1
+y2
)*0.5f;
1577 immutable float x23
= (x2
+x3
)*0.5f;
1578 immutable float y23
= (y2
+y3
)*0.5f;
1579 immutable float x34
= (x3
+x4
)*0.5f;
1580 immutable float y34
= (y3
+y4
)*0.5f;
1581 immutable float x123
= (x12
+x23
)*0.5f;
1582 immutable float y123
= (y12
+y23
)*0.5f;
1583 immutable float x234
= (x23
+x34
)*0.5f;
1584 immutable float y234
= (y23
+y34
)*0.5f;
1585 immutable float x1234
= (x123
+x234
)*0.5f;
1586 immutable float y1234
= (y123
+y234
)*0.5f;
1588 // try to approximate the full cubic curve by a single straight line
1589 immutable float dx
= x4
-x1
;
1590 immutable float dy
= y4
-y1
;
1592 float d2
= fabsf(((x2
-x4
)*dy
-(y2
-y4
)*dx
));
1593 float d3
= fabsf(((x3
-x4
)*dy
-(y3
-y4
)*dx
));
1595 final switch ((cast(int)(d2
> CollinearEPS
)<<1)+cast(int)(d3
> CollinearEPS
)) {
1597 // all collinear or p1 == p4
1598 float k
= dx
*dx
+dy
*dy
;
1600 d2
= distSquared(x1
, y1
, x2
, y2
);
1601 d3
= distSquared(x4
, y4
, x3
, y3
);
1606 d2
= k
*(da1
*dx
+da2
*dy
);
1609 d3
= k
*(da1
*dx
+da2
*dy
);
1610 if (d2
> 0 && d2
< 1 && d3
> 0 && d3
< 1) {
1611 // Simple collinear case, 1---2---3---4
1612 // We can leave just two endpoints
1615 if (d2
<= 0) d2
= distSquared(x2
, y2
, x1
, y1
);
1616 else if (d2
>= 1) d2
= distSquared(x2
, y2
, x4
, y4
);
1617 else d2
= distSquared(x2
, y2
, x1
+d2
*dx
, y1
+d2
*dy
);
1619 if (d3
<= 0) d3
= distSquared(x3
, y3
, x1
, y1
);
1620 else if (d3
>= 1) d3
= distSquared(x3
, y3
, x4
, y4
);
1621 else d3
= distSquared(x3
, y3
, x1
+d3
*dx
, y1
+d3
*dy
);
1625 addVertex(x2
, y2
/*, type*/);
1628 } if (d3
< tessTol
) {
1629 addVertex(x3
, y3
/*, type*/);
1634 // p1,p2,p4 are collinear, p3 is significant
1635 if (d3
*d3
<= tessTol
*(dx
*dx
+dy
*dy
)) {
1636 if (angleTol
< AngleTolEPS
) {
1637 addVertex(x23
, y23
/*, type*/);
1641 float da1
= fabsf(atan2f(y4
-y3
, x4
-x3
)-atan2f(y3
-y2
, x3
-x2
));
1642 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1643 if (da1
< angleTol
) {
1644 addVertex(x2
, y2
/*, type*/);
1645 addVertex(x3
, y3
/*, type*/);
1648 if (cuspLimit
!= 0) {
1649 if (da1
> cuspLimit
) {
1650 addVertex(x3
, y3
/*, type*/);
1658 // p1,p3,p4 are collinear, p2 is significant
1659 if (d2
*d2
<= tessTol
*(dx
*dx
+dy
*dy
)) {
1660 if (angleTol
< AngleTolEPS
) {
1661 addVertex(x23
, y23
/*, type*/);
1665 float da1
= fabsf(atan2f(y3
-y2
, x3
-x2
)-atan2f(y2
-y1
, x2
-x1
));
1666 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1667 if (da1
< angleTol
) {
1668 addVertex(x2
, y2
/*, type*/);
1669 addVertex(x3
, y3
/*, type*/);
1672 if (cuspLimit
!= 0) {
1673 if (da1
> cuspLimit
) {
1674 addVertex(x2
, y2
/*, type*/);
1683 if ((d2
+d3
)*(d2
+d3
) <= tessTol
*(dx
*dx
+dy
*dy
)) {
1684 // if the curvature doesn't exceed the distance tolerance value, we tend to finish subdivisions
1685 if (angleTol
< AngleTolEPS
) {
1686 addVertex(x23
, y23
/*, type*/);
1689 // angle and cusp condition
1690 immutable float k
= atan2f(y3
-y2
, x3
-x2
);
1691 float da1
= fabsf(k
-atan2f(y2
-y1
, x2
-x1
));
1692 float da2
= fabsf(atan2f(y4
-y3
, x4
-x3
)-k
);
1693 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1694 if (da2
>= FLT_PI
) da2
= 2.0f*FLT_PI
-da2
;
1695 if (da1
+da2
< angleTol
) {
1696 // finally we can stop the recursion
1697 addVertex(x23
, y23
/*, type*/);
1700 if (cuspLimit
!= 0) {
1701 if (da1
> cuspLimit
) {
1702 addVertex(x2
, y2
/*, type*/);
1705 if (da2
> cuspLimit
) {
1706 addVertex(x3
, y3
/*, type*/);
1715 // continue subdivision
1716 tesselateBezierMcSeem(x1
, y1
, x12
, y12
, x123
, y123
, x1234
, y1234
, level
+1/*, 0*/);
1717 tesselateBezierMcSeem(x1234
, y1234
, x234
, y234
, x34
, y34
, x4
, y4
, level
+1/*, type*/);
1720 // Adaptive forward differencing for bezier tesselation.
1721 // See Lien, Sheue-Ling, Michael Shantz, and Vaughan Pratt.
1722 // "Adaptive forward differencing for rendering curves and surfaces."
1723 // ACM SIGGRAPH Computer Graphics. Vol. 21. No. 4. ACM, 1987.
1724 // original code by Taylor Holliday <taylor@audulus.com>
1725 void tesselateBezierAFD (in float x1
, in float y1
, in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
/*, in int type*/) nothrow @trusted @nogc {
1726 enum AFD_ONE
= (1<<10);
1729 immutable float ax
= -x1
+3*x2
-3*x3
+x4
;
1730 immutable float ay
= -y1
+3*y2
-3*y3
+y4
;
1731 immutable float bx
= 3*x1
-6*x2
+3*x3
;
1732 immutable float by
= 3*y1
-6*y2
+3*y3
;
1733 immutable float cx
= -3*x1
+3*x2
;
1734 immutable float cy
= -3*y1
+3*y2
;
1736 // Transform to forward difference basis (stepsize 1)
1739 float dx
= ax
+bx
+cx
;
1740 float dy
= ay
+by
+cy
;
1741 float ddx
= 6*ax
+2*bx
;
1742 float ddy
= 6*ay
+2*by
;
1746 //printf("dx: %f, dy: %f\n", dx, dy);
1747 //printf("ddx: %f, ddy: %f\n", ddx, ddy);
1748 //printf("dddx: %f, dddy: %f\n", dddx, dddy);
1753 immutable float tol
= tessTol
*4;
1755 while (t
< AFD_ONE
) {
1756 // Flatness measure.
1757 float d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1759 // printf("d: %f, th: %f\n", d, th);
1761 // Go to higher resolution if we're moving a lot or overshooting the end.
1762 while ((d
> tol
&& dt > 1) ||
(t
+dt > AFD_ONE
)) {
1765 // Apply L to the curve. Increase curve resolution.
1766 dx
= 0.5f*dx
-(1.0f/8.0f)*ddx
+(1.0f/16.0f)*dddx
;
1767 dy
= 0.5f*dy
-(1.0f/8.0f)*ddy
+(1.0f/16.0f)*dddy
;
1768 ddx
= (1.0f/4.0f)*ddx
-(1.0f/8.0f)*dddx
;
1769 ddy
= (1.0f/4.0f)*ddy
-(1.0f/8.0f)*dddy
;
1770 dddx
= (1.0f/8.0f)*dddx
;
1771 dddy
= (1.0f/8.0f)*dddy
;
1773 // Half the stepsize.
1777 d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1780 // Go to lower resolution if we're really flat
1781 // and we aren't going to overshoot the end.
1782 // XXX: tol/32 is just a guess for when we are too flat.
1783 while ((d
> 0 && d
< tol
/32.0f && dt < AFD_ONE
) && (t
+2*dt <= AFD_ONE
)) {
1784 // printf("down\n");
1786 // Apply L^(-1) to the curve. Decrease curve resolution.
1794 // Double the stepsize.
1798 d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1801 // Forward differencing.
1810 addVertex(px
, py
/*, (t > 0 ? type : 0)*/);
1812 // Advance along the curve.
1815 // Ensure we don't overshoot.
1816 assert(t
<= AFD_ONE
);
1821 public void tesselateBezier (in float x1
, in float y1
, in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
) {
1822 final switch (tesselator
) with (AGGTesselation
) {
1824 tesselateBezierDCj(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
, 0/*, type*/);
1827 tesselateBezierAFD(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
/*, type*/);
1829 case DeCasteljauMcSeem
:
1830 addVertex(x1
, y1
/*, 0*/);
1831 tesselateBezierMcSeem(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
, 1/*, type*/);
1832 addVertex(x4
, y4
/*, type*/);
1837 // ////////////////////////////////////////////////////////////////////////// //
1838 public enum BaphometDims
= 512; // [0..511]
1839 public void renderBaphomet (float ofsx
=0.0f, float ofsy
=0.0f, float scalex
=1.0f, float scaley
=1.0f) {
1840 auto path
= cast(const(ubyte)[])baphometPath
;
1841 immutable plen
= path
.length
;
1845 Bounds
, // always first, has 4 args (x0, y0, x1, y1)
1853 CubicTo
, // cubic bezier
1857 Command
getCommand () nothrow @trusted @nogc {
1858 if (ppos
>= plen
) assert(0, "invalid path");
1859 return cast(Command
)(path
.ptr
[ppos
++]);
1862 float getFloat () nothrow @trusted @nogc {
1863 if (ppos
>= plen || plen
-ppos
< float.sizeof
) assert(0, "invalid path");
1864 version(LittleEndian
) {
1865 float res
= *cast(const(float)*)(&path
.ptr
[ppos
]);
1866 ppos
+= cast(uint)float.sizeof
;
1869 static assert(float.sizeof
== 4);
1870 uint xp
= path
.ptr
[ppos
]|
(path
.ptr
[ppos
+1]<<8)|
(path
.ptr
[ppos
+2]<<16)|
(path
.ptr
[ppos
+3]<<24);
1871 ppos
+= cast(uint)float.sizeof
;
1872 return *cast(const(float)*)(&xp
);
1876 float scaleX (in float v
) nothrow @trusted @nogc { pragma(inline
, true); return ofsx
+cast(float)v
*scalex
; }
1877 float scaleY (in float v
) nothrow @trusted @nogc { pragma(inline
, true); return ofsy
+cast(float)v
*scaley
; }
1880 float cx
= 0.0f, cy
= 0.0f;
1881 bool doStroke
= false, doFill
= false;
1882 while (ppos
< plen
) {
1883 auto cmd
= getCommand();
1885 foreach (string mn; __traits(allMembers, Command)) {
1886 if (__traits(getMember, Command, mn) == cmd) {
1887 import core.stdc.stdio; printf("cmd=%s\n", mn.ptr);
1891 final switch (cmd
) {
1892 case Command
.Bounds
: ppos
+= 4*cast(uint)float.sizeof
; break;
1893 case Command
.StrokeMode
: doStroke
= true; doFill
= false; break;
1894 case Command
.FillMode
: doStroke
= false; doFill
= true; break;
1895 case Command
.StrokeFillMode
: doStroke
= true; doFill
= true; break;
1896 case Command
.NormalStroke
: case Command
.ThinStroke
: break;
1897 case Command
.MoveTo
:
1898 cx
= scaleX(getFloat());
1899 cy
= scaleY(getFloat());
1902 case Command
.LineTo
:
1903 immutable float ex
= scaleX(getFloat());
1904 immutable float ey
= scaleY(getFloat());
1909 case Command
.CubicTo
: // cubic bezier
1910 immutable float x1
= scaleX(getFloat());
1911 immutable float y1
= scaleY(getFloat());
1912 immutable float x2
= scaleX(getFloat());
1913 immutable float y2
= scaleY(getFloat());
1914 immutable float ex
= scaleX(getFloat());
1915 immutable float ey
= scaleY(getFloat());
1916 bezierTo(x1
, y1
, x2
, y2
, ex
, ey
);
1920 case Command
.EndPath
: // don't close this path
1922 if (doStroke
) stroke();
1923 //doFill = doStroke = false;
1929 if (doStroke
) stroke();
1933 private static immutable ubyte[7641] baphometPath
= [
1934 0x01,0x04,0x06,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x08,0xa0,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,
1935 0x00,0x80,0xff,0x43,0xa2,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x08,0x00,0x80,0xff,
1936 0x43,0x7a,0x89,0xe5,0x42,0xa0,0x1d,0xc6,0x43,0x00,0x00,0x00,0x00,0x30,0x89,0x7f,0x43,0x00,0x00,0x00,
1937 0x00,0x08,0x7a,0x89,0xe5,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0x89,0xe5,0x42,0x00,0x00,
1938 0x00,0x00,0x30,0x89,0x7f,0x43,0x08,0x00,0x00,0x00,0x00,0xa2,0x1d,0xc6,0x43,0x7a,0x89,0xe5,0x42,0x00,
1939 0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x09,0x06,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
1940 0x43,0x08,0x16,0x68,0xb3,0x43,0x72,0x87,0xdd,0x43,0x71,0x87,0xdd,0x43,0x17,0x68,0xb3,0x43,0x71,0x87,
1941 0xdd,0x43,0x30,0x89,0x7f,0x43,0x08,0x71,0x87,0xdd,0x43,0xd2,0x2f,0x18,0x43,0x16,0x68,0xb3,0x43,0x35,
1942 0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x35,0xe2,0x87,0x42,0x08,0xd1,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,
1943 0x35,0xe2,0x87,0x42,0xd2,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x08,0x35,0xe2,0x87,
1944 0x42,0x17,0x68,0xb3,0x43,0xd1,0x2f,0x18,0x43,0x72,0x87,0xdd,0x43,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
1945 0x43,0x09,0x06,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x07,0xa4,0x3f,0x7f,0x43,0x0b,0x86,0xdc,0x43,
1946 0x07,0x6c,0xb9,0xb2,0x43,0xe8,0xd1,0xca,0x42,0x07,0x6e,0x4d,0xa0,0x42,0xa9,0x10,0x9c,0x43,0x07,0xb7,
1947 0x40,0xd7,0x43,0xa9,0x10,0x9c,0x43,0x07,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x09,0x06,0x98,0x42,
1948 0x74,0x43,0xb1,0x8d,0x68,0x43,0x08,0xd7,0x24,0x79,0x43,0xba,0x83,0x6e,0x43,0xa9,0x16,0x7c,0x43,0x56,
1949 0xa1,0x76,0x43,0x74,0x2a,0x7d,0x43,0x44,0x73,0x80,0x43,0x08,0x55,0xd1,0x7e,0x43,0xe3,0xea,0x76,0x43,
1950 0xbc,0x18,0x81,0x43,0x7f,0xa8,0x6e,0x43,0x8f,0x0a,0x84,0x43,0x02,0xfc,0x68,0x43,0x09,0x06,0x92,0x29,
1951 0x8d,0x43,0x73,0xc3,0x67,0x43,0x08,0xa4,0xd9,0x8e,0x43,0xf2,0xa6,0x7a,0x43,0x8f,0x22,0x88,0x43,0x75,
1952 0x2a,0x7d,0x43,0x42,0x7f,0x82,0x43,0x08,0xc8,0x88,0x43,0x09,0x06,0xc1,0x79,0x74,0x43,0x50,0x64,0x89,
1953 0x43,0x08,0x68,0x2d,0x72,0x43,0xee,0x21,0x81,0x43,0xcd,0x97,0x55,0x43,0xe6,0xf1,0x7b,0x43,0x91,0xec,
1954 0x5d,0x43,0xa8,0xc7,0x6a,0x43,0x09,0x06,0xfa,0xa5,0x52,0x43,0x60,0x97,0x7c,0x43,0x08,0x19,0xff,0x50,
1955 0x43,0xe9,0x6e,0x8a,0x43,0xb0,0xbd,0x70,0x43,0x4c,0x51,0x82,0x43,0x04,0xeb,0x69,0x43,0x66,0x0f,0x8e,
1956 0x43,0x09,0x06,0x17,0xbf,0x71,0x43,0x2c,0x58,0x94,0x43,0x08,0x1c,0x96,0x6e,0x43,0x61,0x68,0x99,0x43,
1957 0x2d,0x3a,0x6e,0x43,0xc8,0x81,0x9e,0x43,0xb7,0x9b,0x72,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0x30,0xdb,
1958 0x82,0x43,0xdb,0xe9,0x93,0x43,0x08,0x11,0x82,0x84,0x43,0x61,0x68,0x99,0x43,0xe8,0x4a,0x84,0x43,0x8e,
1959 0xa6,0x9e,0x43,0x42,0x7f,0x82,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0xc4,0x02,0x85,0x43,0xd1,0x0b,0x92,
1960 0x43,0x08,0xd6,0xb2,0x86,0x43,0x34,0x1e,0x92,0x43,0x4f,0x58,0x87,0x43,0xa4,0xf1,0x92,0x43,0x03,0xd9,
1961 0x87,0x43,0x7b,0xc6,0x94,0x43,0x09,0x06,0x87,0x3e,0x64,0x43,0x31,0x3b,0x93,0x43,0x08,0x3b,0xbf,0x64,
1962 0x43,0x6f,0xf9,0x91,0x43,0x96,0x0b,0x67,0x43,0xc5,0x4a,0x91,0x43,0xcf,0xfe,0x6a,0x43,0x31,0x2f,0x91,
1963 0x43,0x09,0x06,0x16,0x74,0xb5,0x43,0x08,0xec,0x8e,0x43,0x08,0x1b,0x4b,0xb2,0x43,0xee,0x5d,0x8b,0x43,
1964 0x48,0x4d,0xad,0x43,0x12,0xa6,0x8a,0x43,0xf3,0xd7,0xa7,0x43,0x74,0xb8,0x8a,0x43,0x08,0x8c,0xb2,0xa0,
1965 0x43,0xcd,0xf8,0x8a,0x43,0x68,0x46,0x9b,0x43,0x79,0x8f,0x87,0x43,0x49,0xc9,0x96,0x43,0xe9,0x3e,0x82,
1966 0x43,0x08,0x60,0x5c,0x97,0x43,0xa1,0xde,0x8b,0x43,0x4e,0xa0,0x93,0x43,0x31,0x3b,0x93,0x43,0x9f,0xea,
1967 0x8d,0x43,0x27,0x8d,0x99,0x43,0x08,0x07,0xe0,0x8c,0x43,0x06,0x34,0x9b,0x43,0x38,0xe9,0x8c,0x43,0x46,
1968 0x0a,0x9e,0x43,0x3d,0xcc,0x8b,0x43,0xb2,0x06,0xa2,0x43,0x08,0xf1,0x40,0x8a,0x43,0xb0,0x12,0xa4,0x43,
1969 0x39,0xd1,0x88,0x43,0x76,0x43,0xa6,0x43,0xfa,0x06,0x88,0x43,0xa4,0x75,0xa9,0x43,0x08,0x19,0x6c,0x88,
1970 0x43,0x9f,0x9e,0xac,0x43,0x66,0xeb,0x87,0x43,0x44,0x76,0xb0,0x43,0x6b,0xce,0x86,0x43,0x3b,0xbc,0xb4,
1971 0x43,0x08,0xa9,0x8c,0x85,0x43,0x06,0xd0,0xb5,0x43,0xfa,0xee,0x83,0x43,0x74,0xa3,0xb6,0x43,0x3d,0x90,
1972 0x81,0x43,0x31,0xf6,0xb6,0x43,0x08,0x9d,0x61,0x7d,0x43,0xee,0x48,0xb7,0x43,0x3b,0x1f,0x75,0x43,0xcf,
1973 0xe3,0xb6,0x43,0xee,0x6f,0x6d,0x43,0x68,0xe2,0xb5,0x43,0x08,0xd4,0xed,0x6b,0x43,0x87,0x2f,0xb2,0x43,
1974 0x0e,0xc9,0x6b,0x43,0xa7,0x7c,0xae,0x43,0x98,0xfa,0x67,0x43,0xab,0x53,0xab,0x43,0x08,0x25,0x2c,0x64,
1975 0x43,0x33,0xa2,0xa8,0x43,0x40,0x96,0x61,0x43,0xc3,0xc2,0xa5,0x43,0x64,0xde,0x60,0x43,0xfa,0xa2,0xa2,
1976 0x43,0x08,0xb0,0x5d,0x60,0x43,0x06,0x4c,0x9f,0x43,0x9a,0xca,0x5f,0x43,0x38,0x3d,0x9b,0x43,0x3b,0x8f,
1977 0x5c,0x43,0x85,0xb0,0x98,0x43,0x08,0x42,0x36,0x51,0x43,0x3d,0xf0,0x91,0x43,0xcd,0x4f,0x49,0x43,0xdb,
1978 0xb9,0x8b,0x43,0xe0,0xdb,0x44,0x43,0x42,0x8b,0x84,0x43,0x08,0x7e,0xc9,0x44,0x43,0x8a,0x57,0x8d,0x43,
1979 0xbc,0x6c,0x0f,0x43,0x23,0x62,0x8e,0x43,0xf5,0x17,0x07,0x43,0xc5,0x3e,0x8f,0x43,0x09,0x06,0xe0,0xea,
1980 0x76,0x43,0xab,0xef,0xc5,0x43,0x08,0x12,0x00,0x79,0x43,0xab,0xcb,0xbf,0x43,0x79,0xb9,0x6d,0x43,0x7e,
1981 0x8d,0xba,0x43,0xee,0x6f,0x6d,0x43,0x98,0xeb,0xb5,0x43,0x08,0xe0,0x02,0x7b,0x43,0x5f,0x1c,0xb8,0x43,
1982 0x85,0x2c,0x82,0x43,0xe9,0x65,0xb8,0x43,0xd6,0xb2,0x86,0x43,0xc6,0x05,0xb5,0x43,0x08,0x03,0xcd,0x85,
1983 0x43,0x5a,0x39,0xb9,0x43,0xe4,0x4f,0x81,0x43,0xdb,0xd4,0xbf,0x43,0xdf,0x6c,0x82,0x43,0xbc,0x93,0xc5,
1984 0x43,0x09,0x06,0xf0,0xd0,0x22,0x43,0x5d,0x19,0x08,0x43,0x08,0xbc,0xab,0x49,0x43,0x4a,0x35,0x29,0x43,
1985 0xcb,0xf7,0x65,0x43,0xce,0x37,0x45,0x43,0x0e,0x99,0x63,0x43,0x67,0xc6,0x5c,0x43,0x09,0x06,0x05,0x94,
1986 0xab,0x43,0xc2,0x13,0x04,0x43,0x08,0x9f,0x26,0x98,0x43,0x11,0x42,0x25,0x43,0x97,0x00,0x8a,0x43,0x32,
1987 0x32,0x41,0x43,0xf5,0x2f,0x8b,0x43,0xc7,0xc0,0x58,0x43,0x09,0x06,0x8f,0x85,0x48,0x43,0xe0,0xa8,0x8c,
1988 0x43,0x08,0x55,0xaa,0x48,0x43,0xe0,0xa8,0x8c,0x43,0x6b,0x3d,0x49,0x43,0xc1,0x43,0x8c,0x43,0x31,0x62,
1989 0x49,0x43,0xc1,0x43,0x8c,0x43,0x08,0x2f,0xe3,0x2f,0x43,0xad,0xe7,0x98,0x43,0xff,0x0d,0x0d,0x43,0xad,
1990 0xf3,0x9a,0x43,0xf0,0xaf,0xcc,0x42,0x74,0x00,0x97,0x43,0x08,0xbb,0xa2,0xf7,0x42,0x93,0x4d,0x93,0x43,
1991 0x5e,0x19,0x08,0x43,0x5a,0x2a,0x87,0x43,0x23,0x6e,0x10,0x43,0x42,0x97,0x86,0x43,0x08,0xca,0xe8,0x33,
1992 0x43,0x1b,0x3c,0x80,0x43,0x80,0xe8,0x4d,0x43,0xda,0xf4,0x70,0x43,0xae,0x0e,0x4f,0x43,0x2b,0x1b,0x65,
1993 0x43,0x08,0x66,0x96,0x54,0x43,0xa3,0xe1,0x3b,0x43,0x4e,0xc4,0x19,0x43,0xa0,0x1a,0x16,0x43,0x10,0xe2,
1994 0x14,0x43,0x26,0x14,0xe0,0x42,0x08,0x5c,0x91,0x1c,0x43,0xcb,0x27,0xee,0x42,0xa9,0x40,0x24,0x43,0x71,
1995 0x3b,0xfc,0x42,0xf3,0xef,0x2b,0x43,0x8b,0x27,0x05,0x43,0x08,0xe2,0x4b,0x2c,0x43,0x48,0x86,0x07,0x43,
1996 0x79,0x62,0x2f,0x43,0x05,0xe5,0x09,0x43,0x55,0x32,0x34,0x43,0xa0,0xd2,0x09,0x43,0x08,0x74,0xa3,0x36,
1997 0x43,0x3a,0xd1,0x08,0x43,0x7e,0x81,0x38,0x43,0x09,0xd4,0x0a,0x43,0x0d,0xba,0x39,0x43,0xa0,0xea,0x0d,
1998 0x43,0x08,0x6f,0xe4,0x3d,0x43,0x43,0xc7,0x0e,0x43,0xd6,0xe5,0x3e,0x43,0xc4,0x4a,0x11,0x43,0x55,0x7a,
1999 0x40,0x43,0x59,0x72,0x13,0x43,0x08,0x55,0x92,0x44,0x43,0xbf,0x73,0x14,0x43,0x23,0x95,0x46,0x43,0xa5,
2000 0x09,0x17,0x43,0xe0,0xf3,0x48,0x43,0xfe,0x55,0x19,0x43,0x08,0xcd,0x4f,0x49,0x43,0xaa,0x10,0x1c,0x43,
2001 0x61,0x77,0x4b,0x43,0xfe,0x6d,0x1d,0x43,0x80,0xe8,0x4d,0x43,0x2b,0x94,0x1e,0x43,0x08,0x58,0xc9,0x51,
2002 0x43,0x41,0x27,0x1f,0x43,0x9b,0x82,0x53,0x43,0x35,0x72,0x20,0x43,0x53,0xf2,0x54,0x43,0x88,0xcf,0x21,
2003 0x43,0x08,0x7b,0x29,0x55,0x43,0xe8,0x0a,0x25,0x43,0xb2,0x2d,0x58,0x43,0xef,0xe8,0x26,0x43,0x9b,0xb2,
2004 0x5b,0x43,0xd0,0x8f,0x28,0x43,0x08,0x5f,0xef,0x5f,0x43,0xeb,0x11,0x2a,0x43,0xfd,0xdc,0x5f,0x43,0x6e,
2005 0x95,0x2c,0x43,0x3b,0xa7,0x60,0x43,0x2b,0xf4,0x2e,0x43,0x08,0x06,0xbb,0x61,0x43,0xfd,0xe5,0x31,0x43,
2006 0xe7,0x61,0x63,0x43,0xef,0x30,0x33,0x43,0x53,0x52,0x65,0x43,0xa3,0xb1,0x33,0x43,0x08,0x12,0xa0,0x68,
2007 0x43,0x7f,0x69,0x34,0x43,0x40,0xc6,0x69,0x43,0x64,0xff,0x36,0x43,0x7e,0x90,0x6a,0x43,0x71,0xcc,0x39,
2008 0x43,0x08,0xbc,0x5a,0x6b,0x43,0x51,0x73,0x3b,0x43,0xc1,0x49,0x6c,0x43,0xa5,0xd0,0x3c,0x43,0xe0,0xba,
2009 0x6e,0x43,0xb8,0x74,0x3c,0x43,0x08,0x6b,0x1c,0x73,0x43,0x13,0xc1,0x3e,0x43,0x40,0xf6,0x71,0x43,0xce,
2010 0x1f,0x41,0x43,0x55,0x89,0x72,0x43,0x8d,0x7e,0x43,0x43,0x08,0x68,0x2d,0x72,0x43,0x89,0xae,0x4b,0x43,
2011 0xc1,0x79,0x74,0x43,0xcb,0x78,0x4c,0x43,0x55,0xa1,0x76,0x43,0x5b,0xb1,0x4d,0x43,0x08,0xa2,0x38,0x7a,
2012 0x43,0xd1,0x56,0x4e,0x43,0x85,0xb6,0x78,0x43,0xb1,0x15,0x54,0x43,0x83,0xc7,0x77,0x43,0x89,0x0e,0x5c,
2013 0x43,0x08,0xcf,0x46,0x77,0x43,0x0f,0x81,0x5f,0x43,0x1a,0xde,0x7a,0x43,0xce,0xc7,0x5d,0x43,0x42,0x73,
2014 0x80,0x43,0x99,0xc3,0x5a,0x43,0x08,0x85,0x2c,0x82,0x43,0xf6,0xe6,0x59,0x43,0x81,0x3d,0x81,0x43,0x16,
2015 0x10,0x50,0x43,0xd6,0x8e,0x80,0x43,0x5b,0x99,0x49,0x43,0x08,0xc4,0xea,0x80,0x43,0x22,0x95,0x46,0x43,
2016 0xfa,0xe2,0x81,0x43,0xda,0xec,0x43,0x43,0x78,0x77,0x83,0x43,0xe4,0xb2,0x41,0x43,0x08,0x8a,0x27,0x85,
2017 0x43,0x86,0x77,0x3e,0x43,0x0c,0x9f,0x85,0x43,0x07,0xf4,0x3b,0x43,0x8f,0x16,0x86,0x43,0xe6,0x82,0x39,
2018 0x43,0x08,0x85,0x44,0x86,0x43,0x37,0xd9,0x35,0x43,0x1e,0x4f,0x87,0x43,0xe1,0x7b,0x34,0x43,0xdf,0x90,
2019 0x88,0x43,0xb6,0x55,0x33,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0xe5,0x31,0x43,0xfa,0x12,0x8a,0x43,0xbf,
2020 0x03,0x2d,0x43,0x19,0x78,0x8a,0x43,0x45,0x5e,0x2c,0x43,0x08,0x03,0xf1,0x8b,0x43,0xac,0x47,0x29,0x43,
2021 0x2f,0x17,0x8d,0x43,0x45,0x46,0x28,0x43,0xc8,0x21,0x8e,0x43,0x30,0xb3,0x27,0x43,0x08,0xa9,0xc8,0x8f,
2022 0x43,0xef,0xe8,0x26,0x43,0xbf,0x5b,0x90,0x43,0x5b,0xc1,0x24,0x43,0x10,0xca,0x90,0x43,0xa0,0x62,0x22,
2023 0x43,0x08,0x26,0x5d,0x91,0x43,0xbb,0xcc,0x1f,0x43,0xf0,0x70,0x92,0x43,0x78,0x13,0x1e,0x43,0x77,0xd7,
2024 0x93,0x43,0x73,0x24,0x1d,0x43,0x08,0x65,0x3f,0x96,0x43,0xce,0x58,0x1b,0x43,0xbe,0x7f,0x96,0x43,0xbf,
2025 0x8b,0x18,0x43,0x60,0x5c,0x97,0x43,0xb6,0xad,0x16,0x43,0x08,0xba,0xa8,0x99,0x43,0x78,0xcb,0x11,0x43,
2026 0x49,0xe1,0x9a,0x43,0x78,0xcb,0x11,0x43,0x01,0x51,0x9c,0x43,0x73,0xdc,0x10,0x43,0x08,0x72,0x24,0x9d,
2027 0x43,0xd2,0xff,0x0f,0x43,0x1c,0xd3,0x9d,0x43,0x07,0xec,0x0e,0x43,0xeb,0xc9,0x9d,0x43,0xe8,0x7a,0x0c,
2028 0x43,0x08,0x60,0x80,0x9d,0x43,0xd7,0xbe,0x08,0x43,0x4d,0xe8,0x9f,0x43,0x86,0x50,0x08,0x43,0x25,0xbd,
2029 0xa1,0x43,0x5b,0x2a,0x07,0x43,0x08,0x99,0x7f,0xa3,0x43,0xc9,0xf1,0x05,0x43,0x48,0x1d,0xa5,0x43,0x86,
2030 0x38,0x04,0x43,0x6c,0x71,0xa6,0x43,0x18,0x59,0x01,0x43,0x08,0x32,0x96,0xa6,0x43,0x6e,0x64,0xff,0x42,
2031 0x48,0x29,0xa7,0x43,0xed,0xcf,0xfd,0x42,0x5f,0xbc,0xa7,0x43,0x71,0x3b,0xfc,0x42,0x08,0xf3,0xe3,0xa9,
2032 0x43,0xf7,0x7d,0xf7,0x42,0xd8,0x6d,0xaa,0x43,0x45,0xe5,0xf2,0x42,0x48,0x41,0xab,0x43,0xcb,0x27,0xee,
2033 0x42,0x08,0x24,0xf9,0xab,0x43,0x52,0x6a,0xe9,0x42,0xee,0x0c,0xad,0x43,0x4c,0x8c,0xe7,0x42,0x1b,0x33,
2034 0xae,0x43,0xcc,0xf7,0xe5,0x42,0x08,0xaa,0x6b,0xaf,0x43,0xe8,0x61,0xe3,0x42,0x90,0xf5,0xaf,0x43,0xc9,
2035 0xf0,0xe0,0x42,0xe0,0x63,0xb0,0x43,0xe5,0x5a,0xde,0x42,0x08,0xaa,0x83,0xb3,0x43,0x29,0x2d,0x09,0x43,
2036 0x6a,0xfe,0x8e,0x43,0xb8,0x74,0x3c,0x43,0xd5,0x06,0x95,0x43,0xe6,0x79,0x67,0x43,0x08,0x2f,0x53,0x97,
2037 0x43,0xe9,0xb0,0x74,0x43,0xa8,0x28,0xa0,0x43,0x43,0xfd,0x76,0x43,0x83,0x28,0xad,0x43,0x17,0x59,0x81,
2038 0x43,0x08,0x3d,0xe7,0xbf,0x43,0x4b,0x8d,0x8c,0x43,0xae,0x96,0xba,0x43,0x66,0x27,0x92,0x43,0x15,0xe0,
2039 0xc7,0x43,0x6f,0x11,0x96,0x43,0x08,0x7e,0x5d,0xb2,0x43,0xdb,0x01,0x98,0x43,0x9e,0x56,0xa0,0x43,0x80,
2040 0xc1,0x97,0x43,0x69,0x2e,0x97,0x43,0x31,0x17,0x8d,0x43,0x09,0x06,0xab,0xa7,0x39,0x43,0x67,0x0f,0x0e,
2041 0x43,0x08,0xdb,0xbc,0x3b,0x43,0xe8,0x92,0x10,0x43,0xb5,0x85,0x3b,0x43,0x97,0x3c,0x14,0x43,0xab,0xa7,
2042 0x39,0x43,0x0c,0x0b,0x18,0x43,0x09,0x06,0xca,0x30,0x40,0x43,0x30,0x3b,0x13,0x43,0x08,0x17,0xc8,0x43,
2043 0x43,0xa5,0x09,0x17,0x43,0x7e,0xc9,0x44,0x43,0x1a,0xd8,0x1a,0x43,0x9d,0x22,0x43,0x43,0x8d,0xa6,0x1e,
2044 0x43,0x09,0x06,0xc8,0x78,0x4c,0x43,0xed,0xc9,0x1d,0x43,0x08,0x0b,0x32,0x4e,0x43,0x22,0xce,0x20,0x43,
2045 0x23,0xc5,0x4e,0x43,0x58,0xd2,0x23,0x43,0x0b,0x32,0x4e,0x43,0x2b,0xc4,0x26,0x43,0x09,0x06,0xec,0x08,
2046 0x58,0x43,0xc7,0xb1,0x26,0x43,0x08,0x02,0x9c,0x58,0x43,0xef,0x00,0x2b,0x43,0xd9,0x64,0x58,0x43,0x02,
2047 0xbd,0x2e,0x43,0x10,0x51,0x57,0x43,0x37,0xc1,0x31,0x43,0x09,0x06,0xcb,0xdf,0x61,0x43,0x4a,0x65,0x31,
2048 0x43,0x08,0xbe,0x2a,0x63,0x43,0xbd,0x33,0x35,0x43,0x32,0xe1,0x62,0x43,0x56,0x4a,0x38,0x43,0xde,0x83,
2049 0x61,0x43,0x3c,0xe0,0x3a,0x43,0x09,0x06,0x1c,0x7e,0x6a,0x43,0x5b,0x39,0x39,0x43,0x08,0x31,0x11,0x6b,
2050 0x43,0x0c,0xd2,0x3d,0x43,0x1c,0x7e,0x6a,0x43,0x13,0xd9,0x42,0x43,0xd9,0xc4,0x68,0x43,0xcb,0x60,0x48,
2051 0x43,0x09,0x06,0xe5,0xc1,0x73,0x43,0x16,0xf8,0x4b,0x43,0x08,0xa6,0xf7,0x72,0x43,0xb1,0xfd,0x4f,0x43,
2052 0x3b,0x07,0x71,0x43,0x4a,0x14,0x53,0x43,0xa2,0xf0,0x6d,0x43,0x7c,0x29,0x55,0x43,0x09,0x06,0x00,0x8d,
2053 0xa6,0x43,0xef,0x21,0x01,0x43,0x08,0x52,0xfb,0xa6,0x43,0xce,0xc8,0x02,0x43,0xe6,0x16,0xa7,0x43,0x51,
2054 0x4c,0x05,0x43,0x3b,0x68,0xa6,0x43,0x4c,0x75,0x08,0x43,0x09,0x06,0xde,0x20,0xa1,0x43,0x86,0x50,0x08,
2055 0x43,0x08,0xd4,0x4e,0xa1,0x43,0xd3,0xe7,0x0b,0x43,0xb5,0xe9,0xa0,0x43,0x59,0x5a,0x0f,0x43,0xba,0xcc,
2056 0x9f,0x43,0x54,0x83,0x12,0x43,0x09,0x06,0x77,0xfb,0x99,0x43,0x6c,0x16,0x13,0x43,0x08,0xde,0xfc,0x9a,
2057 0x43,0x4a,0xbd,0x14,0x43,0x06,0x34,0x9b,0x43,0xfe,0x55,0x19,0x43,0x13,0xe9,0x99,0x43,0x41,0x27,0x1f,
2058 0x43,0x09,0x06,0x46,0xce,0x93,0x43,0x26,0xa5,0x1d,0x43,0x08,0xe7,0xaa,0x94,0x43,0xbb,0xcc,0x1f,0x43,
2059 0x18,0xb4,0x94,0x43,0xa8,0x40,0x24,0x43,0xe2,0xbb,0x93,0x43,0x21,0xfe,0x28,0x43,0x09,0x06,0xb1,0x8e,
2060 0x8d,0x43,0xa8,0x58,0x28,0x43,0x08,0x19,0x90,0x8e,0x43,0x54,0x13,0x2b,0x43,0xa4,0xd9,0x8e,0x43,0x84,
2061 0x40,0x31,0x43,0x46,0xaa,0x8d,0x43,0x29,0x24,0x37,0x43,0x09,0x06,0xd6,0xbe,0x88,0x43,0xef,0x30,0x33,
2062 0x43,0x08,0x0c,0xb7,0x89,0x43,0x0e,0xa2,0x35,0x43,0xc0,0x37,0x8a,0x43,0x7a,0xaa,0x3b,0x43,0xbb,0x48,
2063 0x89,0x43,0xbb,0x7b,0x41,0x43,0x09,0x06,0x3a,0xad,0x82,0x43,0xc4,0x59,0x43,0x43,0x08,0xd2,0xb7,0x83,
2064 0x43,0x2b,0x5b,0x44,0x43,0x35,0xd6,0x85,0x43,0x48,0xf5,0x49,0x43,0x42,0x97,0x86,0x43,0xc4,0xa1,0x4f,
2065 0x43,0x09,0x06,0x9c,0xb3,0x80,0x43,0x48,0x55,0x5a,0x43,0x08,0xff,0xc5,0x80,0x43,0x09,0x73,0x55,0x43,
2066 0x93,0xe1,0x80,0x43,0x0f,0x39,0x53,0x43,0xf1,0xbe,0x7e,0x43,0x18,0xe7,0x4c,0x43,0x09,0x06,0xe0,0x02,
2067 0x7b,0x43,0x92,0xec,0x5d,0x43,0x08,0x09,0x3a,0x7b,0x43,0xf0,0xf7,0x58,0x43,0x09,0x3a,0x7b,0x43,0xe6,
2068 0x31,0x5b,0x43,0xe0,0x02,0x7b,0x43,0xa8,0x4f,0x56,0x43,0x09,0x06,0x39,0x4f,0x7d,0x43,0x3e,0x8f,0x5c,
2069 0x43,0x08,0xe9,0xe0,0x7c,0x43,0x03,0x9c,0x58,0x43,0x1e,0x2b,0x81,0x43,0x7f,0x30,0x5a,0x43,0xff,0x73,
2070 0x7d,0x43,0xf6,0xb6,0x51,0x43,0x09,0x06,0x5c,0xb8,0x52,0x43,0x28,0x21,0x87,0x43,0x08,0xae,0x3e,0x57,
2071 0x43,0x12,0x9a,0x88,0x43,0x23,0xf5,0x56,0x43,0x04,0xf1,0x8b,0x43,0x25,0xfc,0x5b,0x43,0x85,0x74,0x8e,
2072 0x43,0x08,0x2f,0xf2,0x61,0x43,0x8e,0x52,0x90,0x43,0xd9,0xdc,0x6c,0x43,0x85,0x74,0x8e,0x43,0xc6,0x20,
2073 0x69,0x43,0x3d,0xd8,0x8d,0x43,0x08,0x6d,0x8c,0x5a,0x43,0xf5,0x3b,0x8d,0x43,0x3d,0x77,0x58,0x43,0xa1,
2074 0xc6,0x87,0x43,0xf8,0xed,0x5e,0x43,0x5e,0x0d,0x86,0x43,0x09,0x06,0xde,0xcc,0x92,0x43,0xf7,0x17,0x87,
2075 0x43,0x08,0xb6,0x89,0x90,0x43,0xae,0x87,0x88,0x43,0x4a,0xa5,0x90,0x43,0xa1,0xde,0x8b,0x43,0xf9,0x2a,
2076 0x8e,0x43,0x23,0x62,0x8e,0x43,0x08,0xf5,0x2f,0x8b,0x43,0x5c,0x49,0x90,0x43,0x35,0xd6,0x85,0x43,0x8e,
2077 0x46,0x8e,0x43,0x3d,0xb4,0x87,0x43,0x47,0xaa,0x8d,0x43,0x08,0x6a,0xfe,0x8e,0x43,0xff,0x0d,0x8d,0x43,
2078 0xbb,0x6c,0x8f,0x43,0xf7,0x17,0x87,0x43,0x5c,0x31,0x8c,0x43,0xb2,0x5e,0x85,0x43,0x09,0x06,0x60,0x38,
2079 0x91,0x43,0x69,0x5d,0x7a,0x43,0x08,0x34,0x1e,0x92,0x43,0x1e,0x5b,0x89,0x43,0x04,0x63,0x7e,0x43,0x5e,
2080 0x01,0x84,0x43,0x59,0x2a,0x87,0x43,0x0d,0xcf,0x8d,0x43,0x09,0x03,0x04,0x06,0x5a,0x18,0x63,0x43,0x82,
2081 0x79,0x8b,0x43,0x08,0x25,0x2c,0x64,0x43,0x82,0x79,0x8b,0x43,0x2a,0x1b,0x65,0x43,0x9d,0xef,0x8a,0x43,
2082 0x2a,0x1b,0x65,0x43,0xc1,0x37,0x8a,0x43,0x08,0x2a,0x1b,0x65,0x43,0x17,0x89,0x89,0x43,0x25,0x2c,0x64,
2083 0x43,0x31,0xff,0x88,0x43,0x5a,0x18,0x63,0x43,0x31,0xff,0x88,0x43,0x08,0xf3,0x16,0x62,0x43,0x31,0xff,
2084 0x88,0x43,0xee,0x27,0x61,0x43,0x17,0x89,0x89,0x43,0xee,0x27,0x61,0x43,0xc1,0x37,0x8a,0x43,0x08,0xee,
2085 0x27,0x61,0x43,0x9d,0xef,0x8a,0x43,0xf3,0x16,0x62,0x43,0x82,0x79,0x8b,0x43,0x5a,0x18,0x63,0x43,0x82,
2086 0x79,0x8b,0x43,0x09,0x06,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x08,0x34,0xee,0x89,0x43,0x82,0x79,
2087 0x8b,0x43,0x85,0x5c,0x8a,0x43,0x9d,0xef,0x8a,0x43,0x85,0x5c,0x8a,0x43,0xc1,0x37,0x8a,0x43,0x08,0x85,
2088 0x5c,0x8a,0x43,0x17,0x89,0x89,0x43,0x34,0xee,0x89,0x43,0x31,0xff,0x88,0x43,0x4f,0x64,0x89,0x43,0x31,
2089 0xff,0x88,0x43,0x08,0x9c,0xe3,0x88,0x43,0x31,0xff,0x88,0x43,0x19,0x6c,0x88,0x43,0x17,0x89,0x89,0x43,
2090 0x19,0x6c,0x88,0x43,0xc1,0x37,0x8a,0x43,0x08,0x19,0x6c,0x88,0x43,0x9d,0xef,0x8a,0x43,0x9c,0xe3,0x88,
2091 0x43,0x82,0x79,0x8b,0x43,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x09,0x02,0x04,0x06,0x19,0x60,0x86,
2092 0x43,0xec,0xed,0xa3,0x43,0x08,0x35,0xd6,0x85,0x43,0x76,0x43,0xa6,0x43,0x93,0xe1,0x80,0x43,0x57,0x02,
2093 0xac,0x43,0x61,0xd8,0x80,0x43,0x87,0x17,0xae,0x43,0x08,0xa5,0x85,0x80,0x43,0xc3,0xfe,0xaf,0x43,0xce,
2094 0xbc,0x80,0x43,0x83,0x40,0xb1,0x43,0xa5,0x91,0x82,0x43,0x79,0x6e,0xb1,0x43,0x08,0x23,0x26,0x84,0x43,
2095 0x40,0x93,0xb1,0x43,0x30,0xe7,0x84,0x43,0xbe,0x1b,0xb1,0x43,0x11,0x82,0x84,0x43,0xab,0x6b,0xaf,0x43,
2096 0x08,0xb7,0x41,0x84,0x43,0x3b,0x98,0xae,0x43,0xb7,0x41,0x84,0x43,0xc3,0xf2,0xad,0x43,0xa1,0xae,0x83,
2097 0x43,0x83,0x28,0xad,0x43,0x08,0xb2,0x52,0x83,0x43,0x80,0x39,0xac,0x43,0x81,0x49,0x83,0x43,0xf0,0x00,
2098 0xab,0x43,0xe4,0x67,0x85,0x43,0x76,0x4f,0xa8,0x43,0x08,0x9c,0xd7,0x86,0x43,0xd1,0x83,0xa6,0x43,0xec,
2099 0x45,0x87,0x43,0x01,0x75,0xa2,0x43,0x19,0x60,0x86,0x43,0xec,0xed,0xa3,0x43,0x09,0x06,0xd9,0xdc,0x6c,
2100 0x43,0x14,0x25,0xa4,0x43,0x08,0xa2,0xf0,0x6d,0x43,0x9f,0x7a,0xa6,0x43,0x47,0xec,0x77,0x43,0x80,0x39,
2101 0xac,0x43,0xa9,0xfe,0x77,0x43,0xb0,0x4e,0xae,0x43,0x08,0x23,0xa4,0x78,0x43,0xea,0x35,0xb0,0x43,0xd2,
2102 0x35,0x78,0x43,0xab,0x77,0xb1,0x43,0xc1,0x79,0x74,0x43,0xa2,0xa5,0xb1,0x43,0x08,0xc6,0x50,0x71,0x43,
2103 0x68,0xca,0xb1,0x43,0xab,0xce,0x6f,0x43,0xe7,0x52,0xb1,0x43,0xea,0x98,0x70,0x43,0xd4,0xa2,0xaf,0x43,
2104 0x08,0x9d,0x19,0x71,0x43,0x96,0xd8,0xae,0x43,0x9d,0x19,0x71,0x43,0xec,0x29,0xae,0x43,0xca,0x3f,0x72,
2105 0x43,0xab,0x5f,0xad,0x43,0x08,0xa6,0xf7,0x72,0x43,0xa7,0x70,0xac,0x43,0x09,0x0a,0x73,0x43,0x17,0x38,
2106 0xab,0x43,0x44,0xcd,0x6e,0x43,0x9f,0x86,0xa8,0x43,0x08,0xd4,0xed,0x6b,0x43,0xf8,0xba,0xa6,0x43,0x31,
2107 0x11,0x6b,0x43,0x2a,0xac,0xa2,0x43,0xd9,0xdc,0x6c,0x43,0x14,0x25,0xa4,0x43,0x09,0x01,0x05,0x06,0x66,
2108 0x5d,0x7a,0x43,0x74,0xeb,0xc2,0x43,0x08,0x09,0x22,0x77,0x43,0x50,0xbb,0xc7,0x43,0xe9,0xe0,0x7c,0x43,
2109 0xf5,0x86,0xc9,0x43,0x8f,0x94,0x7a,0x43,0xc5,0x95,0xcd,0x43,0x09,0x06,0x08,0x98,0x80,0x43,0x6b,0x19,
2110 0xc3,0x43,0x08,0xb7,0x35,0x82,0x43,0x79,0xf2,0xc7,0x43,0xf1,0xbe,0x7e,0x43,0x1e,0xbe,0xc9,0x43,0x73,
2111 0x7c,0x80,0x43,0xec,0xcc,0xcd,0x43,0x09,0x06,0x28,0xab,0x7d,0x43,0xae,0xde,0xc6,0x43,0x08,0x1e,0xcd,
2112 0x7b,0x43,0x8a,0xa2,0xc9,0x43,0x30,0x89,0x7f,0x43,0x5c,0x94,0xcc,0x43,0x28,0xab,0x7d,0x43,0x42,0x2a,
2113 0xcf,0x43,0x09,0x01,0x05,0x06,0x24,0x14,0xe0,0x42,0xf5,0x77,0x97,0x43,0x08,0xf7,0x1d,0xe7,0x42,0x74,
2114 0x00,0x97,0x43,0x4d,0x93,0xec,0x42,0xdb,0xf5,0x95,0x43,0x29,0x4b,0xed,0x42,0xcd,0x34,0x95,0x43,0x09,
2115 0x06,0x29,0x7b,0xf5,0x42,0x6f,0x1d,0x98,0x43,0x08,0xe4,0xf1,0xfb,0x42,0x61,0x5c,0x97,0x43,0xdb,0x7d,
2116 0x01,0x43,0xb2,0xbe,0x95,0x43,0x55,0x23,0x02,0x43,0xe7,0xaa,0x94,0x43,0x09,0x06,0x98,0xdc,0x03,0x43,
2117 0xbe,0x8b,0x98,0x43,0x08,0x66,0xdf,0x05,0x43,0x47,0xe6,0x97,0x43,0xae,0x87,0x08,0x43,0x98,0x48,0x96,
2118 0x43,0x61,0x08,0x09,0x43,0xd6,0x06,0x95,0x43,0x09,0x06,0x31,0x0b,0x0b,0x43,0x8e,0x82,0x98,0x43,0x08,
2119 0xdb,0xc5,0x0d,0x43,0x80,0xc1,0x97,0x43,0xd6,0xee,0x10,0x43,0xa9,0xec,0x95,0x43,0x79,0xcb,0x11,0x43,
2120 0x55,0x8f,0x94,0x43,0x09,0x06,0xd1,0x2f,0x18,0x43,0xdb,0x01,0x98,0x43,0x08,0xad,0xe7,0x18,0x43,0x38,
2121 0x25,0x97,0x43,0x8a,0x9f,0x19,0x43,0x80,0xb5,0x95,0x43,0xd6,0x1e,0x19,0x43,0xe0,0xd8,0x94,0x43,0x09,
2122 0x06,0x9a,0x5b,0x1d,0x43,0x58,0x8a,0x97,0x43,0x08,0x01,0x5d,0x1e,0x43,0xf1,0x88,0x96,0x43,0x2f,0x83,
2123 0x1f,0x43,0x19,0xb4,0x94,0x43,0x19,0xf0,0x1e,0x43,0x6f,0x05,0x94,0x43,0x09,0x06,0x0b,0x53,0x24,0x43,
2124 0xae,0xdb,0x96,0x43,0x08,0x25,0xd5,0x25,0x43,0x50,0xac,0x95,0x43,0x53,0xfb,0x26,0x43,0x8a,0x7b,0x93,
2125 0x43,0x76,0x43,0x26,0x43,0xb7,0x95,0x92,0x43,0x09,0x06,0x76,0x5b,0x2a,0x43,0x47,0xda,0x95,0x43,0x08,
2126 0xf3,0xef,0x2b,0x43,0x10,0xe2,0x94,0x43,0x6d,0x95,0x2c,0x43,0xae,0xc3,0x92,0x43,0x68,0xa6,0x2b,0x43,
2127 0x47,0xc2,0x91,0x43,0x09,0x06,0x36,0xc1,0x31,0x43,0x2c,0x58,0x94,0x43,0x08,0x8c,0x1e,0x33,0x43,0x31,
2128 0x3b,0x93,0x43,0x79,0x7a,0x33,0x43,0xff,0x25,0x91,0x43,0xd9,0x9d,0x32,0x43,0xc1,0x5b,0x90,0x43,0x09,
2129 0x06,0x25,0x35,0x36,0x43,0x31,0x3b,0x93,0x43,0x08,0x3f,0xb7,0x37,0x43,0xc1,0x67,0x92,0x43,0xe0,0x93,
2130 0x38,0x43,0xae,0xb7,0x90,0x43,0x7e,0x81,0x38,0x43,0x0d,0xdb,0x8f,0x43,0x09,0x06,0xb5,0x85,0x3b,0x43,
2131 0xe4,0xaf,0x91,0x43,0x08,0xcf,0x07,0x3d,0x43,0x9d,0x13,0x91,0x43,0xbc,0x63,0x3d,0x43,0x47,0xb6,0x8f,
2132 0x43,0xe5,0x9a,0x3d,0x43,0x74,0xd0,0x8e,0x43,0x09,0x06,0xae,0xc6,0x42,0x43,0xa4,0xd9,0x8e,0x43,0x08,
2133 0xca,0x48,0x44,0x43,0xfa,0x2a,0x8e,0x43,0xa2,0x11,0x44,0x43,0x9d,0xfb,0x8c,0x43,0x55,0x92,0x44,0x43,
2134 0x0d,0xc3,0x8b,0x43,0x09,0x06,0x39,0x10,0xc3,0x43,0x34,0x36,0x96,0x43,0x08,0x92,0x44,0xc1,0x43,0xe4,
2135 0xc7,0x95,0x43,0x6f,0xf0,0xbf,0x43,0x4b,0xbd,0x94,0x43,0x47,0xb9,0xbf,0x43,0x0b,0xf3,0x93,0x43,0x09,
2136 0x06,0x8f,0x49,0xbe,0x43,0xb7,0xad,0x96,0x43,0x08,0x11,0xb5,0xbc,0x43,0x77,0xe3,0x95,0x43,0x9c,0xf2,
2137 0xba,0x43,0xfa,0x4e,0x94,0x43,0xae,0x96,0xba,0x43,0x31,0x3b,0x93,0x43,0x09,0x06,0xdb,0xb0,0xb9,0x43,
2138 0x10,0xee,0x96,0x43,0x08,0x42,0xa6,0xb8,0x43,0xc8,0x51,0x96,0x43,0x50,0x5b,0xb7,0x43,0x19,0xb4,0x94,
2139 0x43,0xf7,0x1a,0xb7,0x43,0x58,0x72,0x93,0x43,0x09,0x06,0xf2,0x2b,0xb6,0x43,0x10,0xee,0x96,0x43,0x08,
2140 0x9d,0xce,0xb4,0x43,0x04,0x2d,0x96,0x43,0xed,0x30,0xb3,0x43,0x2c,0x58,0x94,0x43,0xce,0xcb,0xb2,0x43,
2141 0xd6,0xfa,0x92,0x43,0x09,0x06,0x5a,0x09,0xb1,0x43,0x19,0xc0,0x96,0x43,0x08,0x6c,0xad,0xb0,0x43,0x77,
2142 0xe3,0x95,0x43,0x7e,0x51,0xb0,0x43,0xc0,0x73,0x94,0x43,0xd8,0x91,0xb0,0x43,0x1e,0x97,0x93,0x43,0x09,
2143 0x06,0x48,0x4d,0xad,0x43,0xbe,0x7f,0x96,0x43,0x08,0x95,0xcc,0xac,0x43,0x58,0x7e,0x95,0x43,0x4d,0x30,
2144 0xac,0x43,0x80,0xa9,0x93,0x43,0xd8,0x79,0xac,0x43,0xd6,0xfa,0x92,0x43,0x09,0x06,0x90,0xd1,0xa9,0x43,
2145 0x14,0xd1,0x95,0x43,0x08,0x83,0x10,0xa9,0x43,0xb7,0xa1,0x94,0x43,0x3b,0x74,0xa8,0x43,0xf1,0x70,0x92,
2146 0x43,0x29,0xd0,0xa8,0x43,0x1e,0x8b,0x91,0x43,0x09,0x06,0x5a,0xcd,0xa6,0x43,0x8a,0x87,0x95,0x43,0x08,
2147 0x1c,0x03,0xa6,0x43,0x23,0x86,0x94,0x43,0x5f,0xb0,0xa5,0x43,0xc1,0x67,0x92,0x43,0xe1,0x27,0xa6,0x43,
2148 0x8a,0x6f,0x91,0x43,0x09,0x06,0xd4,0x5a,0xa3,0x43,0x2c,0x58,0x94,0x43,0x08,0x29,0xac,0xa2,0x43,0x31,
2149 0x3b,0x93,0x43,0x32,0x7e,0xa2,0x43,0xff,0x25,0x91,0x43,0x83,0xec,0xa2,0x43,0x8e,0x52,0x90,0x43,0x09,
2150 0x06,0xf8,0x96,0xa0,0x43,0x1e,0x97,0x93,0x43,0x08,0xeb,0xd5,0x9f,0x43,0x7b,0xba,0x92,0x43,0x99,0x67,
2151 0x9f,0x43,0x9d,0x13,0x91,0x43,0x99,0x67,0x9f,0x43,0xfa,0x36,0x90,0x43,0x09,0x06,0xeb,0xc9,0x9d,0x43,
2152 0xc8,0x39,0x92,0x43,0x08,0xde,0x08,0x9d,0x43,0xb2,0xa6,0x91,0x43,0xe6,0xda,0x9c,0x43,0x2c,0x40,0x90,
2153 0x43,0x52,0xbf,0x9c,0x43,0x5a,0x5a,0x8f,0x43,0x09,0x06,0x37,0x3d,0x9b,0x43,0x85,0x80,0x90,0x43,0x08,
2154 0x2a,0x7c,0x9a,0x43,0xdb,0xd1,0x8f,0x43,0xf0,0xa0,0x9a,0x43,0x7d,0xa2,0x8e,0x43,0x65,0x57,0x9a,0x43,
2155 0xee,0x69,0x8d,0x43,0x09,0x02,0x04,0x06,0x2a,0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x08,0x0d,0x8a,0x31,
2156 0x42,0x9f,0x0e,0x94,0x43,0xf3,0x1f,0x34,0x42,0x3d,0xfc,0x93,0x43,0x63,0xff,0x36,0x42,0xa9,0xe0,0x93,
2157 0x43,0x08,0xb5,0x34,0x5d,0x42,0x0b,0xf3,0x93,0x43,0x6d,0xa4,0x5e,0x42,0x03,0x39,0x98,0x43,0xe7,0x31,
2158 0x5b,0x42,0x93,0x89,0x9d,0x43,0x08,0x02,0x9c,0x58,0x42,0xd4,0x5a,0xa3,0x43,0x38,0x70,0x53,0x42,0x14,
2159 0x49,0xaa,0x43,0xf8,0xed,0x5e,0x42,0x83,0x28,0xad,0x43,0x08,0xea,0x68,0x68,0x42,0x20,0x22,0xaf,0x43,
2160 0x12,0xb8,0x6c,0x42,0xb5,0x49,0xb1,0x43,0x2a,0x4b,0x6d,0x42,0x0d,0x96,0xb3,0x43,0x07,0x2a,0x4b,0x6d,
2161 0x42,0xc6,0x05,0xb5,0x43,0x08,0x87,0x6e,0x6c,0x42,0x68,0xee,0xb7,0x43,0x1c,0x66,0x66,0x42,0x31,0x0e,
2162 0xbb,0x43,0x57,0x11,0x5e,0x42,0x8f,0x49,0xbe,0x43,0x08,0x66,0x96,0x54,0x42,0xb9,0x5c,0xb8,0x43,0x2c,
2163 0x2b,0x3c,0x42,0x68,0xd6,0xb3,0x43,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x07,0x2a,0xf4,0x2e,0x42,
2164 0x61,0xa4,0xa3,0x43,0x08,0x55,0x1a,0x30,0x42,0xf0,0xd0,0xa2,0x43,0xf8,0xf6,0x30,0x42,0xb2,0x06,0xa2,
2165 0x43,0x98,0xd3,0x31,0x42,0xd6,0x4e,0xa1,0x43,0x08,0x1c,0x6f,0x38,0x42,0x2a,0x94,0x9e,0x43,0xc1,0x22,
2166 0x36,0x42,0xf5,0x9b,0x9d,0x43,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x57,
2167 0xa2,0x9b,0x43,0x08,0xab,0x8f,0x35,0x42,0x8a,0xab,0x9b,0x43,0xe9,0x71,0x3a,0x42,0xb2,0xe2,0x9b,0x43,
2168 0xb7,0x74,0x3c,0x42,0x34,0x5a,0x9c,0x43,0x08,0x23,0x7d,0x42,0x42,0x0b,0x2f,0x9e,0x43,0xe5,0x9a,0x3d,
2169 0x42,0x38,0x6d,0xa3,0x43,0x36,0xd9,0x35,0x42,0xf3,0xd7,0xa7,0x43,0x08,0x12,0x61,0x2e,0x42,0xb0,0x42,
2170 0xac,0x43,0x63,0xff,0x36,0x42,0xdd,0x74,0xaf,0x43,0x1e,0xa6,0x45,0x42,0x44,0x82,0xb2,0x43,0x08,0x74,
2171 0x1b,0x4b,0x42,0x79,0x7a,0xb3,0x43,0x10,0x21,0x4f,0x42,0x2a,0x18,0xb5,0x43,0xdb,0x4c,0x54,0x42,0x91,
2172 0x19,0xb6,0x43,0x08,0xee,0x3f,0x65,0x42,0x5f,0x28,0xba,0x43,0xa7,0xaf,0x66,0x42,0xb9,0x50,0xb6,0x43,
2173 0x14,0x58,0x5c,0x42,0xca,0xdc,0xb1,0x43,0x08,0x2c,0x8b,0x4c,0x42,0x4e,0x30,0xac,0x43,0x19,0xcf,0x48,
2174 0x42,0x2a,0xd0,0xa8,0x43,0xbc,0xab,0x49,0x42,0xa9,0x4c,0xa6,0x43,0x08,0x61,0x5f,0x47,0x42,0xfa,0xa2,
2175 0xa2,0x43,0xa7,0xaf,0x66,0x42,0x85,0x98,0x94,0x43,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x07,0x2a,
2176 0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x09,0x06,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x08,0xdc,0xe3,
2177 0xf1,0x41,0xe9,0x9e,0x92,0x43,0xd2,0xe7,0x0b,0x42,0xd6,0x06,0x95,0x43,0x2a,0xf4,0x2e,0x42,0x04,0x21,
2178 0x94,0x43,0x07,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x08,0x87,0x17,0x2e,0x42,0xc3,0x62,0x95,0x43,
2179 0xe7,0x3a,0x2d,0x42,0xf5,0x6b,0x95,0x43,0x44,0x5e,0x2c,0x42,0xf5,0x6b,0x95,0x43,0x08,0xd1,0x47,0x1c,
2180 0x42,0x19,0xc0,0x96,0x43,0x66,0xdf,0x05,0x42,0x38,0x19,0x95,0x43,0x12,0x6a,0x00,0x42,0xb2,0xbe,0x95,
2181 0x43,0x08,0xbb,0x6b,0xea,0x41,0xd6,0x12,0x97,0x43,0x2d,0x82,0xfa,0x41,0x61,0x74,0x9b,0x43,0x7e,0x72,
2182 0x06,0x42,0x8a,0xab,0x9b,0x43,0x08,0xc8,0x39,0x12,0x42,0x4e,0xd0,0x9b,0x43,0x53,0xe3,0x22,0x42,0xc3,
2183 0x86,0x9b,0x43,0x2a,0xf4,0x2e,0x42,0x57,0xa2,0x9b,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,
2184 0x08,0x01,0xa5,0x2a,0x42,0xa4,0x2d,0x9d,0x43,0x96,0x9c,0x24,0x42,0x06,0x40,0x9d,0x43,0x8a,0xb7,0x1d,
2185 0x42,0x9a,0x5b,0x9d,0x43,0x08,0x6b,0x16,0x13,0x42,0xcd,0x64,0x9d,0x43,0x42,0xc7,0x0e,0x42,0x9a,0x5b,
2186 0x9d,0x43,0x23,0x26,0x04,0x42,0xcd,0x64,0x9d,0x43,0x08,0xe6,0x91,0xeb,0x41,0x38,0x49,0x9d,0x43,0x73,
2187 0x7b,0xdb,0x41,0xf5,0x83,0x99,0x43,0x7f,0x60,0xe2,0x41,0x0b,0x0b,0x98,0x43,0x08,0x7f,0x60,0xe2,0x41,
2188 0xec,0x99,0x95,0x43,0xe3,0x5a,0xde,0x41,0xbe,0x7f,0x96,0x43,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,
2189 0x07,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x09,0x06,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x08,
2190 0xd4,0x7e,0x29,0x42,0xab,0x6b,0xaf,0x43,0x4e,0x0c,0x26,0x42,0x44,0x6a,0xae,0x43,0x38,0x79,0x25,0x42,
2191 0xd4,0x96,0xad,0x43,0x08,0x25,0xbd,0x21,0x42,0xe2,0x4b,0xac,0x43,0x49,0x35,0x29,0x42,0x9a,0x97,0xa7,
2192 0x43,0x2a,0xf4,0x2e,0x42,0x61,0xa4,0xa3,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x09,0x06,
2193 0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x08,0x86,0x20,0x80,0x43,0x57,0x41,0xe6,0x43,0x7d,0x4e,0x80,
2194 0x43,0x25,0x38,0xe6,0x43,0xa5,0x85,0x80,0x43,0xf3,0x2e,0xe6,0x43,0x08,0x35,0xca,0x83,0x43,0xd4,0xc9,
2195 0xe5,0x43,0x9c,0xd7,0x86,0x43,0x44,0x91,0xe4,0x43,0xd5,0xca,0x8a,0x43,0x91,0x1c,0xe6,0x43,0x08,0x53,
2196 0x5f,0x8c,0x43,0xf8,0x1d,0xe7,0x43,0x2f,0x17,0x8d,0x43,0x4e,0x7b,0xe8,0x43,0x92,0x29,0x8d,0x43,0x2f,
2197 0x22,0xea,0x43,0x07,0x92,0x29,0x8d,0x43,0x44,0xb5,0xea,0x43,0x08,0xfe,0x0d,0x8d,0x43,0x2a,0x4b,0xed,
2198 0x43,0xe3,0x8b,0x8b,0x43,0x55,0x7d,0xf0,0x43,0xec,0x51,0x89,0x43,0x72,0x0b,0xf4,0x43,0x08,0xcd,0xd4,
2199 0x84,0x43,0x9d,0x55,0xfb,0x43,0xc9,0xe5,0x83,0x43,0x74,0x1e,0xfb,0x43,0x73,0x94,0x84,0x43,0x5a,0x90,
2200 0xf7,0x43,0x08,0xe8,0x62,0x88,0x43,0xfd,0x30,0xee,0x43,0x39,0xc5,0x86,0x43,0xdd,0xbf,0xeb,0x43,0x35,
2201 0xbe,0x81,0x43,0x40,0xde,0xed,0x43,0x08,0x4f,0x34,0x81,0x43,0x36,0x0c,0xee,0x43,0x08,0x98,0x80,0x43,
2202 0xfd,0x30,0xee,0x43,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x40,0xec,
2203 0x43,0x08,0x35,0xbe,0x81,0x43,0x06,0xf7,0xeb,0x43,0x15,0x65,0x83,0x43,0x49,0xa4,0xeb,0x43,0x1e,0x43,
2204 0x85,0x43,0xbe,0x5a,0xeb,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0x18,0xea,0x43,0x42,0x97,0x86,0x43,0x5f,
2205 0x67,0xf4,0x43,0xa9,0x98,0x87,0x43,0xd4,0x1d,0xf4,0x43,0x08,0x5c,0x25,0x8a,0x43,0xcf,0x16,0xef,0x43,
2206 0x46,0xaa,0x8d,0x43,0x5a,0x3c,0xe9,0x43,0x19,0x6c,0x88,0x43,0x53,0x5e,0xe7,0x43,0x08,0xc4,0x02,0x85,
2207 0x43,0x96,0x0b,0xe7,0x43,0x85,0x2c,0x82,0x43,0x83,0x67,0xe7,0x43,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,
2208 0x43,0x07,0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x09,0x06,0xfd,0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,
2209 0x08,0xfa,0x6c,0x78,0x43,0xd1,0xc2,0xe0,0x43,0x25,0x5c,0x6c,0x43,0x25,0x44,0xe8,0x43,0x1d,0xe5,0x7f,
2210 0x43,0x87,0x4a,0xe6,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,0x43,0x08,0xa6,0x27,0x7b,0x43,0x91,
2211 0x28,0xe8,0x43,0xbc,0xa2,0x77,0x43,0xb0,0x8d,0xe8,0x43,0xc6,0x68,0x75,0x43,0x57,0x4d,0xe8,0x43,0x08,
2212 0xe0,0xd2,0x72,0x43,0xab,0x9e,0xe7,0x43,0x50,0x9a,0x71,0x43,0x2a,0x27,0xe7,0x43,0xea,0x98,0x70,0x43,
2213 0x57,0x35,0xe4,0x43,0x08,0x94,0x3b,0x6f,0x43,0x14,0x7c,0xe2,0x43,0xff,0x13,0x6d,0x43,0x06,0xbb,0xe1,
2214 0x43,0xcf,0xfe,0x6a,0x43,0x06,0xbb,0xe1,0x43,0x08,0x44,0x9d,0x66,0x43,0x77,0x8e,0xe2,0x43,0x3b,0xef,
2215 0x6c,0x43,0x91,0x10,0xe4,0x43,0xfd,0x24,0x6c,0x43,0xb0,0x81,0xe6,0x43,0x08,0x96,0x23,0x6b,0x43,0xee,
2216 0x57,0xe9,0x43,0xca,0x0f,0x6a,0x43,0x5f,0x37,0xec,0x43,0x55,0x71,0x6e,0x43,0x9f,0x01,0xed,0x43,0x08,
2217 0xdb,0xfb,0x75,0x43,0x3b,0xef,0xec,0x43,0x09,0x3a,0x7b,0x43,0xb0,0xa5,0xec,0x43,0x1d,0xe5,0x7f,0x43,
2218 0x91,0x40,0xec,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x08,0xa9,0x16,0x7c,0x43,0xb0,0xb1,
2219 0xee,0x43,0x47,0xec,0x77,0x43,0xd9,0xe8,0xee,0x43,0x1e,0x9d,0x73,0x43,0xcf,0x16,0xef,0x43,0x08,0x0e,
2220 0xc9,0x6b,0x43,0xee,0x7b,0xef,0x43,0x7e,0x90,0x6a,0x43,0xfd,0x30,0xee,0x43,0x01,0xfc,0x68,0x43,0x4e,
2221 0x93,0xec,0x43,0x08,0x31,0xf9,0x66,0x43,0x4e,0x87,0xea,0x43,0x31,0x11,0x6b,0x43,0xd4,0xd5,0xe7,0x43,
2222 0xd9,0xc4,0x68,0x43,0xd4,0xc9,0xe5,0x43,0x08,0xe5,0x79,0x67,0x43,0x77,0x9a,0xe4,0x43,0x44,0x9d,0x66,
2223 0x43,0xab,0x86,0xe3,0x43,0x7e,0x78,0x66,0x43,0x0b,0xaa,0xe2,0x43,0x07,0x7e,0x78,0x66,0x43,0x57,0x29,
2224 0xe2,0x43,0x08,0xa7,0xaf,0x66,0x43,0xbe,0x1e,0xe1,0x43,0x87,0x56,0x68,0x43,0x77,0x82,0xe0,0x43,0xfd,
2225 0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,0x09,0x06,0xc4,0x41,0xbf,0x43,0x85,0xc0,0x72,0x42,0x08,0x73,0xdf,
2226 0xc0,0x43,0xf4,0x76,0x72,0x42,0x97,0x33,0xc2,0x43,0x85,0xc0,0x72,0x42,0xb2,0xb5,0xc3,0x43,0x64,0x56,
2227 0x75,0x42,0x08,0x03,0x24,0xc4,0x43,0x5e,0x7f,0x78,0x42,0xfa,0x51,0xc4,0x43,0x01,0x85,0x7c,0x42,0x5c,
2228 0x64,0xc4,0x43,0xa0,0xb3,0x80,0x42,0x07,0x5c,0x64,0xc4,0x43,0x10,0x93,0x83,0x42,0x08,0xc8,0x48,0xc4,
2229 0x43,0x1c,0x78,0x8a,0x42,0x27,0x6c,0xc3,0x43,0xaf,0xcf,0x94,0x42,0x23,0x7d,0xc2,0x43,0x99,0x9c,0xa4,
2230 0x42,0x08,0x3d,0xe7,0xbf,0x43,0xfb,0xfd,0xb5,0x42,0xb3,0x9d,0xbf,0x43,0x88,0x17,0xae,0x42,0xc4,0x41,
2231 0xbf,0x43,0x69,0x76,0xa3,0x42,0x07,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x08,0x4f,0x8b,0xbf,0x43,
2232 0xed,0x81,0x91,0x42,0xe4,0xa6,0xbf,0x43,0x5d,0x61,0x94,0x42,0xfa,0x39,0xc0,0x43,0x3b,0x49,0x9d,0x42,
2233 0x08,0x2b,0x43,0xc0,0x43,0x28,0xed,0xa9,0x42,0x61,0x3b,0xc1,0x43,0x00,0x9e,0xa5,0x42,0xe4,0xb2,0xc1,
2234 0x43,0x5d,0x91,0x9c,0x42,0x08,0x78,0xce,0xc1,0x43,0xfd,0x36,0x90,0x42,0x22,0x89,0xc4,0x43,0x81,0x72,
2235 0x86,0x42,0xae,0xc6,0xc2,0x43,0xa0,0xb3,0x80,0x42,0x08,0x54,0x86,0xc2,0x43,0x58,0xd1,0x7e,0x42,0x30,
2236 0x32,0xc1,0x43,0xce,0x5e,0x7b,0x42,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x07,0xc4,0x41,0xbf,0x43,
2237 0x85,0xc0,0x72,0x42,0x09,0x06,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x08,0x35,0xfd,0xbb,0x43,0xa4,
2238 0xa1,0x5c,0x42,0x5e,0x34,0xbc,0x43,0x9d,0x2a,0x70,0x42,0x5e,0x40,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,
2239 0x4c,0x9c,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,0xef,0xbe,0x43,0x0e,0x0a,0x73,0x42,0xc4,0x41,0xbf,0x43,
2240 0x85,0xc0,0x72,0x42,0x07,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x08,0xcd,0x13,0xbf,0x43,0xe8,0xf1,
2241 0x7b,0x42,0xd6,0xe5,0xbe,0x43,0x71,0x3b,0x7c,0x42,0xdf,0xb7,0xbe,0x43,0x71,0x3b,0x7c,0x42,0x08,0x08,
2242 0xe3,0xbc,0x43,0xa4,0x61,0x7d,0x42,0x28,0x3c,0xbb,0x43,0x91,0x45,0x69,0x42,0x28,0x3c,0xbb,0x43,0x58,
2243 0x71,0x6e,0x42,0x08,0xce,0xfb,0xba,0x43,0xd5,0x35,0x78,0x42,0x59,0x45,0xbb,0x43,0x58,0x23,0x82,0x42,
2244 0xa1,0xe1,0xbb,0x43,0xd7,0xbe,0x88,0x42,0x08,0xc9,0x18,0xbc,0x43,0xaf,0x9f,0x8c,0x42,0x1e,0x76,0xbd,
2245 0x43,0x51,0x7c,0x8d,0x42,0xd6,0xe5,0xbe,0x43,0xf4,0x58,0x8e,0x42,0x08,0x9c,0x0a,0xbf,0x43,0x45,0xc7,
2246 0x8e,0x42,0x30,0x26,0xbf,0x43,0x96,0x35,0x8f,0x42,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x07,0xc4,
2247 0x41,0xbf,0x43,0x69,0x76,0xa3,0x42,0x08,0x08,0xef,0xbe,0x43,0xb1,0xd6,0x99,0x42,0xe8,0x89,0xbe,0x43,
2248 0xde,0xc5,0x8d,0x42,0xc0,0x46,0xbc,0x43,0xc2,0x5b,0x90,0x42,0x08,0x9c,0xf2,0xba,0x43,0x86,0x80,0x90,
2249 0x42,0xf2,0x43,0xba,0x43,0xe8,0x73,0x87,0x42,0x8f,0x31,0xba,0x43,0xb6,0xf4,0x7d,0x42,0x07,0x8f,0x31,
2250 0xba,0x43,0x21,0xc6,0x76,0x42,0x08,0xc0,0x3a,0xba,0x43,0x5f,0x48,0x6b,0x42,0xae,0x96,0xba,0x43,0xe3,
2251 0x83,0x61,0x42,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x09,0x06,0xea,0x74,0xea,0x43,0x61,0x44,0x93,
2252 0x43,0x08,0x24,0x5c,0xec,0x43,0x31,0x3b,0x93,0x43,0xfb,0x30,0xee,0x43,0x93,0x4d,0x93,0x43,0x0d,0xe1,
2253 0xef,0x43,0x80,0xa9,0x93,0x43,0x08,0x8f,0x58,0xf0,0x43,0xd1,0x17,0x94,0x43,0xb7,0x8f,0xf0,0x43,0x10,
2254 0xe2,0x94,0x43,0xea,0x98,0xf0,0x43,0xa9,0xec,0x95,0x43,0x07,0xea,0x98,0xf0,0x43,0x38,0x25,0x97,0x43,
2255 0x08,0x23,0x74,0xf0,0x43,0x9f,0x32,0x9a,0x43,0x5a,0x60,0xef,0x43,0x53,0xcb,0x9e,0x43,0x2d,0x3a,0xee,
2256 0x43,0xfd,0x91,0xa3,0x43,0x08,0xa2,0xf0,0xed,0x43,0xdd,0x38,0xa5,0x43,0x17,0xa7,0xed,0x43,0xbe,0xdf,
2257 0xa6,0x43,0x5a,0x54,0xed,0x43,0x9f,0x86,0xa8,0x43,0x08,0xfc,0x24,0xec,0x43,0xca,0xc4,0xad,0x43,0x48,
2258 0xa4,0xeb,0x43,0x40,0x6f,0xab,0x43,0x28,0x3f,0xeb,0x43,0x1c,0x0f,0xa8,0x43,0x08,0x1f,0x6d,0xeb,0x43,
2259 0x72,0x48,0xa3,0x43,0x67,0x09,0xec,0x43,0xd1,0x53,0x9e,0x43,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,0x43,
2260 0x07,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x08,0x7e,0x90,0xea,0x43,0x8a,0x9f,0x99,0x43,0x12,0xac,
2261 0xea,0x43,0xbc,0xa8,0x99,0x43,0xa7,0xc7,0xea,0x43,0xbc,0xa8,0x99,0x43,0x08,0x51,0x76,0xeb,0x43,0x9f,
2262 0x32,0x9a,0x43,0x5e,0x37,0xec,0x43,0x49,0xed,0x9c,0x43,0xb0,0xa5,0xec,0x43,0x2a,0xa0,0xa0,0x43,0x08,
2263 0x09,0xe6,0xec,0x43,0xd1,0x77,0xa4,0x43,0x28,0x4b,0xed,0x43,0x61,0xa4,0xa3,0x43,0xab,0xc2,0xed,0x43,
2264 0x8e,0xb2,0xa0,0x43,0x08,0x70,0xe7,0xed,0x43,0xde,0x08,0x9d,0x43,0x87,0x86,0xf0,0x43,0x2f,0x53,0x97,
2265 0x43,0x87,0x7a,0xee,0x43,0xec,0x99,0x95,0x43,0x08,0xca,0x27,0xee,0x43,0xff,0x3d,0x95,0x43,0x74,0xca,
2266 0xec,0x43,0x55,0x8f,0x94,0x43,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x07,0xea,0x74,0xea,0x43,0x61,
2267 0x44,0x93,0x43,0x09,0x06,0x05,0xd3,0xe5,0x43,0x19,0x9c,0x90,0x43,0x08,0x09,0xc2,0xe6,0x43,0xd1,0xff,
2268 0x8f,0x43,0x4d,0x6f,0xe6,0x43,0x74,0xe8,0x92,0x43,0x3b,0xd7,0xe8,0x43,0xc3,0x56,0x93,0x43,0x08,0x1f,
2269 0x61,0xe9,0x43,0x93,0x4d,0x93,0x43,0x05,0xeb,0xe9,0x43,0x93,0x4d,0x93,0x43,0xea,0x74,0xea,0x43,0x61,
2270 0x44,0x93,0x43,0x07,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x08,0x24,0x50,0xea,0x43,0xe7,0xaa,0x94,
2271 0x43,0x2d,0x22,0xea,0x43,0xe7,0xaa,0x94,0x43,0x36,0xf4,0xe9,0x43,0xe7,0xaa,0x94,0x43,0x08,0xa2,0xcc,
2272 0xe7,0x43,0xe0,0xd8,0x94,0x43,0xd4,0xc9,0xe5,0x43,0x19,0xa8,0x92,0x43,0xd4,0xc9,0xe5,0x43,0x27,0x69,
2273 0x93,0x43,0x08,0x17,0x77,0xe5,0x43,0xe0,0xd8,0x94,0x43,0x67,0xe5,0xe5,0x43,0x47,0xda,0x95,0x43,0x43,
2274 0x9d,0xe6,0x43,0xe2,0xd3,0x97,0x43,0x08,0x9d,0xdd,0xe6,0x43,0xad,0xe7,0x98,0x43,0x09,0xce,0xe8,0x43,
2275 0xff,0x55,0x99,0x43,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x07,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,
2276 0x43,0x08,0x71,0xcf,0xe9,0x43,0x53,0xb3,0x9a,0x43,0xa7,0xbb,0xe8,0x43,0xdb,0x0d,0x9a,0x43,0xc6,0x14,
2277 0xe7,0x43,0xdb,0x0d,0x9a,0x43,0x08,0x48,0x80,0xe5,0x43,0xdb,0x0d,0x9a,0x43,0x0a,0xb6,0xe4,0x43,0xc3,
2278 0x6e,0x97,0x43,0x76,0x9a,0xe4,0x43,0x74,0xf4,0x94,0x43,0x07,0x76,0x9a,0xe4,0x43,0x79,0xd7,0x93,0x43,
2279 0x08,0xd8,0xac,0xe4,0x43,0x66,0x27,0x92,0x43,0x29,0x1b,0xe5,0x43,0xe0,0xc0,0x90,0x43,0x05,0xd3,0xe5,
2280 0x43,0x19,0x9c,0x90,0x43,0x09,0x06,0x1b,0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x08,0x71,0x0b,0xf4,0x42,
2281 0x00,0x0e,0x8d,0x42,0x8c,0x0f,0x01,0x43,0x3e,0xc0,0x89,0x42,0xf3,0x28,0x06,0x43,0x48,0x9e,0x8b,0x42,
2282 0x08,0x15,0x89,0x09,0x43,0x00,0x0e,0x8d,0x42,0xe0,0x9c,0x0a,0x43,0xc1,0x8b,0x98,0x42,0xa6,0xc1,0x0a,
2283 0x43,0x02,0xa5,0xaa,0x42,0x07,0xa6,0xc1,0x0a,0x43,0xf9,0xf6,0xb0,0x42,0x08,0xa6,0xc1,0x0a,0x43,0x47,
2284 0x8e,0xb4,0x42,0x42,0xaf,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0xe0,0x9c,0x0a,0x43,0xba,0x74,0xbc,0x42,0x08,
2285 0xa1,0xd2,0x09,0x43,0x40,0x47,0xd0,0x42,0x0d,0xab,0x07,0x43,0x91,0xb5,0xd0,0x42,0x3b,0xb9,0x04,0x43,
2286 0xec,0x71,0xba,0x42,0x08,0xe5,0x5b,0x03,0x43,0xe3,0x33,0xa8,0x42,0x63,0xd8,0x00,0x43,0xce,0x70,0x9f,
2287 0x42,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x07,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,0x42,0x08,0xed,
2288 0x6f,0xed,0x42,0x73,0x24,0x9d,0x42,0xd8,0x0c,0xf5,0x42,0x99,0x6c,0x9c,0x42,0x27,0xab,0xfd,0x42,0xea,
2289 0xda,0x9c,0x42,0x08,0x36,0xca,0x03,0x43,0x2b,0x94,0x9e,0x42,0x68,0xc7,0x01,0x43,0x8f,0xbe,0xa2,0x42,
2290 0xfa,0x06,0x08,0x43,0x73,0xb4,0xb5,0x42,0x08,0x8e,0x2e,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0x9d,0xe3,0x08,
2291 0x43,0xd7,0x1e,0x99,0x42,0x28,0x15,0x05,0x43,0x32,0x3b,0x93,0x42,0x08,0x63,0xf0,0x04,0x43,0x70,0xed,
2292 0x8f,0x42,0x71,0x0b,0xf4,0x42,0x32,0x3b,0x93,0x42,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x07,0x1b,
2293 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x09,0x06,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,0x08,0x8e,0x55,
2294 0xc0,0x42,0xb8,0x4d,0x86,0x42,0x60,0xbf,0xd7,0x42,0x3e,0xf0,0x91,0x42,0x63,0xf6,0xe4,0x42,0x70,0xed,
2295 0x8f,0x42,0x08,0x7a,0x89,0xe5,0x42,0xac,0xc8,0x8f,0x42,0xcc,0xf7,0xe5,0x42,0xac,0xc8,0x8f,0x42,0x1b,
2296 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x07,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x08,0x63,0xf6,0xe4,
2297 0x42,0x3b,0x19,0x95,0x42,0xe6,0x61,0xe3,0x42,0x00,0x3e,0x95,0x42,0xf4,0x16,0xe2,0x42,0xc4,0x62,0x95,
2298 0x42,0x08,0x6e,0x74,0xd6,0x42,0x15,0xd1,0x95,0x42,0x97,0x63,0xca,0x42,0xaf,0xcf,0x94,0x42,0xfb,0x2d,
2299 0xbe,0x42,0x86,0x80,0x90,0x42,0x08,0x97,0x03,0xba,0x42,0xce,0x10,0x8f,0x42,0x5e,0x28,0xba,0x42,0x3e,
2300 0xf0,0x91,0x42,0xf2,0x4f,0xbc,0x42,0x45,0xf7,0x96,0x42,0x08,0x27,0x54,0xbf,0x42,0x73,0x24,0x9d,0x42,
2301 0xa5,0xe8,0xc0,0x42,0x86,0xe0,0xa0,0x42,0xe4,0xca,0xc5,0x42,0xed,0x11,0xaa,0x42,0x08,0x54,0xaa,0xc8,
2302 0x42,0x86,0x40,0xb1,0x42,0x59,0x81,0xc5,0x42,0xa1,0x11,0xc4,0x42,0x3e,0xe7,0xbf,0x42,0xfb,0x8d,0xce,
2303 0x42,0x08,0xb4,0x6d,0xb7,0x42,0x30,0xc2,0xd9,0x42,0x46,0xf5,0xc9,0x42,0xdf,0x53,0xd9,0x42,0x38,0x40,
2304 0xcb,0x42,0x62,0x8f,0xcf,0x42,0x08,0x7d,0xf9,0xcc,0x42,0xec,0xa1,0xc2,0x42,0x07,0x43,0xcd,0x42,0x6c,
2305 0xdd,0xb8,0x42,0x2b,0x8b,0xcc,0x42,0x92,0xf5,0xaf,0x42,0x08,0xf9,0x8d,0xce,0x42,0x41,0x57,0xa7,0x42,
2306 0x5b,0xb8,0xd2,0x42,0xae,0x2f,0xa5,0x42,0x18,0x2f,0xd9,0x42,0x13,0x2a,0xa1,0x42,0x08,0x41,0x7e,0xdd,
2307 0x42,0xe3,0x03,0xa0,0x42,0x2e,0xf2,0xe1,0x42,0x7c,0x02,0x9f,0x42,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,
2308 0x42,0x07,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x08,0x4d,0x63,0xe4,0x42,0x00,0x9e,0xa5,0x42,0xf4,
2309 0x16,0xe2,0x42,0x15,0x31,0xa6,0x42,0x99,0xca,0xdf,0x42,0x2b,0xc4,0xa6,0x42,0x08,0xc0,0x82,0xc6,0x42,
2310 0xc4,0xc2,0xa5,0x42,0x57,0xe1,0xd5,0x42,0x91,0xb5,0xd0,0x42,0x54,0xda,0xd0,0x42,0x97,0x93,0xd2,0x42,
2311 0x08,0x9c,0x3a,0xc7,0x42,0x17,0x58,0xdc,0x42,0x9c,0x0a,0xbf,0x42,0x6e,0xa4,0xde,0x42,0x90,0x25,0xb8,
2312 0x42,0xdf,0x53,0xd9,0x42,0x08,0x59,0x21,0xb5,0x42,0xf2,0xdf,0xd4,0x42,0x51,0x43,0xb3,0x42,0x91,0xb5,
2313 0xd0,0x42,0xc5,0x29,0xbb,0x42,0x0e,0x1a,0xca,0x42,0x08,0x65,0x36,0xc4,0x42,0xd0,0x07,0xbd,0x42,0x3e,
2314 0xe7,0xbf,0x42,0x37,0x09,0xbe,0x42,0x0c,0xea,0xc1,0x42,0xcd,0xd0,0xaf,0x42,0x08,0x2b,0x5b,0xc4,0x42,
2315 0x18,0x08,0xa3,0x42,0x67,0xa6,0xab,0x42,0x99,0x3c,0x94,0x42,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,
2320 //----------------------------------------------------------------------------
2321 // Anti-Grain Geometry (AGG) - Version 2.5
2322 // A high quality rendering engine for C++
2323 // Copyright (C) 2002-2006 Maxim Shemanarev
2324 // Contact: mcseem@antigrain.com
2325 // mcseemagg@yahoo.com
2326 // http://antigrain.com
2328 // AGG is free software; you can redistribute it and/or
2329 // modify it under the terms of the GNU General Public License
2330 // as published by the Free Software Foundation; either version 2
2331 // of the License, or (at your option) any later version.
2333 // AGG is distributed in the hope that it will be useful,
2334 // but WITHOUT ANY WARRANTY; without even the implied warranty of
2335 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2336 // GNU General Public License for more details.
2338 // You should have received a copy of the GNU General Public License
2339 // along with AGG; if not, write to the Free Software
2340 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
2341 // MA 02110-1301, USA.
2342 //----------------------------------------------------------------------------
2343 private nothrow @trusted @nogc:
2346 enum PathCommand
: ubyte {
2354 enum PathFlag
: ubyte {
2363 bool isVertex (in uint c
) pure { pragma(inline
, true); return (c
>= PathCommand
.MoveTo
&& c
< PathCommand
.EndPoly
); }
2364 bool isDrawing (in uint c
) pure { pragma(inline
, true); return (c
>= PathCommand
.LineTo
&& c
< PathCommand
.EndPoly
); }
2365 bool isStop (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.Stop
); }
2366 bool isMoveTo (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.MoveTo
); }
2367 bool isLineTo (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.LineTo
); }
2368 bool isEndPoly (in uint c
) pure { pragma(inline
, true); return ((c
&PathCommand
.Mask
) == PathCommand
.EndPoly
); }
2369 bool isClose (in uint c
) pure { pragma(inline
, true); return (c
&~cast(uint)(PathFlag
.CW|PathFlag
.CCW
)) == (PathCommand
.EndPoly|PathFlag
.Close
); }
2370 bool isCW (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.CW
) != 0); }
2371 bool isCCW (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.CCW
) != 0); }
2372 bool isOriented (in uint c
) pure { pragma(inline
, true); return ((c
&(PathFlag
.CW|PathFlag
.CCW
)) != 0); }
2373 bool isClosed (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.Close
) != 0); }
2374 uint getCloseFlag (in uint c
) pure { pragma(inline
, true); return (c
&PathFlag
.Close
); }
2375 uint clearOrientation (in uint c
) pure { pragma(inline
, true); return (c
&~cast(uint)(PathFlag
.CW|PathFlag
.CCW
)); }
2376 uint getOrientation (in uint c
) pure { pragma(inline
, true); return (c
&(PathFlag
.CW|PathFlag
.CCW
)); }
2377 uint setOrientation (in uint c
, uint o
) pure { pragma(inline
, true); return (clearOrientation(c
)|o
); }
2379 //enum PI = 3.14159265358979323846;
2380 //enum DBL_PI = cast(double)(0x1.921fb54442d18p+1);
2381 enum FLT_PI
= cast(float)(0x1.921fb54442d18p
+1);
2383 enum DEG2RAD_MULT_D
= cast(double)(0x1.1df46a
2529d39p
-6);
2384 enum RAD2DEG_MULT_D
= cast(double)(0x1.ca5dc1a63c1f8p
+5);
2386 enum DEG2RAD_MULT_F
= cast(float)(0x1.1df46ap
-6f);
2387 enum RAD2DEG_MULT_F
= cast(float)(0x1.ca5dc2p
+5f);
2389 //float deg2rad (in float deg) pure nothrow @safe @nogc { pragma(inline, true); return deg*cast(float)(PI/180.0f); }
2390 //float rad2deg (in float rad) pure nothrow @safe @nogc { pragma(inline, true); return rad*cast(float)(180.0f/PI); }
2391 public T
deg2rad(T
) (in T deg
) if (__traits(isFloating
, T
) && (T
.sizeof
== 4 || T
.sizeof
== 8)) {
2392 pragma(inline
, true);
2393 static if (T
.sizeof
== 4) {
2394 return deg
*DEG2RAD_MULT_F
;
2396 return deg
*DEG2RAD_MULT_D
;
2400 public T
rad2deg(T
) (in T rad
) if (__traits(isFloating
, T
) && (T
.sizeof
== 4 || T
.sizeof
== 8)) {
2401 pragma(inline
, true);
2402 static if (T
.sizeof
== 4) {
2403 return rad
*RAD2DEG_MULT_F
;
2405 return rad
*RAD2DEG_MULT_D
;
2410 float calcPolygonArea(Storage
) (in ref Storage st
) {
2416 foreach (immutable uint i
; 1..st
.length
) {
2422 return (sum
+x
*ys
-y
*xs
)*0.5f;
2426 void shortenPath(VertexSequence
) (ref VertexSequence vs
, float s
, in uint closed
=0) {
2427 alias VertexType
= VertexSequence
.ValueType
;
2428 if (s
> 0 && vs
.length
> 1) {
2430 int n
= cast(int)(vs
.length
-2);
2432 immutable float d
= vs
[n
].dist
;
2438 if (vs
.length
< 2) {
2442 VertexType
* prev
= &vs
[n
-1];
2443 VertexType
* last
= &vs
[n
];
2444 immutable float d
= (prev
.dist
-s
)/prev
.dist
;
2445 immutable float x
= prev
.x
+(last
.x
-prev
.x
)*d
;
2446 immutable float y
= prev
.y
+(last
.y
-prev
.y
)*d
;
2449 if (!(*prev
)(*last
)) vs
.removeLast();
2450 vs
.close(closed
!= 0);
2456 // ////////////////////////////////////////////////////////////////////////// //
2457 // Vertex (x, y) with the distance to the next one. The last vertex has
2458 // distance between the last and the first points if the polygon is closed
2459 // and 0.0 if it's a polyline.
2461 public nothrow @trusted @nogc:
2466 this (in float ax
, in float ay
) pure { x
= ax
; y
= ay
; /*dist = 0.0f;*/ }
2468 bool opCall() (in auto ref VertexDist val
) {
2469 //enum VertexDistEPS = cast(double)1e-14; // Coinciding points maximal distance (Epsilon)
2470 enum VertexDistEPS
= cast(float)0.00001f; // Coinciding points maximal distance (Epsilon)
2471 immutable bool ret = (dist
= distance(x
, y
, val
.x
, val
.y
)) > VertexDistEPS
;
2472 if (!ret) dist
= 1.0f/VertexDistEPS
;
2478 // ////////////////////////////////////////////////////////////////////////// //
2479 struct SimpleVector(T
) {
2480 public nothrow @trusted @nogc:
2481 alias ValueType
= T
;
2483 uint pvecAllot
, pvecSize
;
2485 mixin(DisableCopyingMixin
);
2488 import core
.stdc
.stdlib
: free
;
2489 if (pvec
!is null) free(pvec
);
2491 pvecAllot
= pvecSize
= 0;
2494 @property uint length () const pure { pragma(inline
, true); return pvecSize
; }
2496 ref inout(T
) opIndex (in uint idx
) inout pure { pragma(inline
, true);return pvec
[idx
]; }
2498 ref inout(T
) curr (in uint idx
) inout pure { pragma(inline
, true);return pvec
[idx
]; }
2499 ref inout(T
) prev (in uint idx
) inout pure { pragma(inline
, true);return pvec
[(idx
+pvecSize
-1)%pvecSize
]; }
2500 ref inout(T
) next (in uint idx
) inout pure { pragma(inline
, true);return pvec
[(idx
+1)%pvecSize
]; }
2503 pragma(inline
, true);
2507 void removeLast () {
2508 pragma(inline
, true);
2509 if (pvecSize
> 0 ) --pvecSize
;
2512 void add() (in auto ref T val
) {
2513 import core
.stdc
.stdlib
: realloc
;
2514 import core
.stdc
.string
: memcpy
;
2515 if (pvecSize
+1 > pvecAllot
) {
2516 uint newsz
= (pvecAllot|
0xff)+1;
2517 pvec
= cast(T
*)realloc(pvec
, T
.sizeof
*newsz
);
2518 if (pvec
is null) assert(0, "out of memory");
2521 assert(pvecSize
< pvecAllot
);
2522 memcpy(pvec
+pvecSize
, &val
, T
.sizeof
);
2528 // ////////////////////////////////////////////////////////////////////////// //
2529 struct VertexSequence(T
) {
2530 public nothrow @trusted @nogc:
2533 alias ValueType
= T
;
2535 mixin(DisableCopyingMixin
);
2537 void add() (in auto ref T val
) {
2538 import core
.stdc
.stdlib
: realloc
;
2539 import core
.stdc
.string
: memcpy
;
2541 if (!pvec
[pvecSize
-2](pvec
[pvecSize
-1])) removeLast();
2546 void modifyLast() (in auto ref T val
) {
2547 if (pvecSize
> 0) removeLast();
2551 // closed aka remove_flag
2552 void close (in bool closed
) {
2553 while (pvecSize
> 1) {
2554 if (pvec
[pvecSize
-2](pvec
[pvecSize
-1])) break;
2555 T t
= pvec
[pvecSize
-1];
2560 while (pvecSize
> 1) {
2561 if (pvec
[pvecSize
-1](pvec
[0])) break;
2569 // ////////////////////////////////////////////////////////////////////////// //
2570 // process vertex source [src] with generator [dest]
2571 void feedWith(VSD
, VSS
) (ref VSD dest
, ref VSS src
) {
2576 immutable cmd
= src
.vertex(&x
, &y
);
2577 dest
.addVertex(x
, y
, cmd
);
2578 if (isStop(cmd
)) break;
2583 // ////////////////////////////////////////////////////////////////////////// //
2584 // this connects vertex source to vertex generator
2586 float x
= 0.0f, y
= 0.0f;
2588 @property bool lineto () const pure nothrow @safe @nogc { pragma(inline
, true); return !moveto
; }
2592 struct PathPointRange
{
2594 SimpleVector
!PathPoint pts
;
2597 public nothrow @trusted @nogc:
2598 mixin(DisableCopyingMixin
);
2600 this(VG
) (ref VG vg
) {
2607 auto cmd
= vs
.vertex(&x
, &y
);
2608 if (isStop(cmd
)) break;
2609 if (isMoveTo(cmd
)) {
2615 if (isLineTo(cmd
)) {
2617 import std.math : isNaN;
2621 if (first
) { pts
.add(PathPoint(sx
, sy
, true)); }
2622 pts
.add(PathPoint(x
, y
, false));
2625 if (isEndPoly(cmd
)) {
2626 if (isClose(cmd
) && !first
) {
2627 //writeln("s=(", sx, ",", sy, "); c=(", x, ",", y, ")");
2628 pts
.add(PathPoint(sx
, sy
, false));
2635 void rewind () { pragma(inline
, true); idx
= 0; }
2637 @property bool empty () const pure { pragma(inline
, true); return (idx
>= pts
.length
); }
2638 @property ref inout(PathPoint
) front () inout pure { pragma(inline
, true); return pts
[idx
]; }
2639 @property int length () const pure { pragma(inline
, true); return pts
.length
-idx
; }
2640 void popFront () { if (idx
< pts
.length
) ++idx
; }
2644 // ////////////////////////////////////////////////////////////////////////// //
2645 bool intersection (in float ax
, in float ay
, in float bx
, in float by
, in float cx
, in float cy
, in float dx
, in float dy
, float* x
, float* y
) /*pure*/ nothrow @trusted @nogc {
2646 //enum IntersectionEPS = cast(double)1.0e-30; // See calc_intersection
2647 enum IntersectionEPS
= cast(float)1.0e-16; // See calc_intersection
2648 //version(aliced) pragma(inline, true);
2649 //import std.math : abs;
2650 import core
.stdc
.math
: fabsf
;
2651 immutable float num
= (ay
-cy
)*(dx
-cx
)-(ax
-cx
)*(dy
-cy
);
2652 immutable float den
= (bx
-ax
)*(dy
-cy
)-(by
-ay
)*(dx
-cx
);
2653 if (fabsf(den
) < IntersectionEPS
) return false;
2654 //if ((den < 0.0f ? (-den < IntersectionEPS) : (den < IntersectionEPS))) return false;
2655 immutable float r
= num
/den
;
2656 if (x
!is null) *x
= ax
+r
*(bx
-ax
);
2657 if (y
!is null) *y
= ay
+r
*(by
-ay
);
2661 float cross (in float x1
, in float y1
, in float x2
, in float y2
, in float x
, in float y
) pure nothrow @safe @nogc {
2662 pragma(inline
, true);
2663 return (x
-x2
)*(y2
-y1
)-(y
-y2
)*(x2
-x1
);
2666 float distance (in float x1
, in float y1
, in float x2
, in float y2
) /*pure*/ nothrow @safe @nogc {
2667 pragma(inline
, true);
2668 import core
.stdc
.math
: sqrtf
;
2669 immutable float dx
= x2
-x1
;
2670 immutable float dy
= y2
-y1
;
2671 return sqrtf(dx
*dx
+dy
*dy
);
2674 float distance() (in auto ref VertexDist v0
, in auto ref VertexDist v1
) /*pure*/ nothrow @safe @nogc {
2675 pragma(inline
, true);
2676 import core
.stdc
.math
: sqrtf
;
2677 immutable float dx
= v1
.x
-v0
.x
;
2678 immutable float dy
= v1
.y
-v0
.y
;
2679 return sqrtf(dx
*dx
+dy
*dy
);
2684 * VertexConsumer API:
2685 * alias value_type = VertexType; // shoud support `VertexType(x, y)`
2686 * vc.remove_all(); -- start new polygon
2687 * vc.add(VT); -- add point to the current polygon
2689 struct StrokeCalc(VertexConsumer
) {
2691 float mWidth
= 0.5f;
2692 float mWidthAbs
= 0.5f;
2693 float mWidthEps
= 0.5f/1024.0f;
2695 float mMiterLimit
= 4.0f;
2696 float mInnerMiterLimit
= 1.01f;
2697 float mApproxScale
= 1.0f;
2698 LineCap mLineCap
= LineCap
.Butt
;
2699 LineJoin mLineJoin
= LineJoin
.Miter
;
2700 InnerJoin mInnerJoin
= InnerJoin
.Miter
;
2702 public nothrow @trusted @nogc:
2703 alias CoordType
= VertexConsumer
.ValueType
;
2705 mixin(DisableCopyingMixin
);
2707 @property void lineCap (in LineCap lc
) { pragma(inline
, true); mLineCap
= lc
; }
2708 @property void lineJoin (in LineJoin lj
) { pragma(inline
, true); mLineJoin
= lj
; }
2709 @property void innerJoin (in InnerJoin ij
) { pragma(inline
, true); mInnerJoin
= ij
; }
2711 @property LineCap
lineCap () const pure { pragma(inline
, true); return mLineCap
; }
2712 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mLineJoin
; }
2713 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mInnerJoin
; }
2715 @property float width () const pure { pragma(inline
, true); return mWidth
*2; }
2716 @property void width (in float w
) {
2718 if (mWidth
< 0.0f) {
2719 mWidthAbs
= -mWidth
;
2725 mWidthEps
= mWidth
/1024.0f;
2728 @property void miterLimit (in float ml
) { pragma(inline
, true); mMiterLimit
= ml
; }
2729 @property void miterLimitTheta (in float t
) { pragma(inline
, true); import core
.stdc
.math
: sinf
; mMiterLimit
= 1.0f/sinf(t
*0.5f); }
2730 @property void innerMiterLimit (in float ml
) { pragma(inline
, true); mInnerMiterLimit
= ml
; }
2731 @property void approximationScale (in float as
) { pragma(inline
, true); mApproxScale
= as
; }
2733 @property float miterLimit () const pure { pragma(inline
, true); return mMiterLimit
; }
2734 @property float innerMiterLimit () const pure { pragma(inline
, true); return mInnerMiterLimit
; }
2735 @property float approximationScale () const pure { pragma(inline
, true); return mApproxScale
; }
2737 void calcCap() (ref VertexConsumer vc
, in auto ref VertexDist v0
, in auto ref VertexDist v1
, in float len
) {
2738 import core
.stdc
.math
: acosf
, atan2f
, cosf
, sinf
;
2742 float dx1
= (v1
.y
-v0
.y
)/len
;
2743 float dy1
= (v1
.x
-v0
.x
)/len
;
2750 if (mLineCap
!= LineCap
.Round
) {
2751 if (mLineCap
== LineCap
.Square
) {
2752 dx2
= dy1
*mWidthSign
;
2753 dy2
= dx1
*mWidthSign
;
2755 addVertex(vc
, v0
.x
-dx1
-dx2
, v0
.y
+dy1
-dy2
);
2756 addVertex(vc
, v0
.x
+dx1
-dx2
, v0
.y
-dy1
-dy2
);
2758 float da = acosf(mWidthAbs
/(mWidthAbs
+0.125f/mApproxScale
))*2.0f;
2759 immutable int n
= cast(int)(FLT_PI
/da);
2761 addVertex(vc
, v0
.x
-dx1
, v0
.y
+dy1
);
2762 if (mWidthSign
> 0.0f) {
2763 float a1
= atan2f(dy1
, -dx1
);
2765 foreach (immutable int i
; 0..n
) {
2766 addVertex(vc
, v0
.x
+cosf(a1
)*mWidth
, v0
.y
+sinf(a1
)*mWidth
);
2770 float a1
= atan2f(-dy1
, dx1
);
2772 foreach (immutable int i
; 0..n
) {
2773 addVertex(vc
, v0
.x
+cosf(a1
)*mWidth
, v0
.y
+sinf(a1
)*mWidth
);
2777 addVertex(vc
, v0
.x
+dx1
, v0
.y
-dy1
);
2781 void calcJoin() (ref VertexConsumer vc
, in auto ref VertexDist v0
, in auto ref VertexDist v1
, in auto ref VertexDist v2
, in float len1
, in float len2
) {
2782 import core
.stdc
.math
: sqrtf
;
2784 immutable float dx1
= mWidth
*(v1
.y
-v0
.y
)/len1
;
2785 immutable float dy1
= mWidth
*(v1
.x
-v0
.x
)/len1
;
2786 immutable float dx2
= mWidth
*(v2
.y
-v1
.y
)/len2
;
2787 immutable float dy2
= mWidth
*(v2
.x
-v1
.x
)/len2
;
2791 float cp
= cross(v0
.x
, v0
.y
, v1
.x
, v1
.y
, v2
.x
, v2
.y
);
2792 if (cp
!= 0.0f && (cp
> 0.0f) == (mWidth
> 0.0f)) {
2794 float limit
= (len1
< len2 ? len1
: len2
)/mWidthAbs
;
2795 if (limit
< mInnerMiterLimit
) limit
= mInnerMiterLimit
;
2797 switch (mInnerJoin
) {
2798 default: // inner_bevel
2799 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2800 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2802 case InnerJoin
.Miter
:
2803 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, LineJoin
.MiterRevert
, limit
, 0.0f);
2806 case InnerJoin
.Round
:
2807 cp
= (dx1
-dx2
)*(dx1
-dx2
)+(dy1
-dy2
)*(dy1
-dy2
);
2808 if (cp
< len1
*len1
&& cp
< len2
*len2
) {
2809 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, LineJoin
.MiterRevert
, limit
, 0.0f);
2811 if (mInnerJoin
== InnerJoin
.Jag
) {
2812 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2813 addVertex(vc
, v1
.x
, v1
.y
);
2814 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2816 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2817 addVertex(vc
, v1
.x
, v1
.y
);
2818 calcArc(vc
, v1
.x
, v1
.y
, dx2
, -dy2
, dx1
, -dy1
);
2819 addVertex(vc
, v1
.x
, v1
.y
);
2820 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2828 // Calculate the distance between v1 and
2829 // the central point of the bevel line segment
2830 float dx
= (dx1
+dx2
)*0.5f;
2831 float dy
= (dy1
+dy2
)*0.5f;
2832 immutable float dbevel
= sqrtf(dx
*dx
+dy
*dy
);
2834 if (mLineJoin
== LineJoin
.Round || mLineJoin
== LineJoin
.Bevel
) {
2835 // This is an optimization that reduces the number of points
2836 // in cases of almost collinear segments. If there's no
2837 // visible difference between bevel and miter joins we'd rather
2838 // use miter join because it adds only one point instead of two.
2840 // Here we calculate the middle point between the bevel points
2841 // and then, the distance between v1 and this middle point.
2842 // At outer joins this distance always less than stroke width,
2843 // because it's actually the height of an isosceles triangle of
2844 // v1 and its two bevel points. If the difference between this
2845 // width and this value is small (no visible bevel) we can
2846 // add just one point.
2848 // The constant in the expression makes the result approximately
2849 // the same as in round joins and caps. You can safely comment
2850 // out this entire "if".
2851 if (mApproxScale
*(mWidthAbs
-dbevel
) < mWidthEps
) {
2852 if (intersection(v0
.x
+dx1
, v0
.y
-dy1
, v1
.x
+dx1
, v1
.y
-dy1
, v1
.x
+dx2
, v1
.y
-dy2
, v2
.x
+dx2
, v2
.y
-dy2
, &dx
, &dy
)) {
2853 addVertex(vc
, dx
, dy
);
2855 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2861 switch (mLineJoin
) {
2862 case LineJoin
.Miter
:
2863 case LineJoin
.MiterRevert
:
2864 case LineJoin
.MiterRound
:
2865 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, mLineJoin
, mMiterLimit
, dbevel
);
2867 case LineJoin
.Round
:
2868 calcArc(vc
, v1
.x
, v1
.y
, dx1
, -dy1
, dx2
, -dy2
);
2870 default: // Bevel join
2871 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2872 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2879 void addVertex (ref VertexConsumer vc
, in float x
, in float y
) {
2880 pragma(inline
, true);
2881 vc
.add(CoordType(x
, y
));
2884 void calcArc (ref VertexConsumer vc
, in float x
, in float y
, in float dx1
, in float dy1
, in float dx2
, in float dy2
) {
2885 import core
.stdc
.math
: acosf
, atan2f
, cosf
, sinf
;
2887 float a1
= atan2f(dy1
*mWidthSign
, dx1
*mWidthSign
);
2888 float a2
= atan2f(dy2
*mWidthSign
, dx2
*mWidthSign
);
2890 immutable float da = acosf(mWidthAbs
/(mWidthAbs
+0.125f/mApproxScale
))*2.0f;
2892 addVertex(vc
, x
+dx1
, y
+dy1
);
2893 if (mWidthSign
> 0.0f) {
2894 if (a1
> a2
) a2
+= 2.0f*FLT_PI
;
2895 immutable int n
= cast(int)((a2
-a1
)/da);
2896 immutable float daa = (a2
-a1
)/(n
+1);
2898 foreach (immutable int i
; 0..n
) {
2899 addVertex(vc
, x
+cosf(a1
)*mWidth
, y
+sinf(a1
)*mWidth
);
2903 if (a1
< a2
) a2
-= 2.0f*FLT_PI
;
2904 immutable int n
= cast(int)((a1
-a2
)/da);
2905 immutable float daa = (a1
-a2
)/(n
+1);
2907 foreach (immutable int i
; 0..n
) {
2908 addVertex(vc
, x
+cosf(a1
)*mWidth
, y
+sinf(a1
)*mWidth
);
2912 addVertex(vc
, x
+dx2
, y
+dy2
);
2915 void calcMiter (ref VertexConsumer vc
, in ref VertexDist v0
, in ref VertexDist v1
, in ref VertexDist v2
,
2916 in float dx1
, in float dy1
, in float dx2
, in float dy2
, in LineJoin lj
,
2917 in float mlimit
, in float dbevel
)
2922 immutable float lim
= mWidthAbs
*mlimit
;
2923 bool miterLimitExceeded
= true; // assume the worst
2924 bool intersectionFailed
= true; // assume the worst
2926 if (intersection(v0
.x
+dx1
, v0
.y
-dy1
, v1
.x
+dx1
, v1
.y
-dy1
, v1
.x
+dx2
, v1
.y
-dy2
, v2
.x
+dx2
, v2
.y
-dy2
, &xi
, &yi
)) {
2927 // Calculation of the intersection succeeded
2928 di = distance(v1
.x
, v1
.y
, xi
, yi
);
2930 // Inside the miter limit
2931 addVertex(vc
, xi
, yi
);
2932 miterLimitExceeded
= false;
2934 intersectionFailed
= false;
2936 // Calculation of the intersection failed, most probably
2937 // the three points lie one straight line.
2938 // First check if v0 and v2 lie on the opposite sides of vector:
2939 // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
2940 // to the line determined by vertices v0 and v1.
2941 // This condition determines whether the next line segments continues
2942 // the previous one or goes back.
2943 immutable float x2
= v1
.x
+dx1
;
2944 immutable float y2
= v1
.y
-dy1
;
2945 if ((cross(v0
.x
, v0
.y
, v1
.x
, v1
.y
, x2
, y2
) < 0) == (cross(v1
.x
, v1
.y
, v2
.x
, v2
.y
, x2
, y2
) < 0)) {
2946 // This case means that the next segment continues
2947 // the previous one (straight line)
2948 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2949 miterLimitExceeded
= false;
2953 if (miterLimitExceeded
) {
2954 // Miter limit exceeded
2955 //------------------------
2957 case LineJoin
.MiterRevert
:
2958 // For the compatibility with SVG, PDF, etc,
2959 // we use a simple bevel join instead of
2961 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2962 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2964 case LineJoin
.MiterRound
:
2965 calcArc(vc
, v1
.x
, v1
.y
, dx1
, -dy1
, dx2
, -dy2
);
2968 // If no miter-revert, calculate new dx1, dy1, dx2, dy2
2969 if (intersectionFailed
) {
2970 immutable float mlimitM
= mlimit
*mWidthSign
;
2971 addVertex(vc
, v1
.x
+dx1
+dy1
*mlimitM
, v1
.y
-dy1
+dx1
*mlimitM
);
2972 addVertex(vc
, v1
.x
+dx2
-dy2
*mlimitM
, v1
.y
-dy2
-dx2
*mlimitM
);
2974 immutable float x1
= v1
.x
+dx1
;
2975 immutable float y1
= v1
.y
-dy1
;
2976 immutable float x2
= v1
.x
+dx2
;
2977 immutable float y2
= v1
.y
-dy2
;
2978 di = (lim
-dbevel
)/(di-dbevel
);
2979 addVertex(vc
, x1
+(xi
-x1
)*di, y1
+(yi
-y1
)*di);
2980 addVertex(vc
, x2
+(xi
-x2
)*di, y2
+(yi
-y2
)*di);
2989 // ////////////////////////////////////////////////////////////////////////// //
2991 public nothrow @trusted @nogc:
2992 alias VertexStorage
= VertexSequence
!VertexDist
;
2993 alias CoordStorage
= SimpleVector
!AGGPoint
;
3011 StrokeCalc
!CoordStorage mStroker
;
3012 VertexStorage mSrcVertices
;
3013 CoordStorage mOutVertices
;
3016 State mStatus
= State
.Initial
;
3018 uint mSrcVertex
= 0;
3019 uint mOutVertex
= 0;
3022 mixin(DisableCopyingMixin
);
3024 @property void lineCap (LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
3025 @property void lineJoin (LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
3026 @property void innerJoin (InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
3028 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
3029 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
3030 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
3032 @property void width (float w
) { pragma(inline
, true); mStroker
.width(w
); }
3033 @property void miterLimit (float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
3034 @property void miterLimitTheta (float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
3035 @property void innerMiterLimit (float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
3036 @property void approximationScale (float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
3038 @property float width () const pure { pragma(inline
, true); return mStroker
.width(); }
3039 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
3040 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
3041 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
3043 @property void shorten (float s
) { pragma(inline
, true); mShorten
= s
; }
3044 @property float shorten () const pure { pragma(inline
, true); return mShorten
; }
3046 // Generator interface
3048 mSrcVertices
.removeAll();
3050 mStatus
= State
.Initial
;
3053 void addVertex (float x
, float y
, uint cmd
) {
3054 mStatus
= State
.Initial
;
3055 if (isMoveTo(cmd
)) {
3056 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3058 if (isVertex(cmd
)) {
3059 mSrcVertices
.add(VertexDist(x
, y
));
3061 mClosed
= getCloseFlag(cmd
);
3066 // Vertex Source Interface
3068 if (mStatus
== State
.Initial
) {
3069 mSrcVertices
.close(mClosed
!= 0);
3070 shortenPath(mSrcVertices
, mShorten
, mClosed
);
3071 if (mSrcVertices
.length
< 3) mClosed
= 0;
3073 mStatus
= State
.Ready
;
3078 uint vertex (float* x
, float* y
) {
3079 uint cmd
= PathCommand
.LineTo
;
3080 while (!isStop(cmd
)) {
3081 final switch (mStatus
) {
3087 if (mSrcVertices
.length
< 2+cast(uint)(mClosed
!= 0)) {
3088 cmd
= PathCommand
.Stop
;
3091 mStatus
= (mClosed ? State
.Outline1
: State
.Cap1
);
3092 cmd
= PathCommand
.MoveTo
;
3098 mStroker
.calcCap(mOutVertices
, mSrcVertices
[0], mSrcVertices
[1], mSrcVertices
[0].dist
);
3100 mPrevStatus
= State
.Outline1
;
3101 mStatus
= State
.OutVertices
;
3106 mStroker
.calcCap(mOutVertices
, mSrcVertices
[mSrcVertices
.length
-1], mSrcVertices
[mSrcVertices
.length
-2], mSrcVertices
[mSrcVertices
.length
-2].dist
);
3107 mPrevStatus
= State
.Outline2
;
3108 mStatus
= State
.OutVertices
;
3112 case State
.Outline1
:
3114 if (mSrcVertex
>= mSrcVertices
.length
) {
3115 mPrevStatus
= State
.CloseFirst
;
3116 mStatus
= State
.End_poly1
;
3120 if (mSrcVertex
>= mSrcVertices
.length
-1) {
3121 mStatus
= State
.Cap2
;
3125 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.next(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
).dist
, mSrcVertices
.curr(mSrcVertex
).dist
);
3127 mPrevStatus
= mStatus
;
3128 mStatus
= State
.OutVertices
;
3132 case State
.CloseFirst
:
3133 mStatus
= State
.Outline2
;
3134 cmd
= PathCommand
.MoveTo
;
3137 case State
.Outline2
:
3138 if (mSrcVertex
<= uint(mClosed
== 0)) {
3139 mStatus
= State
.End_poly2
;
3140 mPrevStatus
= State
.Stop
;
3145 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.next(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
).dist
, mSrcVertices
.prev(mSrcVertex
).dist
);
3147 mPrevStatus
= mStatus
;
3148 mStatus
= State
.OutVertices
;
3152 case State
.OutVertices
:
3153 if (mOutVertex
>= mOutVertices
.length
) {
3154 mStatus
= mPrevStatus
;
3156 const(AGGPoint
)* c
= &mOutVertices
[mOutVertex
++];
3163 case State
.End_poly1
:
3164 mStatus
= mPrevStatus
;
3165 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CCW
;
3167 case State
.End_poly2
:
3168 mStatus
= mPrevStatus
;
3169 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CW
;
3172 cmd
= PathCommand
.Stop
;
3181 // ////////////////////////////////////////////////////////////////////////// //
3183 public nothrow @trusted @nogc:
3184 alias VertexStorage
= VertexSequence
!VertexDist
;
3185 alias CoordStorage
= SimpleVector
!AGGPoint
;
3197 StrokeCalc
!CoordStorage mStroker
;
3199 VertexStorage mSrcVertices
;
3200 CoordStorage mOutVertices
;
3202 uint mSrcVertex
= 0;
3205 uint mOrientation
= 0;
3206 bool mAutoDetect
= false;
3209 mixin(DisableCopyingMixin
);
3211 @property void lineCap (LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
3212 @property void lineJoin (LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
3213 @property void innerJoin (InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
3215 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
3216 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
3217 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
3219 @property void width (float w
) { pragma(inline
, true); mStroker
.width(mWidth
= w
); }
3220 @property void miterLimit (float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
3221 @property void miterLimitTheta (float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
3222 @property void innerMiterLimit (float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
3223 @property void approximationScale (float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
3225 @property float width () const pure { pragma(inline
, true); return mWidth
; }
3226 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
3227 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
3228 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
3230 @property void autoDetectOrientation (bool v
) { pragma(inline
, true); mAutoDetect
= v
; }
3231 @property bool autoDetectOrientation () const pure { pragma(inline
, true); return mAutoDetect
; }
3233 // Generator interface
3235 mSrcVertices
.removeAll();
3238 mStatus
= State
.Initial
;
3241 void addVertex (float x
, float y
, uint cmd
) {
3242 mStatus
= State
.Initial
;
3243 if (isMoveTo(cmd
)) {
3244 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3246 if (isVertex(cmd
)) {
3247 mSrcVertices
.add(VertexDist(x
, y
));
3249 if (isEndPoly(cmd
)) {
3250 mClosed
= getCloseFlag(cmd
);
3251 if (mOrientation
== PathFlag
.None
) {
3252 mOrientation
= getOrientation(cmd
);
3259 // Vertex Source Interface
3261 if (mStatus
== State
.Initial
) {
3262 mSrcVertices
.close(true);
3264 if (!isOriented(mOrientation
)) {
3265 mOrientation
= (calcPolygonArea(mSrcVertices
) > 0 ? PathFlag
.CCW
: PathFlag
.CW
);
3268 if (isOriented(mOrientation
)) {
3269 mStroker
.width(isCCW(mOrientation
) ? mWidth
: -mWidth
);
3272 mStatus
= State
.Ready
;
3276 uint vertex (float* x
, float* y
) {
3277 uint cmd
= PathCommand
.LineTo
;
3278 while (!isStop(cmd
)) {
3279 final switch (mStatus
) {
3285 if (mSrcVertices
.length
< 2+cast(uint)(mClosed
!= 0)) {
3286 cmd
= PathCommand
.Stop
;
3289 mStatus
= State
.Outline
;
3290 cmd
= PathCommand
.MoveTo
;
3296 if (mSrcVertex
>= mSrcVertices
.length
) {
3297 mStatus
= State
.EndPoly
;
3300 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.next(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
).dist
, mSrcVertices
.curr(mSrcVertex
).dist
);
3302 mStatus
= State
.OutVertices
;
3306 case State
.OutVertices
:
3307 if (mOutVertex
>= mOutVertices
.length
) {
3308 mStatus
= State
.Outline
;
3310 const(AGGPoint
)* c
= &mOutVertices
[mOutVertex
++];
3318 if (!mClosed
) return PathCommand
.Stop
;
3319 mStatus
= State
.Stop
;
3320 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CCW
;
3323 return PathCommand
.Stop
;
3331 // ////////////////////////////////////////////////////////////////////////// //
3333 private nothrow @trusted @nogc:
3334 alias VertexStorage
= VertexSequence
!VertexDist
;
3335 enum MaxDashes
= 32;
3345 float[MaxDashes
] mDashes
= 0;
3346 float mTotalDashLen
= 0;
3347 uint mNumDashes
= 0;
3348 float mDashStart
= 0;
3350 float mCurrDashStart
= 0;
3352 float mCurrRest
= 0;
3353 const(VertexDist
)* m_v1
= null;
3354 const(VertexDist
)* m_v2
= null;
3356 VertexStorage mSrcVertices
;
3358 State mStatus
= State
.Initial
;
3359 uint mSrcVertex
= 0;
3362 mixin(DisableCopyingMixin
);
3364 @property void shorten (float s
) { mShorten
= s
; }
3365 @property float shorten () const pure { return mShorten
; }
3367 void removeAllDashes () {
3374 void addDash (float dashLen
, float gapLen
) {
3375 if (mNumDashes
< MaxDashes
) {
3376 mTotalDashLen
+= dashLen
+gapLen
;
3377 mDashes
[mNumDashes
++] = dashLen
;
3378 mDashes
[mNumDashes
++] = gapLen
;
3382 void dashStart (float ds) {
3383 //import std.math : abs;
3384 import core
.stdc
.math
: fabsf
;
3386 calcDashStart(fabsf(ds));
3389 // Vertex Generator Interface
3391 mStatus
= State
.Initial
;
3392 mSrcVertices
.removeAll();
3396 void addVertex (float x
, float y
, uint cmd
) {
3397 mStatus
= State
.Initial
;
3398 if (isMoveTo(cmd
)) {
3399 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3401 if (isVertex(cmd
)) {
3402 mSrcVertices
.add(VertexDist(x
, y
));
3404 mClosed
= getCloseFlag(cmd
);
3409 // Vertex Source Interface
3411 if (mStatus
== State
.Initial
) {
3412 mSrcVertices
.close(mClosed
!= 0);
3413 shortenPath(mSrcVertices
, mShorten
, mClosed
);
3415 mStatus
= State
.Ready
;
3419 uint vertex (float* x
, float* y
) {
3420 uint cmd
= PathCommand
.MoveTo
;
3422 while (!isStop(cmd
)) {
3423 final switch (mStatus
) {
3429 if (mNumDashes
< 2 || mSrcVertices
.length
< 2) {
3430 cmd
= PathCommand
.Stop
;
3433 mStatus
= State
.Polyline
;
3435 m_v1
= &mSrcVertices
[0];
3436 m_v2
= &mSrcVertices
[1];
3437 mCurrRest
= m_v1
.dist
;
3440 if (mDashStart
>= 0) calcDashStart(mDashStart
);
3441 return PathCommand
.MoveTo
;
3443 case State
.Polyline
:
3444 immutable float dashRest
= mDashes
[mCurrDash
]-mCurrDashStart
;
3445 cmd
= (mCurrDash
&1 ? PathCommand
.MoveTo
: PathCommand
.LineTo
);
3446 if (mCurrRest
> dashRest
) {
3447 mCurrRest
-= dashRest
;
3449 if (mCurrDash
>= mNumDashes
) mCurrDash
= 0;
3451 *x
= m_v2
.x
-(m_v2
.x
-m_v1
.x
)*mCurrRest
/m_v1
.dist
;
3452 *y
= m_v2
.y
-(m_v2
.y
-m_v1
.y
)*mCurrRest
/m_v1
.dist
;
3454 mCurrDashStart
+= mCurrRest
;
3459 mCurrRest
= m_v1
.dist
;
3461 if (mSrcVertex
> mSrcVertices
.length
) {
3462 mStatus
= State
.Stop
;
3464 m_v2
= &mSrcVertices
[mSrcVertex
>= mSrcVertices
.length ?
0 :mSrcVertex
];
3467 if (mSrcVertex
>= mSrcVertices
.length
) {
3468 mStatus
= State
.Stop
;
3470 m_v2
= &mSrcVertices
[mSrcVertex
];
3477 cmd
= PathCommand
.Stop
;
3481 return PathCommand
.Stop
;
3485 void calcDashStart (float ds) {
3489 if (ds > mDashes
[mCurrDash
]) {
3490 ds -= mDashes
[mCurrDash
];
3493 if (mCurrDash
>= mNumDashes
) mCurrDash
= 0;
3495 mCurrDashStart
= ds;
3503 // ////////////////////////////////////////////////////////////////////////// //
3504 // Matrices and Transformations
3507 public align(1) struct AGGMatrix
{
3510 static immutable float[6] IdentityMat
= [
3517 /// Matrix values. Initial value is identity matrix.
3524 public nothrow @trusted @nogc:
3525 /// Create Matrix with the given values.
3526 this (const(float)[] amat
...) {
3527 pragma(inline
, true);
3528 if (amat
.length
>= 6) {
3529 mat
.ptr
[0..6] = amat
.ptr
[0..6];
3531 mat
.ptr
[0..6] = 0.0f;
3532 mat
.ptr
[0..amat
.length
] = amat
[];
3536 /// Can be used to check validity of [inverted] result
3537 @property bool valid () const { import core
.stdc
.math
: isfinite
; return (isfinite(mat
.ptr
[0]) != 0); }
3539 /// Returns `true` if this matrix is identity matrix.
3540 @property bool isIdentity () const { version(aliced
) pragma(inline
, true); return (mat
[] == IdentityMat
[]); }
3542 /// Returns new inverse matrix.
3543 /// If inverted matrix cannot be calculated, `res.valid` fill be `false`.
3544 AGGMatrix
inverted () const {
3545 AGGMatrix res
= this;
3550 /// Inverts this matrix.
3551 /// If inverted matrix cannot be calculated, `this.valid` fill be `false`.
3552 ref AGGMatrix
invert () {
3553 float[6] inv
= void;
3554 immutable double det
= cast(double)mat
.ptr
[0]*mat
.ptr
[3]-cast(double)mat
.ptr
[2]*mat
.ptr
[1];
3555 if (det
> -1e-6 && det
< 1e-6) {
3558 immutable double invdet
= 1.0/det
;
3559 inv
.ptr
[0] = cast(float)(mat
.ptr
[3]*invdet
);
3560 inv
.ptr
[2] = cast(float)(-mat
.ptr
[2]*invdet
);
3561 inv
.ptr
[4] = cast(float)((cast(double)mat
.ptr
[2]*mat
.ptr
[5]-cast(double)mat
.ptr
[3]*mat
.ptr
[4])*invdet
);
3562 inv
.ptr
[1] = cast(float)(-mat
.ptr
[1]*invdet
);
3563 inv
.ptr
[3] = cast(float)(mat
.ptr
[0]*invdet
);
3564 inv
.ptr
[5] = cast(float)((cast(double)mat
.ptr
[1]*mat
.ptr
[4]-cast(double)mat
.ptr
[0]*mat
.ptr
[5])*invdet
);
3566 mat
.ptr
[0..6] = inv
.ptr
[0..6];
3570 /// Sets this matrix to identity matrix.
3571 ref AGGMatrix
identity () { version(aliced
) pragma(inline
, true); mat
[] = IdentityMat
[]; return this; }
3573 /// Translate this matrix.
3574 ref AGGMatrix
translate (in float tx
, in float ty
) {
3575 version(aliced
) pragma(inline
, true);
3576 return this.mul(Translated(tx
, ty
));
3579 /// Scale this matrix.
3580 ref AGGMatrix
scale (in float sx
, in float sy
) {
3581 version(aliced
) pragma(inline
, true);
3582 return this.mul(Scaled(sx
, sy
));
3585 /// Rotate this matrix.
3586 ref AGGMatrix
rotate (in float a
) {
3587 version(aliced
) pragma(inline
, true);
3588 return this.mul(Rotated(a
));
3591 /// Skew this matrix by X axis.
3592 ref AGGMatrix
skewX (in float a
) {
3593 version(aliced
) pragma(inline
, true);
3594 return this.mul(SkewedX(a
));
3597 /// Skew this matrix by Y axis.
3598 ref AGGMatrix
skewY (in float a
) {
3599 version(aliced
) pragma(inline
, true);
3600 return this.mul(SkewedY(a
));
3603 /// Skew this matrix by both axes.
3604 ref AGGMatrix
skewY (in float ax
, in float ay
) {
3605 version(aliced
) pragma(inline
, true);
3606 return this.mul(SkewedXY(ax
, ay
));
3609 /// Transform point with this matrix. `null` destinations are allowed.
3610 /// [sx] and [sy] is the source point. [dx] and [dy] may point to the same variables.
3611 void point (float* dx
, float* dy
, float sx
, float sy
) {
3612 version(aliced
) pragma(inline
, true);
3613 if (dx
!is null) *dx
= sx
*mat
.ptr
[0]+sy
*mat
.ptr
[2]+mat
.ptr
[4];
3614 if (dy
!is null) *dy
= sx
*mat
.ptr
[1]+sy
*mat
.ptr
[3]+mat
.ptr
[5];
3617 /// Transform point with this matrix.
3618 void point (ref float x
, ref float y
) {
3619 version(aliced
) pragma(inline
, true);
3620 immutable float nx
= x
*mat
.ptr
[0]+y
*mat
.ptr
[2]+mat
.ptr
[4];
3621 immutable float ny
= x
*mat
.ptr
[1]+y
*mat
.ptr
[3]+mat
.ptr
[5];
3626 /// Sets this matrix to the result of multiplication of `this` and [s] (this * S).
3627 ref AGGMatrix
mul() (in auto ref AGGMatrix s
) {
3628 immutable float t0
= mat
.ptr
[0]*s
.mat
.ptr
[0]+mat
.ptr
[1]*s
.mat
.ptr
[2];
3629 immutable float t2
= mat
.ptr
[2]*s
.mat
.ptr
[0]+mat
.ptr
[3]*s
.mat
.ptr
[2];
3630 immutable float t4
= mat
.ptr
[4]*s
.mat
.ptr
[0]+mat
.ptr
[5]*s
.mat
.ptr
[2]+s
.mat
.ptr
[4];
3631 mat
.ptr
[1] = mat
.ptr
[0]*s
.mat
.ptr
[1]+mat
.ptr
[1]*s
.mat
.ptr
[3];
3632 mat
.ptr
[3] = mat
.ptr
[2]*s
.mat
.ptr
[1]+mat
.ptr
[3]*s
.mat
.ptr
[3];
3633 mat
.ptr
[5] = mat
.ptr
[4]*s
.mat
.ptr
[1]+mat
.ptr
[5]*s
.mat
.ptr
[3]+s
.mat
.ptr
[5];
3640 /// Sets this matrix to the result of multiplication of [s] and `this` (S * this).
3641 /// Sets the transform to the result of multiplication of two transforms, of A = B*A.
3643 ref AGGMatrix
premul() (in auto ref AGGMatrix s
) {
3650 /// Multiply this matrix by [s], return result as new matrix.
3651 /// Performs operations in this left-to-right order.
3652 AGGMatrix
opBinary(string op
="*") (in auto ref AGGMatrix s
) const {
3653 version(aliced
) pragma(inline
, true);
3654 AGGMatrix res
= this;
3659 /// Multiply this matrix by [s].
3660 /// Performs operations in this left-to-right order.
3661 ref AGGMatrix
opOpAssign(string op
="*") (in auto ref AGGMatrix s
) {
3662 version(aliced
) pragma(inline
, true);
3666 float scaleX () const { pragma(inline
, true); import core
.stdc
.math
: sqrtf
; return sqrtf(mat
.ptr
[0]*mat
.ptr
[0]+mat
.ptr
[2]*mat
.ptr
[2]); } /// Returns x scaling of this matrix.
3667 float scaleY () const { pragma(inline
, true); import core
.stdc
.math
: sqrtf
; return sqrtf(mat
.ptr
[1]*mat
.ptr
[1]+mat
.ptr
[3]*mat
.ptr
[3]); } /// Returns y scaling of this matrix.
3668 float rotation () const { pragma(inline
, true); import core
.stdc
.math
: atan2f
; return atan2f(mat
.ptr
[1], mat
.ptr
[0]); } /// Returns rotation of this matrix.
3669 float tx () const { pragma(inline
, true); return mat
.ptr
[4]; } /// Returns x translation of this matrix.
3670 float ty () const { pragma(inline
, true); return mat
.ptr
[5]; } /// Returns y translation of this matrix.
3672 ref AGGMatrix
scaleX (in float v
) { pragma(inline
, true); return scaleRotateTransform(v
, scaleY
, rotation
, tx
, ty
); } /// Sets x scaling of this matrix.
3673 ref AGGMatrix
scaleY (in float v
) { pragma(inline
, true); return scaleRotateTransform(scaleX
, v
, rotation
, tx
, ty
); } /// Sets y scaling of this matrix.
3674 ref AGGMatrix
rotation (in float v
) { pragma(inline
, true); return scaleRotateTransform(scaleX
, scaleY
, v
, tx
, ty
); } /// Sets rotation of this matrix.
3675 ref AGGMatrix
tx (in float v
) { pragma(inline
, true); mat
.ptr
[4] = v
; return this; } /// Sets x translation of this matrix.
3676 ref AGGMatrix
ty (in float v
) { pragma(inline
, true); mat
.ptr
[5] = v
; return this; } /// Sets y translation of this matrix.
3678 /// Utility function to be used in `setXXX()`.
3679 /// This is the same as doing: `mat.identity.rotate(a).scale(xs, ys).translate(tx, ty)`, only faster
3680 ref AGGMatrix
scaleRotateTransform (in float xscale
, in float yscale
, in float a
, in float tx
, in float ty
) {
3681 import core
.stdc
.math
: sinf
, cosf
;
3682 immutable float cs
= cosf(a
), sn
= sinf(a
);
3683 mat
.ptr
[0] = xscale
*cs
; mat
.ptr
[1] = yscale
*sn
;
3684 mat
.ptr
[2] = xscale
*-sn
; mat
.ptr
[3] = yscale
*cs
;
3685 mat
.ptr
[4] = tx
; mat
.ptr
[5] = ty
;
3689 /// This is the same as doing: `mat.identity.rotate(a).translate(tx, ty)`, only faster
3690 ref AGGMatrix
rotateTransform (in float a
, in float tx
, in float ty
) {
3691 import core
.stdc
.math
: sinf
, cosf
;
3692 immutable float cs
= cosf(a
), sn
= sinf(a
);
3693 mat
.ptr
[0] = cs
; mat
.ptr
[1] = sn
;
3694 mat
.ptr
[2] = -sn
; mat
.ptr
[3] = cs
;
3695 mat
.ptr
[4] = tx
; mat
.ptr
[5] = ty
;
3699 /// Returns new identity matrix.
3700 static AGGMatrix
Identity () { pragma(inline
, true); return AGGMatrix
.init
; }
3702 /// Returns new translation matrix.
3703 static AGGMatrix
Translated (in float tx
, in float ty
) {
3704 version(aliced
) pragma(inline
, true);
3705 AGGMatrix res
= void;
3706 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = 0.0f;
3707 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = 1.0f;
3708 res
.mat
.ptr
[4] = tx
; res
.mat
.ptr
[5] = ty
;
3712 /// Returns new scaling matrix.
3713 static AGGMatrix
Scaled (in float sx
, in float sy
) {
3714 version(aliced
) pragma(inline
, true);
3715 AGGMatrix res
= void;
3716 res
.mat
.ptr
[0] = sx
; res
.mat
.ptr
[1] = 0.0f;
3717 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = sy
;
3718 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3722 /// Returns new rotation matrix. Angle is specified in radians.
3723 static AGGMatrix
Rotated (in float a
) {
3724 version(aliced
) pragma(inline
, true);
3725 import core
.stdc
.math
: sinf
, cosf
;
3726 immutable float cs
= cosf(a
), sn
= sinf(a
);
3727 AGGMatrix res
= void;
3728 res
.mat
.ptr
[0] = cs
; res
.mat
.ptr
[1] = sn
;
3729 res
.mat
.ptr
[2] = -sn
; res
.mat
.ptr
[3] = cs
;
3730 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3734 /// Returns new x-skewing matrix. Angle is specified in radians.
3735 static AGGMatrix
SkewedX (in float a
) {
3736 version(aliced
) pragma(inline
, true);
3737 import core
.stdc
.math
: tanf
;
3738 AGGMatrix res
= void;
3739 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = 0.0f;
3740 res
.mat
.ptr
[2] = tanf(a
); res
.mat
.ptr
[3] = 1.0f;
3741 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3745 /// Returns new y-skewing matrix. Angle is specified in radians.
3746 static AGGMatrix
SkewedY (in float a
) {
3747 version(aliced
) pragma(inline
, true);
3748 import core
.stdc
.math
: tanf
;
3749 AGGMatrix res
= void;
3750 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = tanf(a
);
3751 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = 1.0f;
3752 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3756 /// Returns new xy-skewing matrix. Angles are specified in radians.
3757 static AGGMatrix
SkewedXY (in float ax
, in float ay
) {
3758 version(aliced
) pragma(inline
, true);
3759 import core
.stdc
.math
: tanf
;
3760 AGGMatrix res
= void;
3761 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = tanf(ay
);
3762 res
.mat
.ptr
[2] = tanf(ax
); res
.mat
.ptr
[3] = 1.0f;
3763 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3767 /// Utility function to be used in `setXXX()`.
3768 /// This is the same as doing: `AGGMatrix.Identity.rotate(a).scale(xs, ys).translate(tx, ty)`, only faster
3769 static AGGMatrix
ScaledRotatedTransformed (in float xscale
, in float yscale
, in float a
, in float tx
, in float ty
) {
3770 AGGMatrix res
= void;
3771 res
.scaleRotateTransform(xscale
, yscale
, a
, tx
, ty
);
3775 /// This is the same as doing: `AGGMatrix.Identity.rotate(a).translate(tx, ty)`, only faster
3776 static AGGMatrix
RotatedTransformed (in float a
, in float tx
, in float ty
) {
3777 AGGMatrix res
= void;
3778 res
.rotateTransform(a
, tx
, ty
);
3783 // premultiplies current coordinate system by specified matrix
3784 ref AGGMatrix
transform() (in auto ref AGGMatrix mt
) { pragma(inline
, true); this *= mt
; return this; }
3786 // translates current coordinate system
3787 ref AGGMatrix
translatePre (in float x
, in float y
) { pragma(inline
, true); return premul(AGGMatrix
.Translated(x
, y
)); }
3789 // rotates current coordinate system; angle is specified in radians
3790 ref AGGMatrix
rotatePre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.Rotated(angle
)); }
3792 // skews the current coordinate system along X axis; angle is specified in radians
3793 ref AGGMatrix
skewXPre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.SkewedX(angle
)); }
3795 // skews the current coordinate system along Y axis; angle is specified in radians
3796 ref AGGMatrix
skewYPre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.SkewedY(angle
)); }
3798 // scales the current coordinate system
3799 ref AGGMatrix
scalePre (in float x
, in float y
) { pragma(inline
, true); return premul(AGGMatrix
.Scaled(x
, y
)); }