2 * Simple Framebuffer Gfx/GUI lib
4 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
5 * Understanding is not required. Only obedience.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 /* *****************************************************************************
20 Anti-Grain Geometry - Version 2.1 Lite
21 Copyright (C) 2002-2003 Maxim Shemanarev (McSeem)
22 D port, additional work: Ketmar Dark
24 Permission to copy, use, modify, sell and distribute this software
25 is granted provided this copyright notice appears in all copies.
26 This software is provided "as is" without express or implied
27 warranty, and with no claim as to its suitability for any purpose.
29 The author gratefully acknowleges the support of David Turner,
30 Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
31 libray - in producing this work. See http://www.freetype.org for details.
33 Initially the rendering algorithm was designed by David Turner and the
34 other authors of the FreeType library - see the above notice. I nearly
35 created a similar renderer, but still I was far from David's work.
36 I completely redesigned the original code and adapted it for Anti-Grain
37 ideas. Two functions - renderLine and renderScanLine are the core of
38 the algorithm - they calculate the exact coverage of each pixel cell
39 of the polygon. I left these functions almost as is, because there's
40 no way to improve the perfection - hats off to David and his group!
42 All other code is very different from the original.
43 ***************************************************************************** */
44 module iv
.egra
.gfx
.aggmini
;
48 private enum DisableCopyingMixin
= "@disable this (this); void opAssign() (in auto ref typeof(this)) { static assert(0, `assigning disabled`); }";
50 import iv
.egra
.gfx
.base
;
51 import iv
.egra
.gfx
.lowlevel
;
53 /* Bezier curve rasterizer.
55 * De Casteljau Bezier rasterizer is faster, but currently rasterizing curves with cusps sligtly wrong.
56 * It doesn't really matter in practice.
58 * AFD tesselator is somewhat slower, but does cusps better.
60 * McSeem rasterizer should have the best quality, bit it is the slowest method. Basically, you will
61 * never notice any visial difference (and this code is not really debugged), so you probably should
62 * not use it. It is there for further experiments.
64 public enum AGGTesselation
{
65 DeCasteljau
, /// default: standard well-known tesselation algorithm
66 AFD
, /// adaptive forward differencing
67 DeCasteljauMcSeem
, /// standard well-known tesselation algorithm, with improvements from Maxim Shemanarev; slowest one, but should give best results
71 // ////////////////////////////////////////////////////////////////////////// //
73 align(1) struct Cell
{
76 static uint packCoord (in int x
, in int y
) pure nothrow @safe @nogc { pragma(inline
, true); return (y
<<16)|
(x
&0xffff); }
83 public nothrow @trusted @nogc:
84 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
; }
86 @property int x () const pure { pragma(inline
, true); return cast(short)(packedCoord
&0xffff); }
87 @property int y () const pure { pragma(inline
, true); return cast(short)(packedCoord
>>16); }
89 void setCover (in int c
, in int a
) { pragma(inline
, true); cover
= c
; area
= a
; }
90 void addCover (in int c
, in int a
) { pragma(inline
, true); cover
+= c
; area
+= a
; }
92 void setCoord (in int cx
, in int cy
) { pragma(inline
, true); packedCoord
= packCoord(cx
, cy
); }
94 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
; }
98 // ////////////////////////////////////////////////////////////////////////// //
99 /* An internal class that implements the main rasterization algorithm.
100 Used in the rasterizer. Should not be used direcly.
103 private nothrow @trusted @nogc:
105 CellBlockShift
= 12U,
106 CellBlockSize
= cast(uint)(1<<CellBlockShift
),
107 CellBlockMask
= cast(uint)(CellBlockSize
-1),
108 CellBlockPool
= 256U,
109 CellBlockLimit
= 1024U,
112 enum QSortThreshold
= 9;
128 Cell mCurCell
= Cell(0x7fff, 0x7fff, 0, 0);
133 int mMinX
= 0x7fffffff;
134 int mMinY
= 0x7fffffff;
135 int mMaxX
= -0x7fffffff;
136 int mMaxY
= -0x7fffffff;
137 uint mFlags
= SortRequired
;
140 void allocateBlock () {
141 import core
.stdc
.stdlib
: realloc
;
142 if (mCurBlock
>= mNumBlocks
) {
143 import core
.stdc
.string
: memset
;
144 if (mNumBlocks
>= mMaxBlocks
) {
145 Cell
** newCells
= cast(Cell
**)realloc(mCells
, (mMaxBlocks
+CellBlockPool
)*(Cell
*).sizeof
);
146 if (newCells
is null) assert(0, "out of memory");
148 mMaxBlocks
+= CellBlockPool
;
150 auto cc
= cast(Cell
*)realloc(null, Cell
.sizeof
*CellBlockSize
);
151 if (cc
is null) assert(0, "out of memory");
152 memset(cc
, 0, Cell
.sizeof
*CellBlockSize
);
153 //foreach (ref c; cc[0..CellBlockSize]) c = Cell.init;
154 mCells
[mNumBlocks
++] = cc
;
156 mCurCellPtr
= mCells
[mCurBlock
++];
160 mixin(DisableCopyingMixin
);
163 import core
.stdc
.stdlib
: free
;
166 Cell
** ptr
= mCells
+mNumBlocks
-1;
167 while (mNumBlocks
--) {
178 mCurCell
.set(0x7fff, 0x7fff, 0, 0);
179 mFlags |
= SortRequired
;
180 mFlags
&= ~NotClosed
;
187 void moveTo (in int x
, in int y
) {
188 if ((mFlags
&SortRequired
) == 0) reset();
189 if (mFlags
&NotClosed
) lineTo(mCloseX
, mCloseY
);
190 setCurCell(x
>>PolyBaseShift
, y
>>PolyBaseShift
);
195 void lineTo (in int x
, in int y
) {
196 if ((mFlags
&SortRequired
) && ((mCurX^x
)|
(mCurY^y
))) {
197 int c
= mCurX
>>PolyBaseShift
;
198 if (c
< mMinX
) mMinX
= c
;
200 if (c
> mMaxX
) mMaxX
= c
;
202 c
= x
>>PolyBaseShift
;
203 if (c
< mMinX
) mMinX
= c
;
205 if (c
> mMaxX
) mMaxX
= c
;
207 renderLine(mCurX
, mCurY
, x
, y
);
214 @property float currX () const pure { pragma(inline
, true); return cast(float)mCurX
/cast(float)PolyBaseSize
; }
215 @property float currY () const pure { pragma(inline
, true); return cast(float)mCurY
/cast(float)PolyBaseSize
; }
217 @property int minX () const pure { pragma(inline
, true); return mMinX
; }
218 @property int minY () const pure { pragma(inline
, true); return mMinY
; }
219 @property int maxX () const pure { pragma(inline
, true); return mMaxX
; }
220 @property int maxY () const pure { pragma(inline
, true); return mMaxY
; }
222 @property uint numCells () const pure { pragma(inline
, true); return mNumCells
; }
224 const(Cell
)** cells () {
225 if (mFlags
&NotClosed
) {
226 lineTo(mCloseX
, mCloseY
);
227 mFlags
&= ~NotClosed
;
229 // perform sort only the first time
230 if (mFlags
&SortRequired
) {
232 if (mNumCells
== 0) return null;
234 mFlags
&= ~SortRequired
;
236 return cast(const(Cell
)**)mSortedCells
;
241 if (mCurCell
.area|mCurCell
.cover
) {
242 if ((mNumCells
&CellBlockMask
) == 0) {
243 if (mNumBlocks
>= CellBlockLimit
) return;
246 *mCurCellPtr
++ = mCurCell
;
251 void setCurCell (in int x
, in int y
) {
252 if (mCurCell
.packedCoord
!= Cell
.packCoord(x
, y
)) {
254 mCurCell
.set(x
, y
, 0, 0);
258 void renderScanLine (in int ey
, in int x1
, int y1
, in int x2
, in int y2
) {
259 immutable int ex2
= x2
>>PolyBaseShift
;
261 // trivial case; happens often
267 int ex1
= x1
>>PolyBaseShift
;
268 immutable int fx1
= x1
&PolyBaseMask
;
269 immutable int fx2
= x2
&PolyBaseMask
;
271 // everything is located in a single cell: that is easy!
273 immutable int delta
= y2
-y1
;
274 mCurCell
.addCover(delta
, (fx1
+fx2
)*delta
);
278 // ok, we'll have to render a run of adjacent cells on the same scanline...
279 int p
= (PolyBaseSize
-fx1
)*(y2
-y1
);
280 int first
= PolyBaseSize
;
294 if (mod
< 0) { --delta
; mod
+= dx
; }
296 mCurCell
.addCover(delta
, (fx1
+first
)*delta
);
303 p
= PolyBaseSize
*(y2
-y1
+delta
);
306 if (rem
< 0) { --lift
; rem
+= dx
; }
311 if (mod
>= 0) { mod
-= dx
; ++delta
; }
312 mCurCell
.addCover(delta
, PolyBaseSize
*delta
);
320 mCurCell
.addCover(delta
, (fx2
+PolyBaseSize
-first
)*delta
);
323 void renderLine (in int x1
, in int y1
, in int x2
, in int y2
) {
324 int ey1
= y1
>>PolyBaseShift
;
325 immutable int ey2
= y2
>>PolyBaseShift
;
327 if (ey1
< mMinY
) mMinY
= ey1
;
328 if (ey1
+1 > mMaxY
) mMaxY
= ey1
+1;
329 if (ey2
< mMinY
) mMinY
= ey2
;
330 if (ey2
+1 > mMaxY
) mMaxY
= ey2
+1;
332 immutable int fy1
= y1
&PolyBaseMask
;
333 immutable int fy2
= y2
&PolyBaseMask
;
335 // everything is on a single scanline
337 renderScanLine(ey1
, x1
, fy1
, x2
, fy2
);
345 //int p, rem, mod, lift, delta, first, incr;
347 // vertical line: we have to calculate start and end cells,
348 // and then the common values of the area and coverage for
349 // all cells of the line. we know exactly there's only one
350 // cell, so, we don't have to call renderScanLine().
353 int ex
= x1
>>PolyBaseShift
;
354 int twoFx
= (x1
-(ex
<<PolyBaseShift
))<<1;
357 int first
= PolyBaseSize
;
358 if (dy
< 0) { first
= 0; incr
= -1; }
360 immutable int xFrom
= x1
;
362 //renderScanLine(ey1, xFrom, fy1, xFrom, first);
363 int delta
= first
-fy1
;
364 mCurCell
.addCover(delta
, twoFx
*delta
);
369 delta
= first
+first
-PolyBaseSize
;
372 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, first);
373 mCurCell
.setCover(delta
, area
);
377 //renderScanLine(ey1, xFrom, PolyBaseSize - first, xFrom, fy2);
378 delta
= fy2
-PolyBaseSize
+first
;
379 mCurCell
.addCover(delta
, twoFx
*delta
);
383 // ok, we have to render several scanlines
384 int p
= (PolyBaseSize
-fy1
)*dx
;
385 int first
= PolyBaseSize
;
397 if (mod
< 0) { --delta
; mod
+= dy
; }
399 int xFrom
= x1
+delta
;
400 renderScanLine(ey1
, x1
, fy1
, xFrom
, first
);
403 setCurCell(xFrom
>>PolyBaseShift
, ey1
);
410 if (rem
< 0) { --lift
; rem
+= dy
; }
416 if (mod
>= 0) { mod
-= dy
; ++delta
; }
418 immutable int xTo
= xFrom
+delta
;
419 renderScanLine(ey1
, xFrom
, PolyBaseSize
-first
, xTo
, first
);
423 setCurCell(xFrom
>>PolyBaseShift
, ey1
);
427 renderScanLine(ey1
, xFrom
, PolyBaseSize
-first
, x2
, fy2
);
431 static void qsortCells (Cell
** start
, uint num
) {
432 static void swapCells (Cell
** a
, Cell
** b
) nothrow @trusted @nogc {
433 pragma(inline
, true);
439 static bool lessThan (Cell
** a
, Cell
** b
) nothrow @trusted @nogc pure { pragma(inline
, true); return ((**a
).packedCoord
< (**b
).packedCoord
); }
441 Cell
**[80] stack
= void;
451 immutable int len
= cast(int)(limit
-base
);
453 if (len
> QSortThreshold
) {
454 // we use base + len/2 as the pivot
455 //auto pivot = base+len/2;
456 auto pivot
= base
+(len
>>1);
457 swapCells(base
, pivot
);
462 // now ensure that *i <= *base <= *j
463 if (lessThan(j
, i
)) swapCells(i
, j
);
464 if (lessThan(base
, i
)) swapCells(base
, i
);
465 if (lessThan(j
, base
)) swapCells(base
, j
);
468 do { ++i
; } while (lessThan(i
, base
));
469 do { --j
; } while (lessThan(base
, j
));
476 // now, push the largest sub-array
477 if (j
-base
> limit
-i
) {
488 // the sub-array is small, perform insertion sort
491 for (; i
< limit
; j
= i
, ++i
) {
492 for (; lessThan(j
+1, j
); --j
) {
494 if (j
== base
) break;
497 if (top
> stack
.ptr
) {
509 if (mNumCells
== 0) return;
511 if (mNumCells
> mSortedSize
) {
512 import core
.stdc
.stdlib
: realloc
;
513 mSortedSize
= mNumCells
;
514 mSortedCells
= cast(Cell
**)realloc(mSortedCells
, (mNumCells
+1)*(Cell
*).sizeof
);
517 Cell
** sortedPtr
= mSortedCells
;
518 Cell
** blockPtr
= mCells
;
521 uint nb
= mNumCells
>>CellBlockShift
;
524 cellPtr
= *blockPtr
++;
525 uint i
= CellBlockSize
;
526 while (i
--) *sortedPtr
++ = cellPtr
++;
529 cellPtr
= *blockPtr
++;
530 uint i
= mNumCells
&CellBlockMask
;
531 while (i
--) *sortedPtr
++ = cellPtr
++;
532 mSortedCells
[mNumCells
] = null;
533 qsortCells(mSortedCells
, mNumCells
);
538 // ////////////////////////////////////////////////////////////////////////// //
539 /*This class is used to transfer data from class outline (or a similar one)
540 to the rendering buffer. It's organized very simple. The class stores
541 information of horizontal spans to render it into a pixel-map buffer.
542 Each span has initial X, length, and an array of bytes that determine the
543 alpha-values for each pixel. So, the restriction of using this class is 256
544 levels of Anti-Aliasing, which is quite enough for any practical purpose.
545 Before using this class you should know the minimal and maximal pixel
546 coordinates of your scanline. The protocol of using is:
548 2. addCell() / addSpan() - accumulate scanline. You pass Y-coordinate
549 into these functions in order to make scanline know the last Y. Before
550 calling addCell() / addSpan() you should check with method isReady(y)
551 if the last Y has changed. It also checks if the scanline is not empty.
552 When forming one scanline the next X coordinate must be always greater
553 than the last stored one, i.e. it works only with ordered coordinates.
554 3. If the current scanline isReady() you should render it and then call
555 resetSpans() before adding new cells/spans.
559 Scanline provides an iterator class that allows you to extract
560 the spans and the cover values for each pixel. Be aware that clipping
561 has not been done yet, so you should perform it yourself.
563 -------------------------------------------------------------------------
564 int baseX = sl.baseX; // base X. Should be added to the span's X
565 // "sl" is a const reference to the
566 // scanline passed in.
568 int y = sl.y; // Y-coordinate of the scanline
570 ************************************
571 ...Perform vertical clipping here...
572 ************************************
574 ubyte* row = mRBuf[y]; // the the address of the beginning of the current row
576 auto span = scanline.iterator;
578 uint spanCount = scanline.spanCount(); // number of spans; it's guaranteed that
579 // spanCount is always greater than 0
582 int x = span.next+baseX; // the beginning X of the span
584 const(ubyte)* covers = span.covers; // the array of the cover values
586 int pixelCount = span.pixelCount; // number of pixels of the span;
587 // always greater than 0, still we
588 // shoud use "int" instead of "uint"
589 // because it's more convenient for clipping
591 **************************************
592 ...Perform horizontal clipping here...
593 ...you have x, covers, and pixCount..
594 **************************************
596 ubyte* dst = row+x; // calculate the start address of the row;
597 // in this case we assume a simple
598 // grayscale image 1-byte per pixel
600 *dst++ = *covers++; // hypotetical rendering
601 } while (--pixelCount);
602 } while (--spanCount); // spanCount cannot be 0, so this loop is quite safe
603 ------------------------------------------------------------------------
605 The question is: why should we accumulate the whole scanline when we
606 could render just separate spans when they're ready?
607 That's because using the scaline is in general faster. When is consists
608 of more than one span the conditions for the processor cash system
609 are better, because switching between two different areas of memory
610 (that can be large ones) occures less frequently.
624 ubyte** mCurStartPtr
;
630 static struct Iterator
{
632 const(ubyte)* mCovers
;
633 const(ushort)* mCurCount
;
634 const(ubyte*)* mCurStartPtr
;
636 public nothrow @trusted @nogc:
637 mixin(DisableCopyingMixin
);
639 this (in ref ScanLine sl
) pure {
640 pragma(inline
, true);
641 mCovers
= sl
.mCovers
;
642 mCurCount
= sl
.mCounts
;
643 mCurStartPtr
= sl
.mStartPtrs
;
647 pragma(inline
, true);
650 return cast(int)(*mCurStartPtr
-mCovers
);
653 @property int pixelCount () const pure { pragma(inline
, true); return cast(int)(*mCurCount
); }
654 @property const(ubyte)* covers () const pure { pragma(inline
, true); return *mCurStartPtr
; }
657 public nothrow @trusted @nogc:
658 mixin(DisableCopyingMixin
);
661 import core
.stdc
.stdlib
: free
;
662 if (mCounts
!is null) free(mCounts
);
663 if (mStartPtrs
!is null) free(mStartPtrs
);
664 if (mCovers
!is null) free(mCovers
);
667 auto iterator () const pure { pragma(inline
, true); return Iterator(this); }
669 void reset (int minX
, int maxX
, int dx
=0, int dy
=0) {
670 uint maxLen
= maxX
-minX
+2;
671 if (maxLen
> mMaxLen
) {
672 import core
.stdc
.stdlib
: realloc
;
673 mCovers
= cast(ubyte*)realloc(mCovers
, maxLen
*mCovers
[0].sizeof
);
674 if (mCovers
is null) assert(0, "out of memory");
675 mStartPtrs
= cast(ubyte**)realloc(mStartPtrs
, mStartPtrs
[0].sizeof
*maxLen
);
676 if (mStartPtrs
is null) assert(0, "out of memory");
677 mCounts
= cast(ushort*)realloc(mCounts
, mCounts
[0].sizeof
*maxLen
);
678 if (mCounts
is null) assert(0, "out of memory");
687 mCurStartPtr
= mStartPtrs
;
692 pragma(inline
, true);
696 mCurStartPtr
= mStartPtrs
;
700 void addSpan (int x
, int y
, uint num
, uint cover
) {
701 import core
.stdc
.string
: memset
;
703 memset(mCovers
+x
, cover
, num
);
705 (*mCurCount
) += cast(ushort)num
;
707 *++mCurCount
= cast(ushort)num
;
708 *++mCurStartPtr
= mCovers
+x
;
715 void addCell (int x
, int y
, uint cover
) {
717 mCovers
[x
] = cast(ubyte)cover
;
722 *++mCurStartPtr
= mCovers
+x
;
729 @property bool isReady (int y
) const pure { pragma(inline
, true); return (mNumSpans
&& (y^mLastY
)); }
730 @property int baseX () const pure { pragma(inline
, true); return mMinX
+mDX
; }
731 @property int y () const pure { pragma(inline
, true); return mLastY
+mDY
; }
732 @property uint spanCount () const pure { pragma(inline
, true); return mNumSpans
; }
736 // ////////////////////////////////////////////////////////////////////////// //
737 /* This class template is used basically for rendering scanlines.
739 auto ras = Rasterizer();
747 ras.render(ren, Color(255, 127, 0));
749 public struct Renderer
{
750 public nothrow @trusted @nogc:
751 mixin(DisableCopyingMixin
);
753 static void render (in ref ScanLine sl
, in GxColor clr
, in ref GxRect clipRect
) {
754 if (clipRect
.size
.h
< 1 || clipRect
.size
.w
< 1 || sl
.y
< clipRect
.pos
.y || sl
.y
>= clipRect
.pos
.y
+clipRect
.size
.h
) return;
755 immutable GxColorU c
= GxColorU(clr
);
756 uint spanCount
= sl
.spanCount
;
757 immutable int baseX
= sl
.baseX
;
758 uint* row
= vglTexBuf
+cast(uint)sl
.y
*cast(uint)VBufWidth
;
759 auto span
= sl
.iterator
;
761 int x
= span
.next
+baseX
;
762 int pixelCount
= span
.pixelCount
;
764 if (clipRect
.clipHStripe(ref x
, sl
.y
, ref pixelCount
, &leftSkip
)) {
765 const(ubyte)* covers
= span
.covers
+leftSkip
;
766 memBlendColorCoverage(row
+x
, covers
, clr
, pixelCount
);
768 } while (--spanCount
);
773 // ////////////////////////////////////////////////////////////////////////// //
774 /* These constants determine the subpixel accuracy, to be more precise,
775 the number of bits of the fractional part of the coordinates.
776 The possible coordinate capacity in bits can be calculated by formula:
777 sizeof(int) * 8 - PolyBaseShift * 2, i.e, for 32-bit integers and
778 8-bits fractional part the capacity is 16 bits or [-32768...32767].
782 PolyBaseSize
= cast(uint)(1<<PolyBaseShift
),
783 PolyBaseMask
= cast(uint)(PolyBaseSize
-1),
787 int polyCoord (in float c
) pure nothrow @safe @nogc { pragma(inline
, true); return (cast(int)(c
*(PolyBaseSize
*2))+1)/2; }
789 int dbl2fix (in float c
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(int)(c
*PolyBaseSize
); }
790 float fix2dbl (in int c
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(float)c
/cast(float)PolyBaseSize
; }
793 // ////////////////////////////////////////////////////////////////////////// //
794 /* Polygon rasterizer that is used to render filled polygons with
795 high-quality Anti-Aliasing. Internally, by default, the class uses
796 integer coordinates in format 24.8, i.e. 24 bits for integer part
797 and 8 bits for fractional - see PolyBaseShift. This class can be
798 used in the following way:
800 1. fillRule = FillRule.EvenOdd; // optional
801 2. gamma() - optional.
803 4. moveTo(x, y) / lineTo(x, y) - make the polygon. One can create
804 more than one contour, but each contour must consist of at least 3
805 vertices, i.e. moveTo(x1, y1); lineTo(x2, y2); lineTo(x3, y3);
806 is the absolute minimum of vertices that define a triangle.
807 The algorithm does not check either the number of vertices nor
808 coincidence of their coordinates, but in the worst case it just
810 The orger of the vertices (clockwise or counterclockwise)
811 is important when using the non-zero filling rule (FillNonZero).
812 In this case the vertex order of all the contours must be the same
813 if you want your intersecting polygons to be without "holes".
814 You actually can use different vertices order. If the contours do not
815 intersect each other the order is not important anyway. If they do,
816 contours with the same vertex order will be rendered without "holes"
817 while the intersecting contours with different orders will have "holes".
819 fillRule() and gamma() can be called anytime before "sweeping".
821 public struct Rasterizer
{
822 public nothrow @trusted @nogc:
824 AAShift
= ScanLine
.AAShift
,
834 FillRule mFillingRule
= FillRule
.NonZero
;
835 ubyte[256] mGamma
= DefaultGamma
[];
838 mixin(DisableCopyingMixin
);
840 void reset () { mOutline
.reset(); }
842 @property FillRule
fillRule () const pure { pragma(inline
, true); return mFillingRule
; }
843 @property void fillRule (FillRule v
) { pragma(inline
, true); mFillingRule
= v
; }
845 void gamma (in float g
) {
846 foreach (immutable uint i
; 0..256) {
847 //import std.math : pow;
848 import core
.stdc
.math
: powf
;
849 mGamma
.ptr
[i
] = cast(ubyte)(powf(cast(float)i
/255.0f, g
)*255.0f);
853 void gamma (const(ubyte)[] g
) {
854 if (g
.length
!= 256) assert(0, "invalid gamma array");
855 mGamma
[] = g
[0..256];
858 @property float currX () const pure { pragma(inline
, true); return mOutline
.currX
; }
859 @property float currY () const pure { pragma(inline
, true); return mOutline
.currY
; }
861 void moveToFixed (int x
, int y
) {
862 if ((x
>>PolyBaseShift
) <= short.min
+8 ||
(x
>>PolyBaseShift
) >= short.max
-8 ||
863 (y
>>PolyBaseShift
) <= short.min
+8 ||
(y
>>PolyBaseShift
) >= short.max
-8) assert(0, "coordinates out of bounds");
864 mOutline
.moveTo(x
, y
);
867 void lineToFixed (int x
, int y
) {
868 if ((x
>>PolyBaseShift
) <= short.min
+8 ||
(x
>>PolyBaseShift
) >= short.max
-8 ||
869 (y
>>PolyBaseShift
) <= short.min
+8 ||
(y
>>PolyBaseShift
) >= short.max
-8) assert(0, "coordinates out of bounds");
870 mOutline
.lineTo(x
, y
);
873 void moveTo (in float x
, in float y
) { mOutline
.moveTo(polyCoord(x
), polyCoord(y
)); }
874 void lineTo (in float x
, in float y
) { mOutline
.lineTo(polyCoord(x
), polyCoord(y
)); }
876 @property int minX () const pure { pragma(inline
, true); return mOutline
.minX
; }
877 @property int minY () const pure { pragma(inline
, true); return mOutline
.minY
; }
878 @property int maxX () const pure { pragma(inline
, true); return mOutline
.maxX
; }
879 @property int maxY () const pure { pragma(inline
, true); return mOutline
.maxY
; }
881 private uint calculateAlpha (int area
) const pure {
882 int cover
= area
>>(PolyBaseShift
*2+1-AAShift
);
883 if (cover
< 0) cover
= -cover
;
884 if (mFillingRule
== FillRule
.EvenOdd
) {
886 if (cover
> AANum
) cover
= AA2Num
-cover
;
888 if (cover
> AAMask
) cover
= AAMask
;
892 void render (in ref GxRect clipRect
, in GxColor c
, int dx
=0, int dy
=0) {
893 const(Cell
)** cells
= mOutline
.cells();
894 if (mOutline
.numCells() == 0) return;
896 mScanline
.reset(mOutline
.minX
, mOutline
.maxX
, dx
, dy
);
899 const(Cell
)* curCell
= *cells
++;
902 const(Cell
)* startCell
= curCell
;
904 int coord
= curCell
.packedCoord
;
908 int area
= startCell
.area
;
909 cover
+= startCell
.cover
;
911 // accumulate all start cells
912 while ((curCell
= *cells
++) !is null) {
913 if (curCell
.packedCoord
!= coord
) break;
914 area
+= curCell
.area
;
915 cover
+= curCell
.cover
;
919 int alpha
= calculateAlpha((cover
<<(PolyBaseShift
+1))-area
);
921 if (mScanline
.isReady(y
)) {
922 Renderer
.render(mScanline
, c
, clipRect
);
923 mScanline
.resetSpans();
925 mScanline
.addCell(x
, y
, mGamma
[alpha
]);
933 int alpha
= calculateAlpha(cover
<<(PolyBaseShift
+1));
935 if (mScanline
.isReady(y
)) {
936 Renderer
.render(mScanline
, c
, clipRect
);
937 mScanline
.resetSpans();
939 mScanline
.addSpan(x
, y
, curCell
.x
-x
, mGamma
[alpha
]);
944 if (mScanline
.spanCount
) Renderer
.render(mScanline
, c
, clipRect
);
947 bool hitTest (int tx
, int ty
) {
948 const(Cell
)** cells
= mOutline
.cells();
949 if (mOutline
.numCells
== 0) return false;
952 const(Cell
)* curCell
= *cells
++;
955 const(Cell
)* startCell
= curCell
;
957 int coord
= curCell
.packedCoord
;
961 if (y
> ty
) return false;
963 int area
= startCell
.area
;
964 cover
+= startCell
.cover
;
966 while ((curCell
= *cells
++) !is null) {
967 if (curCell
.packedCoord
!= coord
) break;
968 area
+= curCell
.area
;
969 cover
+= curCell
.cover
;
973 int alpha
= calculateAlpha((cover
<<(PolyBaseShift
+1))-area
);
975 if (tx
== x
&& ty
== y
) return true;
980 if (curCell
is null) break;
983 int alpha
= calculateAlpha(cover
<<(PolyBaseShift
+1));
985 if (ty
== y
&& tx
>= x
&& tx
<= curCell
.x
) return true;
993 static immutable ubyte[256] DefaultGamma
= [
994 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8,
995 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18,
996 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28,
997 29, 29, 30, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37, 38,
998 39, 39, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49,
999 49, 50, 51, 51, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60,
1000 60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 68, 68, 69, 70, 71, 71,
1001 72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 83, 84,
1002 85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
1003 100,101,101,102,103,104,105,106,107,108,109,110,111,112,114,115,
1004 116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,132,
1005 134,135,136,137,139,140,141,142,144,145,146,147,149,150,151,153,
1006 154,155,157,158,159,161,162,164,165,166,168,169,171,172,174,175,
1007 177,178,180,181,183,184,186,188,189,191,192,194,195,197,199,200,
1008 202,204,205,207,209,210,212,214,215,217,219,220,222,224,225,227,
1009 229,230,232,234,236,237,239,241,242,244,246,248,249,251,253,255
1014 // ////////////////////////////////////////////////////////////////////////// //
1015 public alias AGGPoint
= AGGPointImpl
!float;
1017 public struct AGGPointImpl(T
) if (__traits(isIntegral
, T
) ||
__traits(isFloating
, T
)) {
1018 public nothrow @trusted @nogc:
1020 alias Me
= AGGPointImpl
!T
;
1023 static if (__traits(isFloating
, T
)) {
1031 // ////////////////////////////////////////////////////////////////////////// //
1032 public enum FillRule
{
1037 public enum LineCap
{
1043 public enum LineJoin
{
1051 public enum InnerJoin
{
1059 // ////////////////////////////////////////////////////////////////////////// //
1060 // some "fastgfx" backend
1061 public struct AGGDrawer
{
1063 static struct Vertex
{
1064 float x
, y
; // fixed point
1070 float tessTol
= 0.25f;
1071 float angleTol
= 0.0f; // 0.0f -- angle tolerance for McSeem Bezier rasterizer
1072 float cuspLimit
= 0.0f; // 0 -- cusp limit for McSeem Bezier rasterizer (0: real cusps)
1074 uint vtxcount
, vtxsize
;
1077 // default tesselator for Bezier curves
1078 AGGTesselation tesselator
= AGGTesselation
.DeCasteljau
;
1079 //AGGTesselation tesselator = AGGTesselation.AFD;
1080 //AGGTesselation tesselator = AGGTesselation.DeCasteljauMcSeem;
1082 nothrow @trusted @nogc:
1084 enum distTol
= cast(float)(1.0f/256.0f);
1085 enum KAPPA90
= 0.5522847493f; // length proportional to radius of a cubic bezier handle for 90deg arcs
1087 static bool ptEquals (in float x0
, in float y0
, in float x1
, in float y1
) pure {
1088 enum EPS
= cast(float)(1.0f/256.0f);
1089 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
)); }
1090 return (eq(x0
, x1
) && eq(y0
, y1
));
1093 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 {
1094 immutable float pqx
= qx
-px
;
1095 immutable float pqy
= qy
-py
;
1098 immutable float d
= pqx
*pqx
+pqy
*pqy
;
1099 float t
= pqx
*dx
+pqy
*dy
;
1101 if (t
< 0) t
= 0; else if (t
> 1) t
= 1;
1107 static float cross() (in float dx0
, in float dy0
, in float dx1
, in float dy1
) pure { pragma(inline
, true); return (dx1
*dy0
-dx0
*dy1
); }
1108 static T
min(T
) (in T a
, in T b
) pure { pragma(inline
, true); return (a
< b ? a
: b
); }
1109 static T
max(T
) (in T a
, in T b
) pure { pragma(inline
, true); return (a
> b ? a
: b
); }
1110 static T
sign(T
) (in T a
) pure { pragma(inline
, true); return (a
>= cast(T
)0 ?
cast(T
)1 : cast(T
)(-1)); }
1112 static float normalize (float* x
, float* y
) nothrow @safe @nogc {
1113 import core
.stdc
.math
: sqrtf
;
1114 float d
= sqrtf((*x
)*(*x
)+(*y
)*(*y
));
1116 immutable float id
= 1.0f/d
;
1123 void addVertexIntr (float fx
, float fy
, bool asMove
=false) {
1124 //static bool eq (in float a, in float b) pure nothrow @safe @nogc { import std.math : abs; return (abs(a-b) < EPS); }
1125 // it is important to reject pixels that are too close!
1126 if (vtxcount
> 0 && ptEquals(fx
, fy
, vtx
[vtxcount
-1].x
, vtx
[vtxcount
-1].y
)) {
1127 if (asMove
!= vtx
[vtxcount
-1].asmove
) return;
1129 if (vtxcount
+1 > vtxsize
) {
1130 import core
.stdc
.stdlib
: realloc
;
1131 uint newsz
= (vtxsize|
0xfff)+1;
1132 vtx
= cast(Vertex
*)realloc(vtx
, newsz
*Vertex
.sizeof
);
1133 if (vtx
is null) assert(0, "out of memory");
1136 if (asMove
&& vtxcount
> 0 && vtx
[vtxcount
-1].asmove
) --vtxcount
;
1137 vtx
[vtxcount
++] = Vertex(fx
, fy
, asMove
);
1140 void addVertex (in float fx
, in float fy
, bool asMove
=false) {
1141 pragma(inline
, true);
1142 if (vtxcount
== 0 && !asMove
) addVertexIntr(0, 0, true);
1143 addVertexIntr(fx
, fy
, asMove
);
1150 @property void lineCap (in LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
1151 @property void lineJoin (in LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
1152 @property void innerJoin (in InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
1154 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
1155 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
1156 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
1158 @property void width (in float w
) { pragma(inline
, true); mStroker
.width(w
); }
1159 @property void miterLimit (in float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
1160 @property void miterLimitTheta (in float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
1161 @property void innerMiterLimit (in float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
1162 @property void approximationScale (in float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
1164 @property float width () const pure { pragma(inline
, true); return mStroker
.width(); }
1165 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
1166 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
1167 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
1169 @property void shorten (in float s
) { pragma(inline
, true); mStroker
.shorten
= s
; }
1170 @property float shorten () const pure { pragma(inline
, true); return mStroker
.shorten
; }
1172 @property FillRule
fillRule () const pure { pragma(inline
, true); return rast
.fillRule
; }
1173 @property void fillRule (FillRule v
) { pragma(inline
, true); rast
.fillRule
= v
; }
1175 @property float currX () const pure { pragma(inline
, true); return (vtxcount
> 0 ? vtx
[vtxcount
-1].x
: 0.0f); }
1176 @property float currY () const pure { pragma(inline
, true); return (vtxcount
> 0 ? vtx
[vtxcount
-1].y
: 0.0f); }
1178 // ////////////////////////////////////////////////////////////////////////// //
1179 ref AGGDrawer
beginFrame () {
1181 //addVertex(0, 0, true);
1182 mStroker
.width
= 1.5f;
1187 ref AGGDrawer
cancelFrame () {
1189 //addVertex(0, 0, true);
1194 ref AGGDrawer
endFrame (in GxColor c
) {
1195 GxRect clipRect
= gxClipRect
;
1196 if (clipRect
.intersect(0, 0, VBufWidth
, VBufHeight
)) {
1197 rast
.render(clipRect
, c
);
1199 return beginFrame();
1202 ref AGGDrawer
beginPath () {
1203 pragma(inline
, true);
1208 ref AGGDrawer
closePath () {
1209 if (vtxcount
> 1 && !vtx
[vtxcount
-1].asmove
) {
1211 while (vp
> 0 && !vtx
[vp
-1].asmove
) --vp
;
1212 addVertex(vtx
[vp
].x
, vtx
[vp
].y
); // close it
1213 addVertex(vtx
[vp
].x
, vtx
[vp
].y
, true); // and open new one
1218 // starts new sub-path with specified point as first point
1219 ref AGGDrawer
moveTo (in float x
, in float y
) { pragma(inline
, true); addVertex(x
, y
, true); return this; }
1221 // adds line segment from the last point in the path to the specified point
1222 ref AGGDrawer
lineTo (in float x
, in float y
) { pragma(inline
, true); addVertex(x
, y
); return this; }
1224 // adds cubic bezier segment from last point in the path via two control points to the specified point
1225 ref AGGDrawer
bezierTo (in float x2
, in float y2
, in float x3
, in float y3
, in float x4
, in float y4
) {
1226 pragma(inline
, true);
1227 //tesselateBezierMcSeem(currX, currY, x2, y2, x3, y3, x4, y4, 0);
1228 tesselateBezier(currX
, currY
, x2
, y2
, x3
, y3
, x4
, y4
);
1232 // adds quadratic bezier segment from last point in the path via a control point to the specified point
1233 void quadTo (in float cx
, in float cy
, in float x
, in float y
) {
1234 immutable float x0
= currX
;
1235 immutable float y0
= currY
;
1237 x0
+2.0f/3.0f*(cx
-x0
), y0
+2.0f/3.0f*(cy
-y0
),
1238 x
+2.0f/3.0f*(cx
-x
), y
+2.0f/3.0f*(cy
-y
),
1243 // adds an arc segment at the corner defined by the last path point, and two specified points
1244 ref AGGDrawer
arcTo (in float x1
, in float y1
, in float x2
, in float y2
, in float radius
) {
1245 import core
.stdc
.math
: acosf
, tanf
, atan2f
;
1247 immutable float x0
= currX
;
1248 immutable float y0
= currY
;
1250 // handle degenerate cases
1251 if (ptEquals(x0
, y0
, x1
, y1
) ||
1252 ptEquals(x1
, y1
, x2
, y2
) ||
1253 distPtSeg(x1
, y1
, x0
, y0
, x2
, y2
) < distTol
*distTol ||
1260 // calculate tangential circle to lines (x0, y0)-(x1, y1) and (x1, y1)-(x2, y2)
1265 normalize(&dx0
, &dy0
);
1266 normalize(&dx1
, &dy1
);
1267 immutable float a
= acosf(dx0
*dx1
+dy0
*dy1
);
1268 immutable float d
= radius
/tanf(a
*0.5f);
1275 float cx
= void, cy
= void, a0
= void, a1
= void;
1277 if (cross(dx0
, dy0
, dx1
, dy1
) > 0.0f) {
1278 cx
= x1
+dx0
*d
+dy0
*radius
;
1279 cy
= y1
+dy0
*d
+-dx0
*radius
;
1280 a0
= atan2f(dx0
, -dy0
);
1281 a1
= atan2f(-dx1
, dy1
);
1283 //printf("CW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
1285 cx
= x1
+dx0
*d
+-dy0
*radius
;
1286 cy
= y1
+dy0
*d
+dx0
*radius
;
1287 a0
= atan2f(-dx0
, dy0
);
1288 a1
= atan2f(dx1
, -dy1
);
1290 //printf("CCW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
1293 return arc(dir
, cx
, cy
, radius
, a0
, a1
); // first is line
1297 // ////////////////////////////////////////////////////////////////////////// //
1300 //pragma(inline, true);
1301 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1302 if (vt
.asmove
) rast
.moveTo(vt
.x
, vt
.y
); else rast
.lineTo(vt
.x
, vt
.y
);
1308 //if (mStroker.width <= 1.0) { contour(); return; }
1309 mStroker
.removeAll();
1311 bool waitingLine
= true;
1312 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1313 mStroker
.addVertex(vt
.x
, vt
.y
, (vt
.asmove ? PathCommand
.MoveTo
: PathCommand
.LineTo
));
1315 mStroker
.addVertex(0, 0, PathCommand
.Stop
);
1320 auto cmd
= mStroker
.vertex(&x
, &y
);
1321 if (isStop(cmd
)) break;
1322 if (isMoveTo(cmd
)) { rast
.moveTo(x
, y
); continue; }
1323 if (isLineTo(cmd
)) { rast
.lineTo(x
, y
); continue; }
1324 if (isEndPoly(cmd
)) {
1326 if (is_close(cmd) && !first) {
1327 //writeln("s=(", sx, ",", sy, "); c=(", x, ",", y, ")");
1328 pts.add(PathPoint(sx, sy, false));
1340 ctr
.lineCap
= mStroker
.lineCap
;
1341 ctr
.lineJoin
= mStroker
.lineJoin
;
1342 ctr
.innerJoin
= mStroker
.innerJoin
;
1344 ctr
.width
= mStroker
.width
;
1345 ctr
.miterLimit
= mStroker
.miterLimit
;
1346 ctr
.innerMiterLimit
= mStroker
.innerMiterLimit
;
1347 ctr
.approximationScale
= mStroker
.approximationScale
;
1349 bool waitingLine
= true;
1350 foreach (const ref Vertex vt
; vtx
[0..vtxcount
]) {
1351 ctr
.addVertex(vt
.x
, vt
.y
, (vt
.asmove ? PathCommand
.MoveTo
: PathCommand
.LineTo
));
1353 ctr
.addVertex(0, 0, PathCommand
.Stop
);
1358 auto cmd
= ctr
.vertex(&x
, &y
);
1359 if (isStop(cmd
)) break;
1360 if (isMoveTo(cmd
)) { rast
.moveTo(x
, y
); continue; }
1361 if (isLineTo(cmd
)) { rast
.lineTo(x
, y
); continue; }
1366 // ////////////////////////////////////////////////////////////////////////// //
1367 enum Winding
{ CW
, CCW
}
1369 /* Creates new circle arc shaped sub-path. The arc center is at (cx, cy), the arc radius is r,
1370 * and the arc is drawn from angle a0 to a1, and swept in direction dir (NVGWinding.CCW, or NVGWinding.CW).
1371 * Angles are specified in radians.
1373 * [mode] is: "original", "move", "line" -- first command will be like original NanoVega, MoveTo, or LineTo
1375 ref AGGDrawer
arc(string mode
="original") (Winding dir
, in float cx
, in float cy
, in float r
,
1376 in float a0
, in float a1
)
1378 static assert(mode
== "original" || mode
== "move" || mode
== "line");
1379 import core
.stdc
.math
: fabsf
, cosf
, sinf
;
1381 //int move = (ctx.ncommands > 0 ? Command.LineTo : Command.MoveTo);
1382 static if (mode
== "original") {
1383 bool asMove
= (vtxcount
== 0);
1384 } else static if (mode
== "move") {
1386 } else static if (mode
== "line") {
1387 enum asMove
= false;
1389 static assert(0, "wtf?!");
1394 if (dir
== Winding
.CW
) {
1395 if (fabsf(da) >= FLT_PI
*2.0f) {
1398 while (da < 0.0f) da += FLT_PI
*2.0f;
1401 if (fabsf(da) >= FLT_PI
*2.0f) {
1404 while (da > 0.0f) da -= FLT_PI
*2.0f;
1408 // split arc into max 90 degree segments
1409 immutable int ndivs
= max(1, min(cast(int)(fabsf(da)/(FLT_PI
*0.5f)+0.5f), 5));
1410 immutable float hda
= (da/cast(float)ndivs
)*0.5f;
1411 float kappa
= fabsf(4.0f/3.0f*(1.0f-cosf(hda
))/sinf(hda
));
1412 if (dir
== Winding
.CCW
) kappa
= -kappa
;
1415 float px
= 0, py
= 0, ptanx
= 0, ptany
= 0;
1416 foreach (int i
; 0..ndivs
+1) {
1417 immutable float a
= a0
+da*(i
/cast(float)ndivs
);
1418 immutable float dx
= cosf(a
);
1419 immutable float dy
= sinf(a
);
1420 immutable float x
= cx
+dx
*r
;
1421 immutable float y
= cy
+dy
*r
;
1422 immutable float tanx
= -dy
*r
*kappa
;
1423 immutable float tany
= dx
*r
*kappa
;
1426 addVertex(x
, y
, asMove
);
1428 bezierTo(px
+ptanx
, py
+ptany
, x
-tanx
, y
-tany
, x
, y
);
1439 // creates new rectangle shaped sub-path
1440 ref AGGDrawer
rect (in float x
, in float y
, in float w
, in float h
) {
1446 lineTo(x
, y
); // close it
1451 // creates new rounded rectangle shaped sub-path
1452 ref AGGDrawer
roundedRect (in float x
, in float y
, in float w
, in float h
, in float radius
) {
1453 return roundedRectVarying(x
, y
, w
, h
, radius
, radius
, radius
, radius
);
1456 // creates new rounded rectangle shaped sub-path
1457 // specify ellipse width and height to round corners according to it
1458 ref AGGDrawer
roundedRectEllipse (in float x
, in float y
, in float w
, in float h
, in float rw
, in float rh
) {
1459 if (rw
< 0.1f || rh
< 0.1f) return rect(x
, y
, w
, h
);
1462 bezierTo(x
+w
-rw
*(1.0f-KAPPA90
), y
, x
+w
, y
+rh
*(1.0f-KAPPA90
), x
+w
, y
+rh
);
1463 lineTo(x
+w
, y
+h
-rh
);
1464 bezierTo(x
+w
, y
+h
-rh
*(1.0f-KAPPA90
), x
+w
-rw
*(1.0f-KAPPA90
), y
+h
, x
+w
-rw
, y
+h
);
1466 bezierTo(x
+rw
*(1.0f-KAPPA90
), y
+h
, x
, y
+h
-rh
*(1.0f-KAPPA90
), x
, y
+h
-rh
);
1468 bezierTo(x
, y
+rh
*(1.0f-KAPPA90
), x
+rw
*(1.0f-KAPPA90
), y
, x
+rw
, y
);
1472 // creates new rounded rectangle shaped sub-path
1473 // this one allows you to specify different rounding radii for each corner
1474 ref AGGDrawer
roundedRectVarying (in float x
, in float y
, in float w
, in float h
,
1475 in float radTopLeft
, in float radTopRight
,
1476 in float radBottomRight
, in float radBottomLeft
)
1478 import core
.stdc
.math
: fabsf
;
1479 if (radTopLeft
< 0.1f && radTopRight
< 0.1f && radBottomRight
< 0.1f && radBottomLeft
< 0.1f) return rect(x
, y
, w
, h
);
1480 immutable float halfw
= fabsf(w
)*0.5f;
1481 immutable float halfh
= fabsf(h
)*0.5f;
1482 immutable float rxBL
= min(radBottomLeft
, halfw
)*sign(w
), ryBL
= min(radBottomLeft
, halfh
)*sign(h
);
1483 immutable float rxBR
= min(radBottomRight
, halfw
)*sign(w
), ryBR
= min(radBottomRight
, halfh
)*sign(h
);
1484 immutable float rxTR
= min(radTopRight
, halfw
)*sign(w
), ryTR
= min(radTopRight
, halfh
)*sign(h
);
1485 immutable float rxTL
= min(radTopLeft
, halfw
)*sign(w
), ryTL
= min(radTopLeft
, halfh
)*sign(h
);
1487 lineTo(x
, y
+h
-ryBL
);
1488 bezierTo(x
, y
+h
-ryBL
*(1.0f-KAPPA90
), x
+rxBL
*(1.0f-KAPPA90
), y
+h
, x
+rxBL
, y
+h
);
1489 lineTo(x
+w
-rxBR
, y
+h
);
1490 bezierTo(x
+w
-rxBR
*(1.0f-KAPPA90
), y
+h
, x
+w
, y
+h
-ryBR
*(1.0f-KAPPA90
), x
+w
, y
+h
-ryBR
);
1491 lineTo(x
+w
, y
+ryTR
);
1492 bezierTo(x
+w
, y
+ryTR
*(1.0f-KAPPA90
), x
+w
-rxTR
*(1.0f-KAPPA90
), y
, x
+w
-rxTR
, y
);
1494 bezierTo(x
+rxTL
*(1.0f-KAPPA90
), y
, x
, y
+ryTL
*(1.0f-KAPPA90
), x
, y
+ryTL
);
1498 // creates new ellipse shaped sub-path
1499 ref AGGDrawer
ellipse (in float cx
, in float cy
, in float rx
, in float ry
) {
1501 bezierTo(cx
-rx
, cy
+ry
*KAPPA90
, cx
-rx
*KAPPA90
, cy
+ry
, cx
, cy
+ry
);
1502 bezierTo(cx
+rx
*KAPPA90
, cy
+ry
, cx
+rx
, cy
+ry
*KAPPA90
, cx
+rx
, cy
);
1503 bezierTo(cx
+rx
, cy
-ry
*KAPPA90
, cx
+rx
*KAPPA90
, cy
-ry
, cx
, cy
-ry
);
1504 bezierTo(cx
-rx
*KAPPA90
, cy
-ry
, cx
-rx
, cy
-ry
*KAPPA90
, cx
-rx
, cy
);
1508 // creates new circle shaped sub-path
1509 ref AGGDrawer
circle (in float cx
, in float cy
, in float r
) {
1510 return ellipse(cx
, cy
, r
, r
);
1514 // ////////////////////////////////////////////////////////////////////////// //
1515 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*/) {
1516 import core
.stdc
.math
: fabsf
;
1517 if (level
> 10) return;
1519 // check for collinear points, and use AFD tesselator on such curves (it is WAY faster for this case)
1521 if (level == 0 && ctx.tesselatortype == NVGTesselation.Combined) {
1522 static bool collinear (in float v0x, in float v0y, in float v1x, in float v1y, in float v2x, in float v2y) nothrow @trusted @nogc {
1523 immutable float cz = (v1x-v0x)*(v2y-v0y)-(v2x-v0x)*(v1y-v0y);
1524 return (fabsf(cz*cz) <= 0.01f); // arbitrary number, seems to work ok with NanoSVG output
1526 if (collinear(x1, y1, x2, y2, x3, y3) && collinear(x2, y2, x3, y3, x3, y4)) {
1527 //{ import core.stdc.stdio; printf("AFD fallback!\n"); }
1528 ctx.tesselateBezierAFD(x1, y1, x2, y2, x3, y3, x4, y4, type);
1534 immutable float x12
= (x1
+x2
)*0.5f;
1535 immutable float y12
= (y1
+y2
)*0.5f;
1536 immutable float x23
= (x2
+x3
)*0.5f;
1537 immutable float y23
= (y2
+y3
)*0.5f;
1538 immutable float x34
= (x3
+x4
)*0.5f;
1539 immutable float y34
= (y3
+y4
)*0.5f;
1540 immutable float x123
= (x12
+x23
)*0.5f;
1541 immutable float y123
= (y12
+y23
)*0.5f;
1543 immutable float dx
= x4
-x1
;
1544 immutable float dy
= y4
-y1
;
1545 immutable float d2
= fabsf(((x2
-x4
)*dy
-(y2
-y4
)*dx
));
1546 immutable float d3
= fabsf(((x3
-x4
)*dy
-(y3
-y4
)*dx
));
1548 if ((d2
+d3
)*(d2
+d3
) < tessTol
*(dx
*dx
+dy
*dy
)) {
1549 addVertex(x4
, y4
/*, type*/);
1553 immutable float x234
= (x23
+x34
)*0.5f;
1554 immutable float y234
= (y23
+y34
)*0.5f;
1555 immutable float x1234
= (x123
+x234
)*0.5f;
1556 immutable float y1234
= (y123
+y234
)*0.5f;
1558 // "taxicab" / "manhattan" check for flat curves
1559 if (fabsf(x1
+x3
-x2
-x2
)+fabsf(y1
+y3
-y2
-y2
)+fabsf(x2
+x4
-x3
-x3
)+fabsf(y2
+y4
-y3
-y3
) < tessTol
*0.25f) {
1560 addVertex(x1234
, y1234
/*, type*/);
1564 tesselateBezierDCj(x1
, y1
, x12
, y12
, x123
, y123
, x1234
, y1234
, level
+1/*, 0*/);
1565 tesselateBezierDCj(x1234
, y1234
, x234
, y234
, x34
, y34
, x4
, y4
, level
+1/*, type*/);
1568 // ////////////////////////////////////////////////////////////////////////// //
1569 // based on the ideas and code of Maxim Shemanarev. Rest in Peace, bro!
1570 // see http://www.antigrain.com/research/adaptive_bezier/index.html
1571 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*/) {
1572 //import std.math : atan2, PI;
1573 import core
.stdc
.math
: fabsf
, atan2f
;
1575 enum CollinearEPS
= 0.00000001f; // 0.00001f;
1576 enum AngleTolEPS
= 0.01f;
1578 static float distSquared (in float x1
, in float y1
, in float x2
, in float y2
) pure nothrow @safe @nogc {
1579 pragma(inline
, true);
1580 immutable float dx
= x2
-x1
;
1581 immutable float dy
= y2
-y1
;
1587 addVertex(x1, y1/*, 0*/);
1588 tesselateBezierMcSeem(x1, y1, x2, y2, x3, y3, x4, y4, 1/*, type*/);
1589 addVertex(x4, y4/*, type*/);
1594 if (level
>= 32) return; // recurse limit; practically, it should be never reached, but...
1596 // calculate all the mid-points of the line segments
1597 immutable float x12
= (x1
+x2
)*0.5f;
1598 immutable float y12
= (y1
+y2
)*0.5f;
1599 immutable float x23
= (x2
+x3
)*0.5f;
1600 immutable float y23
= (y2
+y3
)*0.5f;
1601 immutable float x34
= (x3
+x4
)*0.5f;
1602 immutable float y34
= (y3
+y4
)*0.5f;
1603 immutable float x123
= (x12
+x23
)*0.5f;
1604 immutable float y123
= (y12
+y23
)*0.5f;
1605 immutable float x234
= (x23
+x34
)*0.5f;
1606 immutable float y234
= (y23
+y34
)*0.5f;
1607 immutable float x1234
= (x123
+x234
)*0.5f;
1608 immutable float y1234
= (y123
+y234
)*0.5f;
1610 // try to approximate the full cubic curve by a single straight line
1611 immutable float dx
= x4
-x1
;
1612 immutable float dy
= y4
-y1
;
1614 float d2
= fabsf(((x2
-x4
)*dy
-(y2
-y4
)*dx
));
1615 float d3
= fabsf(((x3
-x4
)*dy
-(y3
-y4
)*dx
));
1617 final switch ((cast(int)(d2
> CollinearEPS
)<<1)+cast(int)(d3
> CollinearEPS
)) {
1619 // all collinear or p1 == p4
1620 float k
= dx
*dx
+dy
*dy
;
1622 d2
= distSquared(x1
, y1
, x2
, y2
);
1623 d3
= distSquared(x4
, y4
, x3
, y3
);
1628 d2
= k
*(da1
*dx
+da2
*dy
);
1631 d3
= k
*(da1
*dx
+da2
*dy
);
1632 if (d2
> 0 && d2
< 1 && d3
> 0 && d3
< 1) {
1633 // Simple collinear case, 1---2---3---4
1634 // We can leave just two endpoints
1637 if (d2
<= 0) d2
= distSquared(x2
, y2
, x1
, y1
);
1638 else if (d2
>= 1) d2
= distSquared(x2
, y2
, x4
, y4
);
1639 else d2
= distSquared(x2
, y2
, x1
+d2
*dx
, y1
+d2
*dy
);
1641 if (d3
<= 0) d3
= distSquared(x3
, y3
, x1
, y1
);
1642 else if (d3
>= 1) d3
= distSquared(x3
, y3
, x4
, y4
);
1643 else d3
= distSquared(x3
, y3
, x1
+d3
*dx
, y1
+d3
*dy
);
1647 addVertex(x2
, y2
/*, type*/);
1650 } if (d3
< tessTol
) {
1651 addVertex(x3
, y3
/*, type*/);
1656 // p1,p2,p4 are collinear, p3 is significant
1657 if (d3
*d3
<= tessTol
*(dx
*dx
+dy
*dy
)) {
1658 if (angleTol
< AngleTolEPS
) {
1659 addVertex(x23
, y23
/*, type*/);
1663 float da1
= fabsf(atan2f(y4
-y3
, x4
-x3
)-atan2f(y3
-y2
, x3
-x2
));
1664 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1665 if (da1
< angleTol
) {
1666 addVertex(x2
, y2
/*, type*/);
1667 addVertex(x3
, y3
/*, type*/);
1670 if (cuspLimit
!= 0.0f) {
1671 if (da1
> cuspLimit
) {
1672 addVertex(x3
, y3
/*, type*/);
1680 // p1,p3,p4 are collinear, p2 is significant
1681 if (d2
*d2
<= tessTol
*(dx
*dx
+dy
*dy
)) {
1682 if (angleTol
< AngleTolEPS
) {
1683 addVertex(x23
, y23
/*, type*/);
1687 float da1
= fabsf(atan2f(y3
-y2
, x3
-x2
)-atan2f(y2
-y1
, x2
-x1
));
1688 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1689 if (da1
< angleTol
) {
1690 addVertex(x2
, y2
/*, type*/);
1691 addVertex(x3
, y3
/*, type*/);
1694 if (cuspLimit
!= 0.0f) {
1695 if (da1
> cuspLimit
) {
1696 addVertex(x2
, y2
/*, type*/);
1705 if ((d2
+d3
)*(d2
+d3
) <= tessTol
*(dx
*dx
+dy
*dy
)) {
1706 // if the curvature doesn't exceed the distance tolerance value, we tend to finish subdivisions
1707 if (angleTol
< AngleTolEPS
) {
1708 addVertex(x23
, y23
/*, type*/);
1711 // angle and cusp condition
1712 immutable float k
= atan2f(y3
-y2
, x3
-x2
);
1713 float da1
= fabsf(k
-atan2f(y2
-y1
, x2
-x1
));
1714 float da2
= fabsf(atan2f(y4
-y3
, x4
-x3
)-k
);
1715 if (da1
>= FLT_PI
) da1
= 2.0f*FLT_PI
-da1
;
1716 if (da2
>= FLT_PI
) da2
= 2.0f*FLT_PI
-da2
;
1717 if (da1
+da2
< angleTol
) {
1718 // finally we can stop the recursion
1719 addVertex(x23
, y23
/*, type*/);
1722 if (cuspLimit
!= 0.0f) {
1723 if (da1
> cuspLimit
) {
1724 addVertex(x2
, y2
/*, type*/);
1727 if (da2
> cuspLimit
) {
1728 addVertex(x3
, y3
/*, type*/);
1737 // continue subdivision
1738 tesselateBezierMcSeem(x1
, y1
, x12
, y12
, x123
, y123
, x1234
, y1234
, level
+1/*, 0*/);
1739 tesselateBezierMcSeem(x1234
, y1234
, x234
, y234
, x34
, y34
, x4
, y4
, level
+1/*, type*/);
1742 // Adaptive forward differencing for bezier tesselation.
1743 // See Lien, Sheue-Ling, Michael Shantz, and Vaughan Pratt.
1744 // "Adaptive forward differencing for rendering curves and surfaces."
1745 // ACM SIGGRAPH Computer Graphics. Vol. 21. No. 4. ACM, 1987.
1746 // original code by Taylor Holliday <taylor@audulus.com>
1747 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 {
1748 enum AFD_ONE
= (1<<10);
1751 immutable float ax
= -x1
+3*x2
-3*x3
+x4
;
1752 immutable float ay
= -y1
+3*y2
-3*y3
+y4
;
1753 immutable float bx
= 3*x1
-6*x2
+3*x3
;
1754 immutable float by
= 3*y1
-6*y2
+3*y3
;
1755 immutable float cx
= -3*x1
+3*x2
;
1756 immutable float cy
= -3*y1
+3*y2
;
1758 // Transform to forward difference basis (stepsize 1)
1761 float dx
= ax
+bx
+cx
;
1762 float dy
= ay
+by
+cy
;
1763 float ddx
= 6*ax
+2*bx
;
1764 float ddy
= 6*ay
+2*by
;
1768 //printf("dx: %f, dy: %f\n", dx, dy);
1769 //printf("ddx: %f, ddy: %f\n", ddx, ddy);
1770 //printf("dddx: %f, dddy: %f\n", dddx, dddy);
1775 immutable float tol
= tessTol
*4.0f;
1777 while (t
< AFD_ONE
) {
1778 // Flatness measure.
1779 float d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1781 // printf("d: %f, th: %f\n", d, th);
1783 // Go to higher resolution if we're moving a lot or overshooting the end.
1784 while ((d
> tol
&& dt > 1) ||
(t
+dt > AFD_ONE
)) {
1787 // Apply L to the curve. Increase curve resolution.
1788 dx
= 0.5f*dx
-(1.0f/8.0f)*ddx
+(1.0f/16.0f)*dddx
;
1789 dy
= 0.5f*dy
-(1.0f/8.0f)*ddy
+(1.0f/16.0f)*dddy
;
1790 ddx
= (1.0f/4.0f)*ddx
-(1.0f/8.0f)*dddx
;
1791 ddy
= (1.0f/4.0f)*ddy
-(1.0f/8.0f)*dddy
;
1792 dddx
= (1.0f/8.0f)*dddx
;
1793 dddy
= (1.0f/8.0f)*dddy
;
1795 // Half the stepsize.
1799 d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1802 // Go to lower resolution if we're really flat
1803 // and we aren't going to overshoot the end.
1804 // XXX: tol/32 is just a guess for when we are too flat.
1805 while ((d
> 0 && d
< tol
/32.0f && dt < AFD_ONE
) && (t
+2*dt <= AFD_ONE
)) {
1806 // printf("down\n");
1808 // Apply L^(-1) to the curve. Decrease curve resolution.
1816 // Double the stepsize.
1820 d
= ddx
*ddx
+ddy
*ddy
+dddx
*dddx
+dddy
*dddy
;
1823 // Forward differencing.
1832 addVertex(px
, py
/*, (t > 0 ? type : 0)*/);
1834 // Advance along the curve.
1837 // Ensure we don't overshoot.
1838 assert(t
<= AFD_ONE
);
1843 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
) {
1844 final switch (tesselator
) with (AGGTesselation
) {
1846 tesselateBezierDCj(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
, 0/*, type*/);
1849 tesselateBezierAFD(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
/*, type*/);
1851 case DeCasteljauMcSeem
:
1852 addVertex(x1
, y1
/*, 0*/);
1853 tesselateBezierMcSeem(x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
, 1/*, type*/);
1854 addVertex(x4
, y4
/*, type*/);
1859 // ////////////////////////////////////////////////////////////////////////// //
1860 public enum BaphometDims
= 512; // [0..511]
1861 private enum baph_debug_time
= false;
1862 private enum baph_debug_dump
= false;
1863 public void renderBaphomet (float ofsx
=0.0f, float ofsy
=0.0f, float scalex
=1.0f, float scaley
=1.0f) {
1864 auto path
= cast(const(ubyte)[])baphometPath
;
1865 immutable plen
= path
.length
;
1869 Bounds
, // always first, has 4 args (x0, y0, x1, y1)
1877 CubicTo
, // cubic bezier
1881 Command
getCommand () nothrow @trusted @nogc {
1882 if (ppos
>= plen
) assert(0, "invalid path");
1883 return cast(Command
)(path
.ptr
[ppos
++]);
1886 float getFloat () nothrow @trusted @nogc {
1887 if (ppos
>= plen || plen
-ppos
< float.sizeof
) assert(0, "invalid path");
1888 version(LittleEndian
) {
1889 float res
= *cast(const(float)*)(&path
.ptr
[ppos
]);
1890 ppos
+= cast(uint)float.sizeof
;
1893 static assert(float.sizeof
== 4);
1894 uint xp
= path
.ptr
[ppos
]|
(path
.ptr
[ppos
+1]<<8)|
(path
.ptr
[ppos
+2]<<16)|
(path
.ptr
[ppos
+3]<<24);
1895 ppos
+= cast(uint)float.sizeof
;
1896 return *cast(const(float)*)(&xp
);
1900 float scaleX (in float v
) nothrow @trusted @nogc { pragma(inline
, true); return ofsx
+cast(float)v
*scalex
; }
1901 float scaleY (in float v
) nothrow @trusted @nogc { pragma(inline
, true); return ofsy
+cast(float)v
*scaley
; }
1903 static if (baph_debug_time
) {
1905 immutable tstt
= clockMicro();
1909 float cx
= 0.0f, cy
= 0.0f;
1910 bool doStroke
= false, doFill
= false;
1911 while (ppos
< plen
) {
1912 auto cmd
= getCommand();
1913 static if (baph_debug_dump
) {
1914 foreach (string mn
; __traits(allMembers
, Command
)) {
1915 if (__traits(getMember
, Command
, mn
) == cmd
) {
1916 import core
.stdc
.stdio
;
1917 static if (baph_debug_time
) {
1918 printf("cmd=%s ... ", mn
.ptr
);
1920 printf("cmd=%s\n", mn
.ptr
);
1924 static if (baph_debug_time
) {
1925 immutable cstt
= clockMicro();
1928 final switch (cmd
) {
1929 case Command
.Bounds
: ppos
+= 4*cast(uint)float.sizeof
; break;
1930 case Command
.StrokeMode
: doStroke
= true; doFill
= false; break;
1931 case Command
.FillMode
: doStroke
= false; doFill
= true; break;
1932 case Command
.StrokeFillMode
: doStroke
= true; doFill
= true; break;
1933 case Command
.NormalStroke
: case Command
.ThinStroke
: break;
1934 case Command
.MoveTo
:
1935 cx
= scaleX(getFloat());
1936 cy
= scaleY(getFloat());
1939 case Command
.LineTo
:
1940 immutable float ex
= scaleX(getFloat());
1941 immutable float ey
= scaleY(getFloat());
1946 case Command
.CubicTo
: // cubic bezier
1947 immutable float x1
= scaleX(getFloat());
1948 immutable float y1
= scaleY(getFloat());
1949 immutable float x2
= scaleX(getFloat());
1950 immutable float y2
= scaleY(getFloat());
1951 immutable float ex
= scaleX(getFloat());
1952 immutable float ey
= scaleY(getFloat());
1953 bezierTo(x1
, y1
, x2
, y2
, ex
, ey
);
1957 case Command
.EndPath
: // don't close this path
1959 if (doStroke
) stroke();
1960 //doFill = doStroke = false;
1964 static if (baph_debug_dump
&& baph_debug_time
) {
1965 immutable estt
= clockMicro()-cstt
;
1966 import core
.stdc
.stdio
; printf("microsecs: %u\n", cast(uint)estt
);
1969 static if (baph_debug_time
) {
1970 immutable estt
= clockMicro()-tstt
;
1971 import core
.stdc
.stdio
; printf("total microsecs: %u\n", cast(uint)estt
);
1974 static if (baph_debug_time
) {
1975 immutable fstt
= clockMicro();
1978 static if (baph_debug_time
) {
1979 immutable t
= clockMicro()-fstt
;
1980 import core
.stdc
.stdio
; printf("fill microsecs: %u\n", cast(uint)t
);
1984 static if (baph_debug_time
) {
1985 immutable sstt
= clockMicro();
1988 static if (baph_debug_time
) {
1989 immutable t
= clockMicro()-sstt
;
1990 import core
.stdc
.stdio
; printf("stroke microsecs: %u\n", cast(uint)t
);
1996 private static immutable ubyte[7641] baphometPath
= [
1997 0x01,0x04,0x06,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x08,0xa0,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,
1998 0x00,0x80,0xff,0x43,0xa2,0x1d,0xc6,0x43,0x00,0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x08,0x00,0x80,0xff,
1999 0x43,0x7a,0x89,0xe5,0x42,0xa0,0x1d,0xc6,0x43,0x00,0x00,0x00,0x00,0x30,0x89,0x7f,0x43,0x00,0x00,0x00,
2000 0x00,0x08,0x7a,0x89,0xe5,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0x89,0xe5,0x42,0x00,0x00,
2001 0x00,0x00,0x30,0x89,0x7f,0x43,0x08,0x00,0x00,0x00,0x00,0xa2,0x1d,0xc6,0x43,0x7a,0x89,0xe5,0x42,0x00,
2002 0x80,0xff,0x43,0x30,0x89,0x7f,0x43,0x00,0x80,0xff,0x43,0x09,0x06,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
2003 0x43,0x08,0x16,0x68,0xb3,0x43,0x72,0x87,0xdd,0x43,0x71,0x87,0xdd,0x43,0x17,0x68,0xb3,0x43,0x71,0x87,
2004 0xdd,0x43,0x30,0x89,0x7f,0x43,0x08,0x71,0x87,0xdd,0x43,0xd2,0x2f,0x18,0x43,0x16,0x68,0xb3,0x43,0x35,
2005 0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x35,0xe2,0x87,0x42,0x08,0xd1,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,
2006 0x35,0xe2,0x87,0x42,0xd2,0x2f,0x18,0x43,0x35,0xe2,0x87,0x42,0x30,0x89,0x7f,0x43,0x08,0x35,0xe2,0x87,
2007 0x42,0x17,0x68,0xb3,0x43,0xd1,0x2f,0x18,0x43,0x72,0x87,0xdd,0x43,0x30,0x89,0x7f,0x43,0x72,0x87,0xdd,
2008 0x43,0x09,0x06,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x07,0xa4,0x3f,0x7f,0x43,0x0b,0x86,0xdc,0x43,
2009 0x07,0x6c,0xb9,0xb2,0x43,0xe8,0xd1,0xca,0x42,0x07,0x6e,0x4d,0xa0,0x42,0xa9,0x10,0x9c,0x43,0x07,0xb7,
2010 0x40,0xd7,0x43,0xa9,0x10,0x9c,0x43,0x07,0x79,0xcb,0x11,0x43,0x62,0xbf,0xd7,0x42,0x09,0x06,0x98,0x42,
2011 0x74,0x43,0xb1,0x8d,0x68,0x43,0x08,0xd7,0x24,0x79,0x43,0xba,0x83,0x6e,0x43,0xa9,0x16,0x7c,0x43,0x56,
2012 0xa1,0x76,0x43,0x74,0x2a,0x7d,0x43,0x44,0x73,0x80,0x43,0x08,0x55,0xd1,0x7e,0x43,0xe3,0xea,0x76,0x43,
2013 0xbc,0x18,0x81,0x43,0x7f,0xa8,0x6e,0x43,0x8f,0x0a,0x84,0x43,0x02,0xfc,0x68,0x43,0x09,0x06,0x92,0x29,
2014 0x8d,0x43,0x73,0xc3,0x67,0x43,0x08,0xa4,0xd9,0x8e,0x43,0xf2,0xa6,0x7a,0x43,0x8f,0x22,0x88,0x43,0x75,
2015 0x2a,0x7d,0x43,0x42,0x7f,0x82,0x43,0x08,0xc8,0x88,0x43,0x09,0x06,0xc1,0x79,0x74,0x43,0x50,0x64,0x89,
2016 0x43,0x08,0x68,0x2d,0x72,0x43,0xee,0x21,0x81,0x43,0xcd,0x97,0x55,0x43,0xe6,0xf1,0x7b,0x43,0x91,0xec,
2017 0x5d,0x43,0xa8,0xc7,0x6a,0x43,0x09,0x06,0xfa,0xa5,0x52,0x43,0x60,0x97,0x7c,0x43,0x08,0x19,0xff,0x50,
2018 0x43,0xe9,0x6e,0x8a,0x43,0xb0,0xbd,0x70,0x43,0x4c,0x51,0x82,0x43,0x04,0xeb,0x69,0x43,0x66,0x0f,0x8e,
2019 0x43,0x09,0x06,0x17,0xbf,0x71,0x43,0x2c,0x58,0x94,0x43,0x08,0x1c,0x96,0x6e,0x43,0x61,0x68,0x99,0x43,
2020 0x2d,0x3a,0x6e,0x43,0xc8,0x81,0x9e,0x43,0xb7,0x9b,0x72,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0x30,0xdb,
2021 0x82,0x43,0xdb,0xe9,0x93,0x43,0x08,0x11,0x82,0x84,0x43,0x61,0x68,0x99,0x43,0xe8,0x4a,0x84,0x43,0x8e,
2022 0xa6,0x9e,0x43,0x42,0x7f,0x82,0x43,0x61,0xa4,0xa3,0x43,0x09,0x06,0xc4,0x02,0x85,0x43,0xd1,0x0b,0x92,
2023 0x43,0x08,0xd6,0xb2,0x86,0x43,0x34,0x1e,0x92,0x43,0x4f,0x58,0x87,0x43,0xa4,0xf1,0x92,0x43,0x03,0xd9,
2024 0x87,0x43,0x7b,0xc6,0x94,0x43,0x09,0x06,0x87,0x3e,0x64,0x43,0x31,0x3b,0x93,0x43,0x08,0x3b,0xbf,0x64,
2025 0x43,0x6f,0xf9,0x91,0x43,0x96,0x0b,0x67,0x43,0xc5,0x4a,0x91,0x43,0xcf,0xfe,0x6a,0x43,0x31,0x2f,0x91,
2026 0x43,0x09,0x06,0x16,0x74,0xb5,0x43,0x08,0xec,0x8e,0x43,0x08,0x1b,0x4b,0xb2,0x43,0xee,0x5d,0x8b,0x43,
2027 0x48,0x4d,0xad,0x43,0x12,0xa6,0x8a,0x43,0xf3,0xd7,0xa7,0x43,0x74,0xb8,0x8a,0x43,0x08,0x8c,0xb2,0xa0,
2028 0x43,0xcd,0xf8,0x8a,0x43,0x68,0x46,0x9b,0x43,0x79,0x8f,0x87,0x43,0x49,0xc9,0x96,0x43,0xe9,0x3e,0x82,
2029 0x43,0x08,0x60,0x5c,0x97,0x43,0xa1,0xde,0x8b,0x43,0x4e,0xa0,0x93,0x43,0x31,0x3b,0x93,0x43,0x9f,0xea,
2030 0x8d,0x43,0x27,0x8d,0x99,0x43,0x08,0x07,0xe0,0x8c,0x43,0x06,0x34,0x9b,0x43,0x38,0xe9,0x8c,0x43,0x46,
2031 0x0a,0x9e,0x43,0x3d,0xcc,0x8b,0x43,0xb2,0x06,0xa2,0x43,0x08,0xf1,0x40,0x8a,0x43,0xb0,0x12,0xa4,0x43,
2032 0x39,0xd1,0x88,0x43,0x76,0x43,0xa6,0x43,0xfa,0x06,0x88,0x43,0xa4,0x75,0xa9,0x43,0x08,0x19,0x6c,0x88,
2033 0x43,0x9f,0x9e,0xac,0x43,0x66,0xeb,0x87,0x43,0x44,0x76,0xb0,0x43,0x6b,0xce,0x86,0x43,0x3b,0xbc,0xb4,
2034 0x43,0x08,0xa9,0x8c,0x85,0x43,0x06,0xd0,0xb5,0x43,0xfa,0xee,0x83,0x43,0x74,0xa3,0xb6,0x43,0x3d,0x90,
2035 0x81,0x43,0x31,0xf6,0xb6,0x43,0x08,0x9d,0x61,0x7d,0x43,0xee,0x48,0xb7,0x43,0x3b,0x1f,0x75,0x43,0xcf,
2036 0xe3,0xb6,0x43,0xee,0x6f,0x6d,0x43,0x68,0xe2,0xb5,0x43,0x08,0xd4,0xed,0x6b,0x43,0x87,0x2f,0xb2,0x43,
2037 0x0e,0xc9,0x6b,0x43,0xa7,0x7c,0xae,0x43,0x98,0xfa,0x67,0x43,0xab,0x53,0xab,0x43,0x08,0x25,0x2c,0x64,
2038 0x43,0x33,0xa2,0xa8,0x43,0x40,0x96,0x61,0x43,0xc3,0xc2,0xa5,0x43,0x64,0xde,0x60,0x43,0xfa,0xa2,0xa2,
2039 0x43,0x08,0xb0,0x5d,0x60,0x43,0x06,0x4c,0x9f,0x43,0x9a,0xca,0x5f,0x43,0x38,0x3d,0x9b,0x43,0x3b,0x8f,
2040 0x5c,0x43,0x85,0xb0,0x98,0x43,0x08,0x42,0x36,0x51,0x43,0x3d,0xf0,0x91,0x43,0xcd,0x4f,0x49,0x43,0xdb,
2041 0xb9,0x8b,0x43,0xe0,0xdb,0x44,0x43,0x42,0x8b,0x84,0x43,0x08,0x7e,0xc9,0x44,0x43,0x8a,0x57,0x8d,0x43,
2042 0xbc,0x6c,0x0f,0x43,0x23,0x62,0x8e,0x43,0xf5,0x17,0x07,0x43,0xc5,0x3e,0x8f,0x43,0x09,0x06,0xe0,0xea,
2043 0x76,0x43,0xab,0xef,0xc5,0x43,0x08,0x12,0x00,0x79,0x43,0xab,0xcb,0xbf,0x43,0x79,0xb9,0x6d,0x43,0x7e,
2044 0x8d,0xba,0x43,0xee,0x6f,0x6d,0x43,0x98,0xeb,0xb5,0x43,0x08,0xe0,0x02,0x7b,0x43,0x5f,0x1c,0xb8,0x43,
2045 0x85,0x2c,0x82,0x43,0xe9,0x65,0xb8,0x43,0xd6,0xb2,0x86,0x43,0xc6,0x05,0xb5,0x43,0x08,0x03,0xcd,0x85,
2046 0x43,0x5a,0x39,0xb9,0x43,0xe4,0x4f,0x81,0x43,0xdb,0xd4,0xbf,0x43,0xdf,0x6c,0x82,0x43,0xbc,0x93,0xc5,
2047 0x43,0x09,0x06,0xf0,0xd0,0x22,0x43,0x5d,0x19,0x08,0x43,0x08,0xbc,0xab,0x49,0x43,0x4a,0x35,0x29,0x43,
2048 0xcb,0xf7,0x65,0x43,0xce,0x37,0x45,0x43,0x0e,0x99,0x63,0x43,0x67,0xc6,0x5c,0x43,0x09,0x06,0x05,0x94,
2049 0xab,0x43,0xc2,0x13,0x04,0x43,0x08,0x9f,0x26,0x98,0x43,0x11,0x42,0x25,0x43,0x97,0x00,0x8a,0x43,0x32,
2050 0x32,0x41,0x43,0xf5,0x2f,0x8b,0x43,0xc7,0xc0,0x58,0x43,0x09,0x06,0x8f,0x85,0x48,0x43,0xe0,0xa8,0x8c,
2051 0x43,0x08,0x55,0xaa,0x48,0x43,0xe0,0xa8,0x8c,0x43,0x6b,0x3d,0x49,0x43,0xc1,0x43,0x8c,0x43,0x31,0x62,
2052 0x49,0x43,0xc1,0x43,0x8c,0x43,0x08,0x2f,0xe3,0x2f,0x43,0xad,0xe7,0x98,0x43,0xff,0x0d,0x0d,0x43,0xad,
2053 0xf3,0x9a,0x43,0xf0,0xaf,0xcc,0x42,0x74,0x00,0x97,0x43,0x08,0xbb,0xa2,0xf7,0x42,0x93,0x4d,0x93,0x43,
2054 0x5e,0x19,0x08,0x43,0x5a,0x2a,0x87,0x43,0x23,0x6e,0x10,0x43,0x42,0x97,0x86,0x43,0x08,0xca,0xe8,0x33,
2055 0x43,0x1b,0x3c,0x80,0x43,0x80,0xe8,0x4d,0x43,0xda,0xf4,0x70,0x43,0xae,0x0e,0x4f,0x43,0x2b,0x1b,0x65,
2056 0x43,0x08,0x66,0x96,0x54,0x43,0xa3,0xe1,0x3b,0x43,0x4e,0xc4,0x19,0x43,0xa0,0x1a,0x16,0x43,0x10,0xe2,
2057 0x14,0x43,0x26,0x14,0xe0,0x42,0x08,0x5c,0x91,0x1c,0x43,0xcb,0x27,0xee,0x42,0xa9,0x40,0x24,0x43,0x71,
2058 0x3b,0xfc,0x42,0xf3,0xef,0x2b,0x43,0x8b,0x27,0x05,0x43,0x08,0xe2,0x4b,0x2c,0x43,0x48,0x86,0x07,0x43,
2059 0x79,0x62,0x2f,0x43,0x05,0xe5,0x09,0x43,0x55,0x32,0x34,0x43,0xa0,0xd2,0x09,0x43,0x08,0x74,0xa3,0x36,
2060 0x43,0x3a,0xd1,0x08,0x43,0x7e,0x81,0x38,0x43,0x09,0xd4,0x0a,0x43,0x0d,0xba,0x39,0x43,0xa0,0xea,0x0d,
2061 0x43,0x08,0x6f,0xe4,0x3d,0x43,0x43,0xc7,0x0e,0x43,0xd6,0xe5,0x3e,0x43,0xc4,0x4a,0x11,0x43,0x55,0x7a,
2062 0x40,0x43,0x59,0x72,0x13,0x43,0x08,0x55,0x92,0x44,0x43,0xbf,0x73,0x14,0x43,0x23,0x95,0x46,0x43,0xa5,
2063 0x09,0x17,0x43,0xe0,0xf3,0x48,0x43,0xfe,0x55,0x19,0x43,0x08,0xcd,0x4f,0x49,0x43,0xaa,0x10,0x1c,0x43,
2064 0x61,0x77,0x4b,0x43,0xfe,0x6d,0x1d,0x43,0x80,0xe8,0x4d,0x43,0x2b,0x94,0x1e,0x43,0x08,0x58,0xc9,0x51,
2065 0x43,0x41,0x27,0x1f,0x43,0x9b,0x82,0x53,0x43,0x35,0x72,0x20,0x43,0x53,0xf2,0x54,0x43,0x88,0xcf,0x21,
2066 0x43,0x08,0x7b,0x29,0x55,0x43,0xe8,0x0a,0x25,0x43,0xb2,0x2d,0x58,0x43,0xef,0xe8,0x26,0x43,0x9b,0xb2,
2067 0x5b,0x43,0xd0,0x8f,0x28,0x43,0x08,0x5f,0xef,0x5f,0x43,0xeb,0x11,0x2a,0x43,0xfd,0xdc,0x5f,0x43,0x6e,
2068 0x95,0x2c,0x43,0x3b,0xa7,0x60,0x43,0x2b,0xf4,0x2e,0x43,0x08,0x06,0xbb,0x61,0x43,0xfd,0xe5,0x31,0x43,
2069 0xe7,0x61,0x63,0x43,0xef,0x30,0x33,0x43,0x53,0x52,0x65,0x43,0xa3,0xb1,0x33,0x43,0x08,0x12,0xa0,0x68,
2070 0x43,0x7f,0x69,0x34,0x43,0x40,0xc6,0x69,0x43,0x64,0xff,0x36,0x43,0x7e,0x90,0x6a,0x43,0x71,0xcc,0x39,
2071 0x43,0x08,0xbc,0x5a,0x6b,0x43,0x51,0x73,0x3b,0x43,0xc1,0x49,0x6c,0x43,0xa5,0xd0,0x3c,0x43,0xe0,0xba,
2072 0x6e,0x43,0xb8,0x74,0x3c,0x43,0x08,0x6b,0x1c,0x73,0x43,0x13,0xc1,0x3e,0x43,0x40,0xf6,0x71,0x43,0xce,
2073 0x1f,0x41,0x43,0x55,0x89,0x72,0x43,0x8d,0x7e,0x43,0x43,0x08,0x68,0x2d,0x72,0x43,0x89,0xae,0x4b,0x43,
2074 0xc1,0x79,0x74,0x43,0xcb,0x78,0x4c,0x43,0x55,0xa1,0x76,0x43,0x5b,0xb1,0x4d,0x43,0x08,0xa2,0x38,0x7a,
2075 0x43,0xd1,0x56,0x4e,0x43,0x85,0xb6,0x78,0x43,0xb1,0x15,0x54,0x43,0x83,0xc7,0x77,0x43,0x89,0x0e,0x5c,
2076 0x43,0x08,0xcf,0x46,0x77,0x43,0x0f,0x81,0x5f,0x43,0x1a,0xde,0x7a,0x43,0xce,0xc7,0x5d,0x43,0x42,0x73,
2077 0x80,0x43,0x99,0xc3,0x5a,0x43,0x08,0x85,0x2c,0x82,0x43,0xf6,0xe6,0x59,0x43,0x81,0x3d,0x81,0x43,0x16,
2078 0x10,0x50,0x43,0xd6,0x8e,0x80,0x43,0x5b,0x99,0x49,0x43,0x08,0xc4,0xea,0x80,0x43,0x22,0x95,0x46,0x43,
2079 0xfa,0xe2,0x81,0x43,0xda,0xec,0x43,0x43,0x78,0x77,0x83,0x43,0xe4,0xb2,0x41,0x43,0x08,0x8a,0x27,0x85,
2080 0x43,0x86,0x77,0x3e,0x43,0x0c,0x9f,0x85,0x43,0x07,0xf4,0x3b,0x43,0x8f,0x16,0x86,0x43,0xe6,0x82,0x39,
2081 0x43,0x08,0x85,0x44,0x86,0x43,0x37,0xd9,0x35,0x43,0x1e,0x4f,0x87,0x43,0xe1,0x7b,0x34,0x43,0xdf,0x90,
2082 0x88,0x43,0xb6,0x55,0x33,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0xe5,0x31,0x43,0xfa,0x12,0x8a,0x43,0xbf,
2083 0x03,0x2d,0x43,0x19,0x78,0x8a,0x43,0x45,0x5e,0x2c,0x43,0x08,0x03,0xf1,0x8b,0x43,0xac,0x47,0x29,0x43,
2084 0x2f,0x17,0x8d,0x43,0x45,0x46,0x28,0x43,0xc8,0x21,0x8e,0x43,0x30,0xb3,0x27,0x43,0x08,0xa9,0xc8,0x8f,
2085 0x43,0xef,0xe8,0x26,0x43,0xbf,0x5b,0x90,0x43,0x5b,0xc1,0x24,0x43,0x10,0xca,0x90,0x43,0xa0,0x62,0x22,
2086 0x43,0x08,0x26,0x5d,0x91,0x43,0xbb,0xcc,0x1f,0x43,0xf0,0x70,0x92,0x43,0x78,0x13,0x1e,0x43,0x77,0xd7,
2087 0x93,0x43,0x73,0x24,0x1d,0x43,0x08,0x65,0x3f,0x96,0x43,0xce,0x58,0x1b,0x43,0xbe,0x7f,0x96,0x43,0xbf,
2088 0x8b,0x18,0x43,0x60,0x5c,0x97,0x43,0xb6,0xad,0x16,0x43,0x08,0xba,0xa8,0x99,0x43,0x78,0xcb,0x11,0x43,
2089 0x49,0xe1,0x9a,0x43,0x78,0xcb,0x11,0x43,0x01,0x51,0x9c,0x43,0x73,0xdc,0x10,0x43,0x08,0x72,0x24,0x9d,
2090 0x43,0xd2,0xff,0x0f,0x43,0x1c,0xd3,0x9d,0x43,0x07,0xec,0x0e,0x43,0xeb,0xc9,0x9d,0x43,0xe8,0x7a,0x0c,
2091 0x43,0x08,0x60,0x80,0x9d,0x43,0xd7,0xbe,0x08,0x43,0x4d,0xe8,0x9f,0x43,0x86,0x50,0x08,0x43,0x25,0xbd,
2092 0xa1,0x43,0x5b,0x2a,0x07,0x43,0x08,0x99,0x7f,0xa3,0x43,0xc9,0xf1,0x05,0x43,0x48,0x1d,0xa5,0x43,0x86,
2093 0x38,0x04,0x43,0x6c,0x71,0xa6,0x43,0x18,0x59,0x01,0x43,0x08,0x32,0x96,0xa6,0x43,0x6e,0x64,0xff,0x42,
2094 0x48,0x29,0xa7,0x43,0xed,0xcf,0xfd,0x42,0x5f,0xbc,0xa7,0x43,0x71,0x3b,0xfc,0x42,0x08,0xf3,0xe3,0xa9,
2095 0x43,0xf7,0x7d,0xf7,0x42,0xd8,0x6d,0xaa,0x43,0x45,0xe5,0xf2,0x42,0x48,0x41,0xab,0x43,0xcb,0x27,0xee,
2096 0x42,0x08,0x24,0xf9,0xab,0x43,0x52,0x6a,0xe9,0x42,0xee,0x0c,0xad,0x43,0x4c,0x8c,0xe7,0x42,0x1b,0x33,
2097 0xae,0x43,0xcc,0xf7,0xe5,0x42,0x08,0xaa,0x6b,0xaf,0x43,0xe8,0x61,0xe3,0x42,0x90,0xf5,0xaf,0x43,0xc9,
2098 0xf0,0xe0,0x42,0xe0,0x63,0xb0,0x43,0xe5,0x5a,0xde,0x42,0x08,0xaa,0x83,0xb3,0x43,0x29,0x2d,0x09,0x43,
2099 0x6a,0xfe,0x8e,0x43,0xb8,0x74,0x3c,0x43,0xd5,0x06,0x95,0x43,0xe6,0x79,0x67,0x43,0x08,0x2f,0x53,0x97,
2100 0x43,0xe9,0xb0,0x74,0x43,0xa8,0x28,0xa0,0x43,0x43,0xfd,0x76,0x43,0x83,0x28,0xad,0x43,0x17,0x59,0x81,
2101 0x43,0x08,0x3d,0xe7,0xbf,0x43,0x4b,0x8d,0x8c,0x43,0xae,0x96,0xba,0x43,0x66,0x27,0x92,0x43,0x15,0xe0,
2102 0xc7,0x43,0x6f,0x11,0x96,0x43,0x08,0x7e,0x5d,0xb2,0x43,0xdb,0x01,0x98,0x43,0x9e,0x56,0xa0,0x43,0x80,
2103 0xc1,0x97,0x43,0x69,0x2e,0x97,0x43,0x31,0x17,0x8d,0x43,0x09,0x06,0xab,0xa7,0x39,0x43,0x67,0x0f,0x0e,
2104 0x43,0x08,0xdb,0xbc,0x3b,0x43,0xe8,0x92,0x10,0x43,0xb5,0x85,0x3b,0x43,0x97,0x3c,0x14,0x43,0xab,0xa7,
2105 0x39,0x43,0x0c,0x0b,0x18,0x43,0x09,0x06,0xca,0x30,0x40,0x43,0x30,0x3b,0x13,0x43,0x08,0x17,0xc8,0x43,
2106 0x43,0xa5,0x09,0x17,0x43,0x7e,0xc9,0x44,0x43,0x1a,0xd8,0x1a,0x43,0x9d,0x22,0x43,0x43,0x8d,0xa6,0x1e,
2107 0x43,0x09,0x06,0xc8,0x78,0x4c,0x43,0xed,0xc9,0x1d,0x43,0x08,0x0b,0x32,0x4e,0x43,0x22,0xce,0x20,0x43,
2108 0x23,0xc5,0x4e,0x43,0x58,0xd2,0x23,0x43,0x0b,0x32,0x4e,0x43,0x2b,0xc4,0x26,0x43,0x09,0x06,0xec,0x08,
2109 0x58,0x43,0xc7,0xb1,0x26,0x43,0x08,0x02,0x9c,0x58,0x43,0xef,0x00,0x2b,0x43,0xd9,0x64,0x58,0x43,0x02,
2110 0xbd,0x2e,0x43,0x10,0x51,0x57,0x43,0x37,0xc1,0x31,0x43,0x09,0x06,0xcb,0xdf,0x61,0x43,0x4a,0x65,0x31,
2111 0x43,0x08,0xbe,0x2a,0x63,0x43,0xbd,0x33,0x35,0x43,0x32,0xe1,0x62,0x43,0x56,0x4a,0x38,0x43,0xde,0x83,
2112 0x61,0x43,0x3c,0xe0,0x3a,0x43,0x09,0x06,0x1c,0x7e,0x6a,0x43,0x5b,0x39,0x39,0x43,0x08,0x31,0x11,0x6b,
2113 0x43,0x0c,0xd2,0x3d,0x43,0x1c,0x7e,0x6a,0x43,0x13,0xd9,0x42,0x43,0xd9,0xc4,0x68,0x43,0xcb,0x60,0x48,
2114 0x43,0x09,0x06,0xe5,0xc1,0x73,0x43,0x16,0xf8,0x4b,0x43,0x08,0xa6,0xf7,0x72,0x43,0xb1,0xfd,0x4f,0x43,
2115 0x3b,0x07,0x71,0x43,0x4a,0x14,0x53,0x43,0xa2,0xf0,0x6d,0x43,0x7c,0x29,0x55,0x43,0x09,0x06,0x00,0x8d,
2116 0xa6,0x43,0xef,0x21,0x01,0x43,0x08,0x52,0xfb,0xa6,0x43,0xce,0xc8,0x02,0x43,0xe6,0x16,0xa7,0x43,0x51,
2117 0x4c,0x05,0x43,0x3b,0x68,0xa6,0x43,0x4c,0x75,0x08,0x43,0x09,0x06,0xde,0x20,0xa1,0x43,0x86,0x50,0x08,
2118 0x43,0x08,0xd4,0x4e,0xa1,0x43,0xd3,0xe7,0x0b,0x43,0xb5,0xe9,0xa0,0x43,0x59,0x5a,0x0f,0x43,0xba,0xcc,
2119 0x9f,0x43,0x54,0x83,0x12,0x43,0x09,0x06,0x77,0xfb,0x99,0x43,0x6c,0x16,0x13,0x43,0x08,0xde,0xfc,0x9a,
2120 0x43,0x4a,0xbd,0x14,0x43,0x06,0x34,0x9b,0x43,0xfe,0x55,0x19,0x43,0x13,0xe9,0x99,0x43,0x41,0x27,0x1f,
2121 0x43,0x09,0x06,0x46,0xce,0x93,0x43,0x26,0xa5,0x1d,0x43,0x08,0xe7,0xaa,0x94,0x43,0xbb,0xcc,0x1f,0x43,
2122 0x18,0xb4,0x94,0x43,0xa8,0x40,0x24,0x43,0xe2,0xbb,0x93,0x43,0x21,0xfe,0x28,0x43,0x09,0x06,0xb1,0x8e,
2123 0x8d,0x43,0xa8,0x58,0x28,0x43,0x08,0x19,0x90,0x8e,0x43,0x54,0x13,0x2b,0x43,0xa4,0xd9,0x8e,0x43,0x84,
2124 0x40,0x31,0x43,0x46,0xaa,0x8d,0x43,0x29,0x24,0x37,0x43,0x09,0x06,0xd6,0xbe,0x88,0x43,0xef,0x30,0x33,
2125 0x43,0x08,0x0c,0xb7,0x89,0x43,0x0e,0xa2,0x35,0x43,0xc0,0x37,0x8a,0x43,0x7a,0xaa,0x3b,0x43,0xbb,0x48,
2126 0x89,0x43,0xbb,0x7b,0x41,0x43,0x09,0x06,0x3a,0xad,0x82,0x43,0xc4,0x59,0x43,0x43,0x08,0xd2,0xb7,0x83,
2127 0x43,0x2b,0x5b,0x44,0x43,0x35,0xd6,0x85,0x43,0x48,0xf5,0x49,0x43,0x42,0x97,0x86,0x43,0xc4,0xa1,0x4f,
2128 0x43,0x09,0x06,0x9c,0xb3,0x80,0x43,0x48,0x55,0x5a,0x43,0x08,0xff,0xc5,0x80,0x43,0x09,0x73,0x55,0x43,
2129 0x93,0xe1,0x80,0x43,0x0f,0x39,0x53,0x43,0xf1,0xbe,0x7e,0x43,0x18,0xe7,0x4c,0x43,0x09,0x06,0xe0,0x02,
2130 0x7b,0x43,0x92,0xec,0x5d,0x43,0x08,0x09,0x3a,0x7b,0x43,0xf0,0xf7,0x58,0x43,0x09,0x3a,0x7b,0x43,0xe6,
2131 0x31,0x5b,0x43,0xe0,0x02,0x7b,0x43,0xa8,0x4f,0x56,0x43,0x09,0x06,0x39,0x4f,0x7d,0x43,0x3e,0x8f,0x5c,
2132 0x43,0x08,0xe9,0xe0,0x7c,0x43,0x03,0x9c,0x58,0x43,0x1e,0x2b,0x81,0x43,0x7f,0x30,0x5a,0x43,0xff,0x73,
2133 0x7d,0x43,0xf6,0xb6,0x51,0x43,0x09,0x06,0x5c,0xb8,0x52,0x43,0x28,0x21,0x87,0x43,0x08,0xae,0x3e,0x57,
2134 0x43,0x12,0x9a,0x88,0x43,0x23,0xf5,0x56,0x43,0x04,0xf1,0x8b,0x43,0x25,0xfc,0x5b,0x43,0x85,0x74,0x8e,
2135 0x43,0x08,0x2f,0xf2,0x61,0x43,0x8e,0x52,0x90,0x43,0xd9,0xdc,0x6c,0x43,0x85,0x74,0x8e,0x43,0xc6,0x20,
2136 0x69,0x43,0x3d,0xd8,0x8d,0x43,0x08,0x6d,0x8c,0x5a,0x43,0xf5,0x3b,0x8d,0x43,0x3d,0x77,0x58,0x43,0xa1,
2137 0xc6,0x87,0x43,0xf8,0xed,0x5e,0x43,0x5e,0x0d,0x86,0x43,0x09,0x06,0xde,0xcc,0x92,0x43,0xf7,0x17,0x87,
2138 0x43,0x08,0xb6,0x89,0x90,0x43,0xae,0x87,0x88,0x43,0x4a,0xa5,0x90,0x43,0xa1,0xde,0x8b,0x43,0xf9,0x2a,
2139 0x8e,0x43,0x23,0x62,0x8e,0x43,0x08,0xf5,0x2f,0x8b,0x43,0x5c,0x49,0x90,0x43,0x35,0xd6,0x85,0x43,0x8e,
2140 0x46,0x8e,0x43,0x3d,0xb4,0x87,0x43,0x47,0xaa,0x8d,0x43,0x08,0x6a,0xfe,0x8e,0x43,0xff,0x0d,0x8d,0x43,
2141 0xbb,0x6c,0x8f,0x43,0xf7,0x17,0x87,0x43,0x5c,0x31,0x8c,0x43,0xb2,0x5e,0x85,0x43,0x09,0x06,0x60,0x38,
2142 0x91,0x43,0x69,0x5d,0x7a,0x43,0x08,0x34,0x1e,0x92,0x43,0x1e,0x5b,0x89,0x43,0x04,0x63,0x7e,0x43,0x5e,
2143 0x01,0x84,0x43,0x59,0x2a,0x87,0x43,0x0d,0xcf,0x8d,0x43,0x09,0x03,0x04,0x06,0x5a,0x18,0x63,0x43,0x82,
2144 0x79,0x8b,0x43,0x08,0x25,0x2c,0x64,0x43,0x82,0x79,0x8b,0x43,0x2a,0x1b,0x65,0x43,0x9d,0xef,0x8a,0x43,
2145 0x2a,0x1b,0x65,0x43,0xc1,0x37,0x8a,0x43,0x08,0x2a,0x1b,0x65,0x43,0x17,0x89,0x89,0x43,0x25,0x2c,0x64,
2146 0x43,0x31,0xff,0x88,0x43,0x5a,0x18,0x63,0x43,0x31,0xff,0x88,0x43,0x08,0xf3,0x16,0x62,0x43,0x31,0xff,
2147 0x88,0x43,0xee,0x27,0x61,0x43,0x17,0x89,0x89,0x43,0xee,0x27,0x61,0x43,0xc1,0x37,0x8a,0x43,0x08,0xee,
2148 0x27,0x61,0x43,0x9d,0xef,0x8a,0x43,0xf3,0x16,0x62,0x43,0x82,0x79,0x8b,0x43,0x5a,0x18,0x63,0x43,0x82,
2149 0x79,0x8b,0x43,0x09,0x06,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x08,0x34,0xee,0x89,0x43,0x82,0x79,
2150 0x8b,0x43,0x85,0x5c,0x8a,0x43,0x9d,0xef,0x8a,0x43,0x85,0x5c,0x8a,0x43,0xc1,0x37,0x8a,0x43,0x08,0x85,
2151 0x5c,0x8a,0x43,0x17,0x89,0x89,0x43,0x34,0xee,0x89,0x43,0x31,0xff,0x88,0x43,0x4f,0x64,0x89,0x43,0x31,
2152 0xff,0x88,0x43,0x08,0x9c,0xe3,0x88,0x43,0x31,0xff,0x88,0x43,0x19,0x6c,0x88,0x43,0x17,0x89,0x89,0x43,
2153 0x19,0x6c,0x88,0x43,0xc1,0x37,0x8a,0x43,0x08,0x19,0x6c,0x88,0x43,0x9d,0xef,0x8a,0x43,0x9c,0xe3,0x88,
2154 0x43,0x82,0x79,0x8b,0x43,0x4f,0x64,0x89,0x43,0x82,0x79,0x8b,0x43,0x09,0x02,0x04,0x06,0x19,0x60,0x86,
2155 0x43,0xec,0xed,0xa3,0x43,0x08,0x35,0xd6,0x85,0x43,0x76,0x43,0xa6,0x43,0x93,0xe1,0x80,0x43,0x57,0x02,
2156 0xac,0x43,0x61,0xd8,0x80,0x43,0x87,0x17,0xae,0x43,0x08,0xa5,0x85,0x80,0x43,0xc3,0xfe,0xaf,0x43,0xce,
2157 0xbc,0x80,0x43,0x83,0x40,0xb1,0x43,0xa5,0x91,0x82,0x43,0x79,0x6e,0xb1,0x43,0x08,0x23,0x26,0x84,0x43,
2158 0x40,0x93,0xb1,0x43,0x30,0xe7,0x84,0x43,0xbe,0x1b,0xb1,0x43,0x11,0x82,0x84,0x43,0xab,0x6b,0xaf,0x43,
2159 0x08,0xb7,0x41,0x84,0x43,0x3b,0x98,0xae,0x43,0xb7,0x41,0x84,0x43,0xc3,0xf2,0xad,0x43,0xa1,0xae,0x83,
2160 0x43,0x83,0x28,0xad,0x43,0x08,0xb2,0x52,0x83,0x43,0x80,0x39,0xac,0x43,0x81,0x49,0x83,0x43,0xf0,0x00,
2161 0xab,0x43,0xe4,0x67,0x85,0x43,0x76,0x4f,0xa8,0x43,0x08,0x9c,0xd7,0x86,0x43,0xd1,0x83,0xa6,0x43,0xec,
2162 0x45,0x87,0x43,0x01,0x75,0xa2,0x43,0x19,0x60,0x86,0x43,0xec,0xed,0xa3,0x43,0x09,0x06,0xd9,0xdc,0x6c,
2163 0x43,0x14,0x25,0xa4,0x43,0x08,0xa2,0xf0,0x6d,0x43,0x9f,0x7a,0xa6,0x43,0x47,0xec,0x77,0x43,0x80,0x39,
2164 0xac,0x43,0xa9,0xfe,0x77,0x43,0xb0,0x4e,0xae,0x43,0x08,0x23,0xa4,0x78,0x43,0xea,0x35,0xb0,0x43,0xd2,
2165 0x35,0x78,0x43,0xab,0x77,0xb1,0x43,0xc1,0x79,0x74,0x43,0xa2,0xa5,0xb1,0x43,0x08,0xc6,0x50,0x71,0x43,
2166 0x68,0xca,0xb1,0x43,0xab,0xce,0x6f,0x43,0xe7,0x52,0xb1,0x43,0xea,0x98,0x70,0x43,0xd4,0xa2,0xaf,0x43,
2167 0x08,0x9d,0x19,0x71,0x43,0x96,0xd8,0xae,0x43,0x9d,0x19,0x71,0x43,0xec,0x29,0xae,0x43,0xca,0x3f,0x72,
2168 0x43,0xab,0x5f,0xad,0x43,0x08,0xa6,0xf7,0x72,0x43,0xa7,0x70,0xac,0x43,0x09,0x0a,0x73,0x43,0x17,0x38,
2169 0xab,0x43,0x44,0xcd,0x6e,0x43,0x9f,0x86,0xa8,0x43,0x08,0xd4,0xed,0x6b,0x43,0xf8,0xba,0xa6,0x43,0x31,
2170 0x11,0x6b,0x43,0x2a,0xac,0xa2,0x43,0xd9,0xdc,0x6c,0x43,0x14,0x25,0xa4,0x43,0x09,0x01,0x05,0x06,0x66,
2171 0x5d,0x7a,0x43,0x74,0xeb,0xc2,0x43,0x08,0x09,0x22,0x77,0x43,0x50,0xbb,0xc7,0x43,0xe9,0xe0,0x7c,0x43,
2172 0xf5,0x86,0xc9,0x43,0x8f,0x94,0x7a,0x43,0xc5,0x95,0xcd,0x43,0x09,0x06,0x08,0x98,0x80,0x43,0x6b,0x19,
2173 0xc3,0x43,0x08,0xb7,0x35,0x82,0x43,0x79,0xf2,0xc7,0x43,0xf1,0xbe,0x7e,0x43,0x1e,0xbe,0xc9,0x43,0x73,
2174 0x7c,0x80,0x43,0xec,0xcc,0xcd,0x43,0x09,0x06,0x28,0xab,0x7d,0x43,0xae,0xde,0xc6,0x43,0x08,0x1e,0xcd,
2175 0x7b,0x43,0x8a,0xa2,0xc9,0x43,0x30,0x89,0x7f,0x43,0x5c,0x94,0xcc,0x43,0x28,0xab,0x7d,0x43,0x42,0x2a,
2176 0xcf,0x43,0x09,0x01,0x05,0x06,0x24,0x14,0xe0,0x42,0xf5,0x77,0x97,0x43,0x08,0xf7,0x1d,0xe7,0x42,0x74,
2177 0x00,0x97,0x43,0x4d,0x93,0xec,0x42,0xdb,0xf5,0x95,0x43,0x29,0x4b,0xed,0x42,0xcd,0x34,0x95,0x43,0x09,
2178 0x06,0x29,0x7b,0xf5,0x42,0x6f,0x1d,0x98,0x43,0x08,0xe4,0xf1,0xfb,0x42,0x61,0x5c,0x97,0x43,0xdb,0x7d,
2179 0x01,0x43,0xb2,0xbe,0x95,0x43,0x55,0x23,0x02,0x43,0xe7,0xaa,0x94,0x43,0x09,0x06,0x98,0xdc,0x03,0x43,
2180 0xbe,0x8b,0x98,0x43,0x08,0x66,0xdf,0x05,0x43,0x47,0xe6,0x97,0x43,0xae,0x87,0x08,0x43,0x98,0x48,0x96,
2181 0x43,0x61,0x08,0x09,0x43,0xd6,0x06,0x95,0x43,0x09,0x06,0x31,0x0b,0x0b,0x43,0x8e,0x82,0x98,0x43,0x08,
2182 0xdb,0xc5,0x0d,0x43,0x80,0xc1,0x97,0x43,0xd6,0xee,0x10,0x43,0xa9,0xec,0x95,0x43,0x79,0xcb,0x11,0x43,
2183 0x55,0x8f,0x94,0x43,0x09,0x06,0xd1,0x2f,0x18,0x43,0xdb,0x01,0x98,0x43,0x08,0xad,0xe7,0x18,0x43,0x38,
2184 0x25,0x97,0x43,0x8a,0x9f,0x19,0x43,0x80,0xb5,0x95,0x43,0xd6,0x1e,0x19,0x43,0xe0,0xd8,0x94,0x43,0x09,
2185 0x06,0x9a,0x5b,0x1d,0x43,0x58,0x8a,0x97,0x43,0x08,0x01,0x5d,0x1e,0x43,0xf1,0x88,0x96,0x43,0x2f,0x83,
2186 0x1f,0x43,0x19,0xb4,0x94,0x43,0x19,0xf0,0x1e,0x43,0x6f,0x05,0x94,0x43,0x09,0x06,0x0b,0x53,0x24,0x43,
2187 0xae,0xdb,0x96,0x43,0x08,0x25,0xd5,0x25,0x43,0x50,0xac,0x95,0x43,0x53,0xfb,0x26,0x43,0x8a,0x7b,0x93,
2188 0x43,0x76,0x43,0x26,0x43,0xb7,0x95,0x92,0x43,0x09,0x06,0x76,0x5b,0x2a,0x43,0x47,0xda,0x95,0x43,0x08,
2189 0xf3,0xef,0x2b,0x43,0x10,0xe2,0x94,0x43,0x6d,0x95,0x2c,0x43,0xae,0xc3,0x92,0x43,0x68,0xa6,0x2b,0x43,
2190 0x47,0xc2,0x91,0x43,0x09,0x06,0x36,0xc1,0x31,0x43,0x2c,0x58,0x94,0x43,0x08,0x8c,0x1e,0x33,0x43,0x31,
2191 0x3b,0x93,0x43,0x79,0x7a,0x33,0x43,0xff,0x25,0x91,0x43,0xd9,0x9d,0x32,0x43,0xc1,0x5b,0x90,0x43,0x09,
2192 0x06,0x25,0x35,0x36,0x43,0x31,0x3b,0x93,0x43,0x08,0x3f,0xb7,0x37,0x43,0xc1,0x67,0x92,0x43,0xe0,0x93,
2193 0x38,0x43,0xae,0xb7,0x90,0x43,0x7e,0x81,0x38,0x43,0x0d,0xdb,0x8f,0x43,0x09,0x06,0xb5,0x85,0x3b,0x43,
2194 0xe4,0xaf,0x91,0x43,0x08,0xcf,0x07,0x3d,0x43,0x9d,0x13,0x91,0x43,0xbc,0x63,0x3d,0x43,0x47,0xb6,0x8f,
2195 0x43,0xe5,0x9a,0x3d,0x43,0x74,0xd0,0x8e,0x43,0x09,0x06,0xae,0xc6,0x42,0x43,0xa4,0xd9,0x8e,0x43,0x08,
2196 0xca,0x48,0x44,0x43,0xfa,0x2a,0x8e,0x43,0xa2,0x11,0x44,0x43,0x9d,0xfb,0x8c,0x43,0x55,0x92,0x44,0x43,
2197 0x0d,0xc3,0x8b,0x43,0x09,0x06,0x39,0x10,0xc3,0x43,0x34,0x36,0x96,0x43,0x08,0x92,0x44,0xc1,0x43,0xe4,
2198 0xc7,0x95,0x43,0x6f,0xf0,0xbf,0x43,0x4b,0xbd,0x94,0x43,0x47,0xb9,0xbf,0x43,0x0b,0xf3,0x93,0x43,0x09,
2199 0x06,0x8f,0x49,0xbe,0x43,0xb7,0xad,0x96,0x43,0x08,0x11,0xb5,0xbc,0x43,0x77,0xe3,0x95,0x43,0x9c,0xf2,
2200 0xba,0x43,0xfa,0x4e,0x94,0x43,0xae,0x96,0xba,0x43,0x31,0x3b,0x93,0x43,0x09,0x06,0xdb,0xb0,0xb9,0x43,
2201 0x10,0xee,0x96,0x43,0x08,0x42,0xa6,0xb8,0x43,0xc8,0x51,0x96,0x43,0x50,0x5b,0xb7,0x43,0x19,0xb4,0x94,
2202 0x43,0xf7,0x1a,0xb7,0x43,0x58,0x72,0x93,0x43,0x09,0x06,0xf2,0x2b,0xb6,0x43,0x10,0xee,0x96,0x43,0x08,
2203 0x9d,0xce,0xb4,0x43,0x04,0x2d,0x96,0x43,0xed,0x30,0xb3,0x43,0x2c,0x58,0x94,0x43,0xce,0xcb,0xb2,0x43,
2204 0xd6,0xfa,0x92,0x43,0x09,0x06,0x5a,0x09,0xb1,0x43,0x19,0xc0,0x96,0x43,0x08,0x6c,0xad,0xb0,0x43,0x77,
2205 0xe3,0x95,0x43,0x7e,0x51,0xb0,0x43,0xc0,0x73,0x94,0x43,0xd8,0x91,0xb0,0x43,0x1e,0x97,0x93,0x43,0x09,
2206 0x06,0x48,0x4d,0xad,0x43,0xbe,0x7f,0x96,0x43,0x08,0x95,0xcc,0xac,0x43,0x58,0x7e,0x95,0x43,0x4d,0x30,
2207 0xac,0x43,0x80,0xa9,0x93,0x43,0xd8,0x79,0xac,0x43,0xd6,0xfa,0x92,0x43,0x09,0x06,0x90,0xd1,0xa9,0x43,
2208 0x14,0xd1,0x95,0x43,0x08,0x83,0x10,0xa9,0x43,0xb7,0xa1,0x94,0x43,0x3b,0x74,0xa8,0x43,0xf1,0x70,0x92,
2209 0x43,0x29,0xd0,0xa8,0x43,0x1e,0x8b,0x91,0x43,0x09,0x06,0x5a,0xcd,0xa6,0x43,0x8a,0x87,0x95,0x43,0x08,
2210 0x1c,0x03,0xa6,0x43,0x23,0x86,0x94,0x43,0x5f,0xb0,0xa5,0x43,0xc1,0x67,0x92,0x43,0xe1,0x27,0xa6,0x43,
2211 0x8a,0x6f,0x91,0x43,0x09,0x06,0xd4,0x5a,0xa3,0x43,0x2c,0x58,0x94,0x43,0x08,0x29,0xac,0xa2,0x43,0x31,
2212 0x3b,0x93,0x43,0x32,0x7e,0xa2,0x43,0xff,0x25,0x91,0x43,0x83,0xec,0xa2,0x43,0x8e,0x52,0x90,0x43,0x09,
2213 0x06,0xf8,0x96,0xa0,0x43,0x1e,0x97,0x93,0x43,0x08,0xeb,0xd5,0x9f,0x43,0x7b,0xba,0x92,0x43,0x99,0x67,
2214 0x9f,0x43,0x9d,0x13,0x91,0x43,0x99,0x67,0x9f,0x43,0xfa,0x36,0x90,0x43,0x09,0x06,0xeb,0xc9,0x9d,0x43,
2215 0xc8,0x39,0x92,0x43,0x08,0xde,0x08,0x9d,0x43,0xb2,0xa6,0x91,0x43,0xe6,0xda,0x9c,0x43,0x2c,0x40,0x90,
2216 0x43,0x52,0xbf,0x9c,0x43,0x5a,0x5a,0x8f,0x43,0x09,0x06,0x37,0x3d,0x9b,0x43,0x85,0x80,0x90,0x43,0x08,
2217 0x2a,0x7c,0x9a,0x43,0xdb,0xd1,0x8f,0x43,0xf0,0xa0,0x9a,0x43,0x7d,0xa2,0x8e,0x43,0x65,0x57,0x9a,0x43,
2218 0xee,0x69,0x8d,0x43,0x09,0x02,0x04,0x06,0x2a,0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x08,0x0d,0x8a,0x31,
2219 0x42,0x9f,0x0e,0x94,0x43,0xf3,0x1f,0x34,0x42,0x3d,0xfc,0x93,0x43,0x63,0xff,0x36,0x42,0xa9,0xe0,0x93,
2220 0x43,0x08,0xb5,0x34,0x5d,0x42,0x0b,0xf3,0x93,0x43,0x6d,0xa4,0x5e,0x42,0x03,0x39,0x98,0x43,0xe7,0x31,
2221 0x5b,0x42,0x93,0x89,0x9d,0x43,0x08,0x02,0x9c,0x58,0x42,0xd4,0x5a,0xa3,0x43,0x38,0x70,0x53,0x42,0x14,
2222 0x49,0xaa,0x43,0xf8,0xed,0x5e,0x42,0x83,0x28,0xad,0x43,0x08,0xea,0x68,0x68,0x42,0x20,0x22,0xaf,0x43,
2223 0x12,0xb8,0x6c,0x42,0xb5,0x49,0xb1,0x43,0x2a,0x4b,0x6d,0x42,0x0d,0x96,0xb3,0x43,0x07,0x2a,0x4b,0x6d,
2224 0x42,0xc6,0x05,0xb5,0x43,0x08,0x87,0x6e,0x6c,0x42,0x68,0xee,0xb7,0x43,0x1c,0x66,0x66,0x42,0x31,0x0e,
2225 0xbb,0x43,0x57,0x11,0x5e,0x42,0x8f,0x49,0xbe,0x43,0x08,0x66,0x96,0x54,0x42,0xb9,0x5c,0xb8,0x43,0x2c,
2226 0x2b,0x3c,0x42,0x68,0xd6,0xb3,0x43,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x07,0x2a,0xf4,0x2e,0x42,
2227 0x61,0xa4,0xa3,0x43,0x08,0x55,0x1a,0x30,0x42,0xf0,0xd0,0xa2,0x43,0xf8,0xf6,0x30,0x42,0xb2,0x06,0xa2,
2228 0x43,0x98,0xd3,0x31,0x42,0xd6,0x4e,0xa1,0x43,0x08,0x1c,0x6f,0x38,0x42,0x2a,0x94,0x9e,0x43,0xc1,0x22,
2229 0x36,0x42,0xf5,0x9b,0x9d,0x43,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x57,
2230 0xa2,0x9b,0x43,0x08,0xab,0x8f,0x35,0x42,0x8a,0xab,0x9b,0x43,0xe9,0x71,0x3a,0x42,0xb2,0xe2,0x9b,0x43,
2231 0xb7,0x74,0x3c,0x42,0x34,0x5a,0x9c,0x43,0x08,0x23,0x7d,0x42,0x42,0x0b,0x2f,0x9e,0x43,0xe5,0x9a,0x3d,
2232 0x42,0x38,0x6d,0xa3,0x43,0x36,0xd9,0x35,0x42,0xf3,0xd7,0xa7,0x43,0x08,0x12,0x61,0x2e,0x42,0xb0,0x42,
2233 0xac,0x43,0x63,0xff,0x36,0x42,0xdd,0x74,0xaf,0x43,0x1e,0xa6,0x45,0x42,0x44,0x82,0xb2,0x43,0x08,0x74,
2234 0x1b,0x4b,0x42,0x79,0x7a,0xb3,0x43,0x10,0x21,0x4f,0x42,0x2a,0x18,0xb5,0x43,0xdb,0x4c,0x54,0x42,0x91,
2235 0x19,0xb6,0x43,0x08,0xee,0x3f,0x65,0x42,0x5f,0x28,0xba,0x43,0xa7,0xaf,0x66,0x42,0xb9,0x50,0xb6,0x43,
2236 0x14,0x58,0x5c,0x42,0xca,0xdc,0xb1,0x43,0x08,0x2c,0x8b,0x4c,0x42,0x4e,0x30,0xac,0x43,0x19,0xcf,0x48,
2237 0x42,0x2a,0xd0,0xa8,0x43,0xbc,0xab,0x49,0x42,0xa9,0x4c,0xa6,0x43,0x08,0x61,0x5f,0x47,0x42,0xfa,0xa2,
2238 0xa2,0x43,0xa7,0xaf,0x66,0x42,0x85,0x98,0x94,0x43,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x07,0x2a,
2239 0xf4,0x2e,0x42,0x04,0x21,0x94,0x43,0x09,0x06,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x08,0xdc,0xe3,
2240 0xf1,0x41,0xe9,0x9e,0x92,0x43,0xd2,0xe7,0x0b,0x42,0xd6,0x06,0x95,0x43,0x2a,0xf4,0x2e,0x42,0x04,0x21,
2241 0x94,0x43,0x07,0x2a,0xf4,0x2e,0x42,0xc3,0x62,0x95,0x43,0x08,0x87,0x17,0x2e,0x42,0xc3,0x62,0x95,0x43,
2242 0xe7,0x3a,0x2d,0x42,0xf5,0x6b,0x95,0x43,0x44,0x5e,0x2c,0x42,0xf5,0x6b,0x95,0x43,0x08,0xd1,0x47,0x1c,
2243 0x42,0x19,0xc0,0x96,0x43,0x66,0xdf,0x05,0x42,0x38,0x19,0x95,0x43,0x12,0x6a,0x00,0x42,0xb2,0xbe,0x95,
2244 0x43,0x08,0xbb,0x6b,0xea,0x41,0xd6,0x12,0x97,0x43,0x2d,0x82,0xfa,0x41,0x61,0x74,0x9b,0x43,0x7e,0x72,
2245 0x06,0x42,0x8a,0xab,0x9b,0x43,0x08,0xc8,0x39,0x12,0x42,0x4e,0xd0,0x9b,0x43,0x53,0xe3,0x22,0x42,0xc3,
2246 0x86,0x9b,0x43,0x2a,0xf4,0x2e,0x42,0x57,0xa2,0x9b,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6a,0x52,0x9d,0x43,
2247 0x08,0x01,0xa5,0x2a,0x42,0xa4,0x2d,0x9d,0x43,0x96,0x9c,0x24,0x42,0x06,0x40,0x9d,0x43,0x8a,0xb7,0x1d,
2248 0x42,0x9a,0x5b,0x9d,0x43,0x08,0x6b,0x16,0x13,0x42,0xcd,0x64,0x9d,0x43,0x42,0xc7,0x0e,0x42,0x9a,0x5b,
2249 0x9d,0x43,0x23,0x26,0x04,0x42,0xcd,0x64,0x9d,0x43,0x08,0xe6,0x91,0xeb,0x41,0x38,0x49,0x9d,0x43,0x73,
2250 0x7b,0xdb,0x41,0xf5,0x83,0x99,0x43,0x7f,0x60,0xe2,0x41,0x0b,0x0b,0x98,0x43,0x08,0x7f,0x60,0xe2,0x41,
2251 0xec,0x99,0x95,0x43,0xe3,0x5a,0xde,0x41,0xbe,0x7f,0x96,0x43,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,
2252 0x07,0xd0,0xfe,0xea,0x41,0x9f,0x0e,0x94,0x43,0x09,0x06,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x08,
2253 0xd4,0x7e,0x29,0x42,0xab,0x6b,0xaf,0x43,0x4e,0x0c,0x26,0x42,0x44,0x6a,0xae,0x43,0x38,0x79,0x25,0x42,
2254 0xd4,0x96,0xad,0x43,0x08,0x25,0xbd,0x21,0x42,0xe2,0x4b,0xac,0x43,0x49,0x35,0x29,0x42,0x9a,0x97,0xa7,
2255 0x43,0x2a,0xf4,0x2e,0x42,0x61,0xa4,0xa3,0x43,0x07,0x2a,0xf4,0x2e,0x42,0x6d,0xad,0xb0,0x43,0x09,0x06,
2256 0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x08,0x86,0x20,0x80,0x43,0x57,0x41,0xe6,0x43,0x7d,0x4e,0x80,
2257 0x43,0x25,0x38,0xe6,0x43,0xa5,0x85,0x80,0x43,0xf3,0x2e,0xe6,0x43,0x08,0x35,0xca,0x83,0x43,0xd4,0xc9,
2258 0xe5,0x43,0x9c,0xd7,0x86,0x43,0x44,0x91,0xe4,0x43,0xd5,0xca,0x8a,0x43,0x91,0x1c,0xe6,0x43,0x08,0x53,
2259 0x5f,0x8c,0x43,0xf8,0x1d,0xe7,0x43,0x2f,0x17,0x8d,0x43,0x4e,0x7b,0xe8,0x43,0x92,0x29,0x8d,0x43,0x2f,
2260 0x22,0xea,0x43,0x07,0x92,0x29,0x8d,0x43,0x44,0xb5,0xea,0x43,0x08,0xfe,0x0d,0x8d,0x43,0x2a,0x4b,0xed,
2261 0x43,0xe3,0x8b,0x8b,0x43,0x55,0x7d,0xf0,0x43,0xec,0x51,0x89,0x43,0x72,0x0b,0xf4,0x43,0x08,0xcd,0xd4,
2262 0x84,0x43,0x9d,0x55,0xfb,0x43,0xc9,0xe5,0x83,0x43,0x74,0x1e,0xfb,0x43,0x73,0x94,0x84,0x43,0x5a,0x90,
2263 0xf7,0x43,0x08,0xe8,0x62,0x88,0x43,0xfd,0x30,0xee,0x43,0x39,0xc5,0x86,0x43,0xdd,0xbf,0xeb,0x43,0x35,
2264 0xbe,0x81,0x43,0x40,0xde,0xed,0x43,0x08,0x4f,0x34,0x81,0x43,0x36,0x0c,0xee,0x43,0x08,0x98,0x80,0x43,
2265 0xfd,0x30,0xee,0x43,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x40,0xec,
2266 0x43,0x08,0x35,0xbe,0x81,0x43,0x06,0xf7,0xeb,0x43,0x15,0x65,0x83,0x43,0x49,0xa4,0xeb,0x43,0x1e,0x43,
2267 0x85,0x43,0xbe,0x5a,0xeb,0x43,0x08,0xae,0x93,0x8a,0x43,0xfd,0x18,0xea,0x43,0x42,0x97,0x86,0x43,0x5f,
2268 0x67,0xf4,0x43,0xa9,0x98,0x87,0x43,0xd4,0x1d,0xf4,0x43,0x08,0x5c,0x25,0x8a,0x43,0xcf,0x16,0xef,0x43,
2269 0x46,0xaa,0x8d,0x43,0x5a,0x3c,0xe9,0x43,0x19,0x6c,0x88,0x43,0x53,0x5e,0xe7,0x43,0x08,0xc4,0x02,0x85,
2270 0x43,0x96,0x0b,0xe7,0x43,0x85,0x2c,0x82,0x43,0x83,0x67,0xe7,0x43,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,
2271 0x43,0x07,0x1d,0xe5,0x7f,0x43,0x87,0x4a,0xe6,0x43,0x09,0x06,0xfd,0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,
2272 0x08,0xfa,0x6c,0x78,0x43,0xd1,0xc2,0xe0,0x43,0x25,0x5c,0x6c,0x43,0x25,0x44,0xe8,0x43,0x1d,0xe5,0x7f,
2273 0x43,0x87,0x4a,0xe6,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x72,0xc3,0xe7,0x43,0x08,0xa6,0x27,0x7b,0x43,0x91,
2274 0x28,0xe8,0x43,0xbc,0xa2,0x77,0x43,0xb0,0x8d,0xe8,0x43,0xc6,0x68,0x75,0x43,0x57,0x4d,0xe8,0x43,0x08,
2275 0xe0,0xd2,0x72,0x43,0xab,0x9e,0xe7,0x43,0x50,0x9a,0x71,0x43,0x2a,0x27,0xe7,0x43,0xea,0x98,0x70,0x43,
2276 0x57,0x35,0xe4,0x43,0x08,0x94,0x3b,0x6f,0x43,0x14,0x7c,0xe2,0x43,0xff,0x13,0x6d,0x43,0x06,0xbb,0xe1,
2277 0x43,0xcf,0xfe,0x6a,0x43,0x06,0xbb,0xe1,0x43,0x08,0x44,0x9d,0x66,0x43,0x77,0x8e,0xe2,0x43,0x3b,0xef,
2278 0x6c,0x43,0x91,0x10,0xe4,0x43,0xfd,0x24,0x6c,0x43,0xb0,0x81,0xe6,0x43,0x08,0x96,0x23,0x6b,0x43,0xee,
2279 0x57,0xe9,0x43,0xca,0x0f,0x6a,0x43,0x5f,0x37,0xec,0x43,0x55,0x71,0x6e,0x43,0x9f,0x01,0xed,0x43,0x08,
2280 0xdb,0xfb,0x75,0x43,0x3b,0xef,0xec,0x43,0x09,0x3a,0x7b,0x43,0xb0,0xa5,0xec,0x43,0x1d,0xe5,0x7f,0x43,
2281 0x91,0x40,0xec,0x43,0x07,0x1d,0xe5,0x7f,0x43,0x91,0x4c,0xee,0x43,0x08,0xa9,0x16,0x7c,0x43,0xb0,0xb1,
2282 0xee,0x43,0x47,0xec,0x77,0x43,0xd9,0xe8,0xee,0x43,0x1e,0x9d,0x73,0x43,0xcf,0x16,0xef,0x43,0x08,0x0e,
2283 0xc9,0x6b,0x43,0xee,0x7b,0xef,0x43,0x7e,0x90,0x6a,0x43,0xfd,0x30,0xee,0x43,0x01,0xfc,0x68,0x43,0x4e,
2284 0x93,0xec,0x43,0x08,0x31,0xf9,0x66,0x43,0x4e,0x87,0xea,0x43,0x31,0x11,0x6b,0x43,0xd4,0xd5,0xe7,0x43,
2285 0xd9,0xc4,0x68,0x43,0xd4,0xc9,0xe5,0x43,0x08,0xe5,0x79,0x67,0x43,0x77,0x9a,0xe4,0x43,0x44,0x9d,0x66,
2286 0x43,0xab,0x86,0xe3,0x43,0x7e,0x78,0x66,0x43,0x0b,0xaa,0xe2,0x43,0x07,0x7e,0x78,0x66,0x43,0x57,0x29,
2287 0xe2,0x43,0x08,0xa7,0xaf,0x66,0x43,0xbe,0x1e,0xe1,0x43,0x87,0x56,0x68,0x43,0x77,0x82,0xe0,0x43,0xfd,
2288 0x24,0x6c,0x43,0xd9,0x94,0xe0,0x43,0x09,0x06,0xc4,0x41,0xbf,0x43,0x85,0xc0,0x72,0x42,0x08,0x73,0xdf,
2289 0xc0,0x43,0xf4,0x76,0x72,0x42,0x97,0x33,0xc2,0x43,0x85,0xc0,0x72,0x42,0xb2,0xb5,0xc3,0x43,0x64,0x56,
2290 0x75,0x42,0x08,0x03,0x24,0xc4,0x43,0x5e,0x7f,0x78,0x42,0xfa,0x51,0xc4,0x43,0x01,0x85,0x7c,0x42,0x5c,
2291 0x64,0xc4,0x43,0xa0,0xb3,0x80,0x42,0x07,0x5c,0x64,0xc4,0x43,0x10,0x93,0x83,0x42,0x08,0xc8,0x48,0xc4,
2292 0x43,0x1c,0x78,0x8a,0x42,0x27,0x6c,0xc3,0x43,0xaf,0xcf,0x94,0x42,0x23,0x7d,0xc2,0x43,0x99,0x9c,0xa4,
2293 0x42,0x08,0x3d,0xe7,0xbf,0x43,0xfb,0xfd,0xb5,0x42,0xb3,0x9d,0xbf,0x43,0x88,0x17,0xae,0x42,0xc4,0x41,
2294 0xbf,0x43,0x69,0x76,0xa3,0x42,0x07,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x08,0x4f,0x8b,0xbf,0x43,
2295 0xed,0x81,0x91,0x42,0xe4,0xa6,0xbf,0x43,0x5d,0x61,0x94,0x42,0xfa,0x39,0xc0,0x43,0x3b,0x49,0x9d,0x42,
2296 0x08,0x2b,0x43,0xc0,0x43,0x28,0xed,0xa9,0x42,0x61,0x3b,0xc1,0x43,0x00,0x9e,0xa5,0x42,0xe4,0xb2,0xc1,
2297 0x43,0x5d,0x91,0x9c,0x42,0x08,0x78,0xce,0xc1,0x43,0xfd,0x36,0x90,0x42,0x22,0x89,0xc4,0x43,0x81,0x72,
2298 0x86,0x42,0xae,0xc6,0xc2,0x43,0xa0,0xb3,0x80,0x42,0x08,0x54,0x86,0xc2,0x43,0x58,0xd1,0x7e,0x42,0x30,
2299 0x32,0xc1,0x43,0xce,0x5e,0x7b,0x42,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x07,0xc4,0x41,0xbf,0x43,
2300 0x85,0xc0,0x72,0x42,0x09,0x06,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x08,0x35,0xfd,0xbb,0x43,0xa4,
2301 0xa1,0x5c,0x42,0x5e,0x34,0xbc,0x43,0x9d,0x2a,0x70,0x42,0x5e,0x40,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,
2302 0x4c,0x9c,0xbe,0x43,0x0e,0x0a,0x73,0x42,0x08,0xef,0xbe,0x43,0x0e,0x0a,0x73,0x42,0xc4,0x41,0xbf,0x43,
2303 0x85,0xc0,0x72,0x42,0x07,0xc4,0x41,0xbf,0x43,0xe8,0xf1,0x7b,0x42,0x08,0xcd,0x13,0xbf,0x43,0xe8,0xf1,
2304 0x7b,0x42,0xd6,0xe5,0xbe,0x43,0x71,0x3b,0x7c,0x42,0xdf,0xb7,0xbe,0x43,0x71,0x3b,0x7c,0x42,0x08,0x08,
2305 0xe3,0xbc,0x43,0xa4,0x61,0x7d,0x42,0x28,0x3c,0xbb,0x43,0x91,0x45,0x69,0x42,0x28,0x3c,0xbb,0x43,0x58,
2306 0x71,0x6e,0x42,0x08,0xce,0xfb,0xba,0x43,0xd5,0x35,0x78,0x42,0x59,0x45,0xbb,0x43,0x58,0x23,0x82,0x42,
2307 0xa1,0xe1,0xbb,0x43,0xd7,0xbe,0x88,0x42,0x08,0xc9,0x18,0xbc,0x43,0xaf,0x9f,0x8c,0x42,0x1e,0x76,0xbd,
2308 0x43,0x51,0x7c,0x8d,0x42,0xd6,0xe5,0xbe,0x43,0xf4,0x58,0x8e,0x42,0x08,0x9c,0x0a,0xbf,0x43,0x45,0xc7,
2309 0x8e,0x42,0x30,0x26,0xbf,0x43,0x96,0x35,0x8f,0x42,0xc4,0x41,0xbf,0x43,0xac,0xc8,0x8f,0x42,0x07,0xc4,
2310 0x41,0xbf,0x43,0x69,0x76,0xa3,0x42,0x08,0x08,0xef,0xbe,0x43,0xb1,0xd6,0x99,0x42,0xe8,0x89,0xbe,0x43,
2311 0xde,0xc5,0x8d,0x42,0xc0,0x46,0xbc,0x43,0xc2,0x5b,0x90,0x42,0x08,0x9c,0xf2,0xba,0x43,0x86,0x80,0x90,
2312 0x42,0xf2,0x43,0xba,0x43,0xe8,0x73,0x87,0x42,0x8f,0x31,0xba,0x43,0xb6,0xf4,0x7d,0x42,0x07,0x8f,0x31,
2313 0xba,0x43,0x21,0xc6,0x76,0x42,0x08,0xc0,0x3a,0xba,0x43,0x5f,0x48,0x6b,0x42,0xae,0x96,0xba,0x43,0xe3,
2314 0x83,0x61,0x42,0xf6,0x32,0xbb,0x43,0x40,0xa7,0x60,0x42,0x09,0x06,0xea,0x74,0xea,0x43,0x61,0x44,0x93,
2315 0x43,0x08,0x24,0x5c,0xec,0x43,0x31,0x3b,0x93,0x43,0xfb,0x30,0xee,0x43,0x93,0x4d,0x93,0x43,0x0d,0xe1,
2316 0xef,0x43,0x80,0xa9,0x93,0x43,0x08,0x8f,0x58,0xf0,0x43,0xd1,0x17,0x94,0x43,0xb7,0x8f,0xf0,0x43,0x10,
2317 0xe2,0x94,0x43,0xea,0x98,0xf0,0x43,0xa9,0xec,0x95,0x43,0x07,0xea,0x98,0xf0,0x43,0x38,0x25,0x97,0x43,
2318 0x08,0x23,0x74,0xf0,0x43,0x9f,0x32,0x9a,0x43,0x5a,0x60,0xef,0x43,0x53,0xcb,0x9e,0x43,0x2d,0x3a,0xee,
2319 0x43,0xfd,0x91,0xa3,0x43,0x08,0xa2,0xf0,0xed,0x43,0xdd,0x38,0xa5,0x43,0x17,0xa7,0xed,0x43,0xbe,0xdf,
2320 0xa6,0x43,0x5a,0x54,0xed,0x43,0x9f,0x86,0xa8,0x43,0x08,0xfc,0x24,0xec,0x43,0xca,0xc4,0xad,0x43,0x48,
2321 0xa4,0xeb,0x43,0x40,0x6f,0xab,0x43,0x28,0x3f,0xeb,0x43,0x1c,0x0f,0xa8,0x43,0x08,0x1f,0x6d,0xeb,0x43,
2322 0x72,0x48,0xa3,0x43,0x67,0x09,0xec,0x43,0xd1,0x53,0x9e,0x43,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,0x43,
2323 0x07,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x08,0x7e,0x90,0xea,0x43,0x8a,0x9f,0x99,0x43,0x12,0xac,
2324 0xea,0x43,0xbc,0xa8,0x99,0x43,0xa7,0xc7,0xea,0x43,0xbc,0xa8,0x99,0x43,0x08,0x51,0x76,0xeb,0x43,0x9f,
2325 0x32,0x9a,0x43,0x5e,0x37,0xec,0x43,0x49,0xed,0x9c,0x43,0xb0,0xa5,0xec,0x43,0x2a,0xa0,0xa0,0x43,0x08,
2326 0x09,0xe6,0xec,0x43,0xd1,0x77,0xa4,0x43,0x28,0x4b,0xed,0x43,0x61,0xa4,0xa3,0x43,0xab,0xc2,0xed,0x43,
2327 0x8e,0xb2,0xa0,0x43,0x08,0x70,0xe7,0xed,0x43,0xde,0x08,0x9d,0x43,0x87,0x86,0xf0,0x43,0x2f,0x53,0x97,
2328 0x43,0x87,0x7a,0xee,0x43,0xec,0x99,0x95,0x43,0x08,0xca,0x27,0xee,0x43,0xff,0x3d,0x95,0x43,0x74,0xca,
2329 0xec,0x43,0x55,0x8f,0x94,0x43,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x07,0xea,0x74,0xea,0x43,0x61,
2330 0x44,0x93,0x43,0x09,0x06,0x05,0xd3,0xe5,0x43,0x19,0x9c,0x90,0x43,0x08,0x09,0xc2,0xe6,0x43,0xd1,0xff,
2331 0x8f,0x43,0x4d,0x6f,0xe6,0x43,0x74,0xe8,0x92,0x43,0x3b,0xd7,0xe8,0x43,0xc3,0x56,0x93,0x43,0x08,0x1f,
2332 0x61,0xe9,0x43,0x93,0x4d,0x93,0x43,0x05,0xeb,0xe9,0x43,0x93,0x4d,0x93,0x43,0xea,0x74,0xea,0x43,0x61,
2333 0x44,0x93,0x43,0x07,0xea,0x74,0xea,0x43,0xe7,0xaa,0x94,0x43,0x08,0x24,0x50,0xea,0x43,0xe7,0xaa,0x94,
2334 0x43,0x2d,0x22,0xea,0x43,0xe7,0xaa,0x94,0x43,0x36,0xf4,0xe9,0x43,0xe7,0xaa,0x94,0x43,0x08,0xa2,0xcc,
2335 0xe7,0x43,0xe0,0xd8,0x94,0x43,0xd4,0xc9,0xe5,0x43,0x19,0xa8,0x92,0x43,0xd4,0xc9,0xe5,0x43,0x27,0x69,
2336 0x93,0x43,0x08,0x17,0x77,0xe5,0x43,0xe0,0xd8,0x94,0x43,0x67,0xe5,0xe5,0x43,0x47,0xda,0x95,0x43,0x43,
2337 0x9d,0xe6,0x43,0xe2,0xd3,0x97,0x43,0x08,0x9d,0xdd,0xe6,0x43,0xad,0xe7,0x98,0x43,0x09,0xce,0xe8,0x43,
2338 0xff,0x55,0x99,0x43,0xea,0x74,0xea,0x43,0x8a,0x9f,0x99,0x43,0x07,0xea,0x74,0xea,0x43,0x1e,0xc7,0x9b,
2339 0x43,0x08,0x71,0xcf,0xe9,0x43,0x53,0xb3,0x9a,0x43,0xa7,0xbb,0xe8,0x43,0xdb,0x0d,0x9a,0x43,0xc6,0x14,
2340 0xe7,0x43,0xdb,0x0d,0x9a,0x43,0x08,0x48,0x80,0xe5,0x43,0xdb,0x0d,0x9a,0x43,0x0a,0xb6,0xe4,0x43,0xc3,
2341 0x6e,0x97,0x43,0x76,0x9a,0xe4,0x43,0x74,0xf4,0x94,0x43,0x07,0x76,0x9a,0xe4,0x43,0x79,0xd7,0x93,0x43,
2342 0x08,0xd8,0xac,0xe4,0x43,0x66,0x27,0x92,0x43,0x29,0x1b,0xe5,0x43,0xe0,0xc0,0x90,0x43,0x05,0xd3,0xe5,
2343 0x43,0x19,0x9c,0x90,0x43,0x09,0x06,0x1b,0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x08,0x71,0x0b,0xf4,0x42,
2344 0x00,0x0e,0x8d,0x42,0x8c,0x0f,0x01,0x43,0x3e,0xc0,0x89,0x42,0xf3,0x28,0x06,0x43,0x48,0x9e,0x8b,0x42,
2345 0x08,0x15,0x89,0x09,0x43,0x00,0x0e,0x8d,0x42,0xe0,0x9c,0x0a,0x43,0xc1,0x8b,0x98,0x42,0xa6,0xc1,0x0a,
2346 0x43,0x02,0xa5,0xaa,0x42,0x07,0xa6,0xc1,0x0a,0x43,0xf9,0xf6,0xb0,0x42,0x08,0xa6,0xc1,0x0a,0x43,0x47,
2347 0x8e,0xb4,0x42,0x42,0xaf,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0xe0,0x9c,0x0a,0x43,0xba,0x74,0xbc,0x42,0x08,
2348 0xa1,0xd2,0x09,0x43,0x40,0x47,0xd0,0x42,0x0d,0xab,0x07,0x43,0x91,0xb5,0xd0,0x42,0x3b,0xb9,0x04,0x43,
2349 0xec,0x71,0xba,0x42,0x08,0xe5,0x5b,0x03,0x43,0xe3,0x33,0xa8,0x42,0x63,0xd8,0x00,0x43,0xce,0x70,0x9f,
2350 0x42,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x07,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,0x42,0x08,0xed,
2351 0x6f,0xed,0x42,0x73,0x24,0x9d,0x42,0xd8,0x0c,0xf5,0x42,0x99,0x6c,0x9c,0x42,0x27,0xab,0xfd,0x42,0xea,
2352 0xda,0x9c,0x42,0x08,0x36,0xca,0x03,0x43,0x2b,0x94,0x9e,0x42,0x68,0xc7,0x01,0x43,0x8f,0xbe,0xa2,0x42,
2353 0xfa,0x06,0x08,0x43,0x73,0xb4,0xb5,0x42,0x08,0x8e,0x2e,0x0a,0x43,0x1f,0x6f,0xb8,0x42,0x9d,0xe3,0x08,
2354 0x43,0xd7,0x1e,0x99,0x42,0x28,0x15,0x05,0x43,0x32,0x3b,0x93,0x42,0x08,0x63,0xf0,0x04,0x43,0x70,0xed,
2355 0x8f,0x42,0x71,0x0b,0xf4,0x42,0x32,0x3b,0x93,0x42,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x07,0x1b,
2356 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x09,0x06,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,0x08,0x8e,0x55,
2357 0xc0,0x42,0xb8,0x4d,0x86,0x42,0x60,0xbf,0xd7,0x42,0x3e,0xf0,0x91,0x42,0x63,0xf6,0xe4,0x42,0x70,0xed,
2358 0x8f,0x42,0x08,0x7a,0x89,0xe5,0x42,0xac,0xc8,0x8f,0x42,0xcc,0xf7,0xe5,0x42,0xac,0xc8,0x8f,0x42,0x1b,
2359 0x66,0xe6,0x42,0xe3,0xa3,0x8f,0x42,0x07,0x1b,0x66,0xe6,0x42,0x73,0xf4,0x94,0x42,0x08,0x63,0xf6,0xe4,
2360 0x42,0x3b,0x19,0x95,0x42,0xe6,0x61,0xe3,0x42,0x00,0x3e,0x95,0x42,0xf4,0x16,0xe2,0x42,0xc4,0x62,0x95,
2361 0x42,0x08,0x6e,0x74,0xd6,0x42,0x15,0xd1,0x95,0x42,0x97,0x63,0xca,0x42,0xaf,0xcf,0x94,0x42,0xfb,0x2d,
2362 0xbe,0x42,0x86,0x80,0x90,0x42,0x08,0x97,0x03,0xba,0x42,0xce,0x10,0x8f,0x42,0x5e,0x28,0xba,0x42,0x3e,
2363 0xf0,0x91,0x42,0xf2,0x4f,0xbc,0x42,0x45,0xf7,0x96,0x42,0x08,0x27,0x54,0xbf,0x42,0x73,0x24,0x9d,0x42,
2364 0xa5,0xe8,0xc0,0x42,0x86,0xe0,0xa0,0x42,0xe4,0xca,0xc5,0x42,0xed,0x11,0xaa,0x42,0x08,0x54,0xaa,0xc8,
2365 0x42,0x86,0x40,0xb1,0x42,0x59,0x81,0xc5,0x42,0xa1,0x11,0xc4,0x42,0x3e,0xe7,0xbf,0x42,0xfb,0x8d,0xce,
2366 0x42,0x08,0xb4,0x6d,0xb7,0x42,0x30,0xc2,0xd9,0x42,0x46,0xf5,0xc9,0x42,0xdf,0x53,0xd9,0x42,0x38,0x40,
2367 0xcb,0x42,0x62,0x8f,0xcf,0x42,0x08,0x7d,0xf9,0xcc,0x42,0xec,0xa1,0xc2,0x42,0x07,0x43,0xcd,0x42,0x6c,
2368 0xdd,0xb8,0x42,0x2b,0x8b,0xcc,0x42,0x92,0xf5,0xaf,0x42,0x08,0xf9,0x8d,0xce,0x42,0x41,0x57,0xa7,0x42,
2369 0x5b,0xb8,0xd2,0x42,0xae,0x2f,0xa5,0x42,0x18,0x2f,0xd9,0x42,0x13,0x2a,0xa1,0x42,0x08,0x41,0x7e,0xdd,
2370 0x42,0xe3,0x03,0xa0,0x42,0x2e,0xf2,0xe1,0x42,0x7c,0x02,0x9f,0x42,0x1b,0x66,0xe6,0x42,0xa2,0x4a,0x9e,
2371 0x42,0x07,0x1b,0x66,0xe6,0x42,0xae,0x2f,0xa5,0x42,0x08,0x4d,0x63,0xe4,0x42,0x00,0x9e,0xa5,0x42,0xf4,
2372 0x16,0xe2,0x42,0x15,0x31,0xa6,0x42,0x99,0xca,0xdf,0x42,0x2b,0xc4,0xa6,0x42,0x08,0xc0,0x82,0xc6,0x42,
2373 0xc4,0xc2,0xa5,0x42,0x57,0xe1,0xd5,0x42,0x91,0xb5,0xd0,0x42,0x54,0xda,0xd0,0x42,0x97,0x93,0xd2,0x42,
2374 0x08,0x9c,0x3a,0xc7,0x42,0x17,0x58,0xdc,0x42,0x9c,0x0a,0xbf,0x42,0x6e,0xa4,0xde,0x42,0x90,0x25,0xb8,
2375 0x42,0xdf,0x53,0xd9,0x42,0x08,0x59,0x21,0xb5,0x42,0xf2,0xdf,0xd4,0x42,0x51,0x43,0xb3,0x42,0x91,0xb5,
2376 0xd0,0x42,0xc5,0x29,0xbb,0x42,0x0e,0x1a,0xca,0x42,0x08,0x65,0x36,0xc4,0x42,0xd0,0x07,0xbd,0x42,0x3e,
2377 0xe7,0xbf,0x42,0x37,0x09,0xbe,0x42,0x0c,0xea,0xc1,0x42,0xcd,0xd0,0xaf,0x42,0x08,0x2b,0x5b,0xc4,0x42,
2378 0x18,0x08,0xa3,0x42,0x67,0xa6,0xab,0x42,0x99,0x3c,0x94,0x42,0x5e,0x28,0xba,0x42,0x35,0xe2,0x87,0x42,
2383 //----------------------------------------------------------------------------
2384 // Anti-Grain Geometry (AGG) - Version 2.5
2385 // A high quality rendering engine for C++
2386 // Copyright (C) 2002-2006 Maxim Shemanarev
2387 // Contact: mcseem@antigrain.com
2388 // mcseemagg@yahoo.com
2389 // http://antigrain.com
2391 // AGG is free software; you can redistribute it and/or
2392 // modify it under the terms of the GNU General Public License
2393 // as published by the Free Software Foundation; either version 2
2394 // of the License, or (at your option) any later version.
2396 // AGG is distributed in the hope that it will be useful,
2397 // but WITHOUT ANY WARRANTY; without even the implied warranty of
2398 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2399 // GNU General Public License for more details.
2401 // You should have received a copy of the GNU General Public License
2402 // along with AGG; if not, write to the Free Software
2403 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
2404 // MA 02110-1301, USA.
2405 //----------------------------------------------------------------------------
2406 private nothrow @trusted @nogc:
2409 enum PathCommand
: ubyte {
2417 enum PathFlag
: ubyte {
2426 bool isVertex (in uint c
) pure { pragma(inline
, true); return (c
>= PathCommand
.MoveTo
&& c
< PathCommand
.EndPoly
); }
2427 bool isDrawing (in uint c
) pure { pragma(inline
, true); return (c
>= PathCommand
.LineTo
&& c
< PathCommand
.EndPoly
); }
2428 bool isStop (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.Stop
); }
2429 bool isMoveTo (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.MoveTo
); }
2430 bool isLineTo (in uint c
) pure { pragma(inline
, true); return (c
== PathCommand
.LineTo
); }
2431 bool isEndPoly (in uint c
) pure { pragma(inline
, true); return ((c
&PathCommand
.Mask
) == PathCommand
.EndPoly
); }
2432 bool isClose (in uint c
) pure { pragma(inline
, true); return (c
&~cast(uint)(PathFlag
.CW|PathFlag
.CCW
)) == (PathCommand
.EndPoly|PathFlag
.Close
); }
2433 bool isCW (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.CW
) != 0); }
2434 bool isCCW (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.CCW
) != 0); }
2435 bool isOriented (in uint c
) pure { pragma(inline
, true); return ((c
&(PathFlag
.CW|PathFlag
.CCW
)) != 0); }
2436 bool isClosed (in uint c
) pure { pragma(inline
, true); return ((c
&PathFlag
.Close
) != 0); }
2437 uint getCloseFlag (in uint c
) pure { pragma(inline
, true); return (c
&PathFlag
.Close
); }
2438 uint clearOrientation (in uint c
) pure { pragma(inline
, true); return (c
&~cast(uint)(PathFlag
.CW|PathFlag
.CCW
)); }
2439 uint getOrientation (in uint c
) pure { pragma(inline
, true); return (c
&(PathFlag
.CW|PathFlag
.CCW
)); }
2440 uint setOrientation (in uint c
, uint o
) pure { pragma(inline
, true); return (clearOrientation(c
)|o
); }
2442 //enum PI = 3.14159265358979323846;
2443 //enum DBL_PI = cast(double)(0x1.921fb54442d18p+1);
2444 enum FLT_PI
= cast(float)(0x1.921fb54442d18p
+1);
2446 enum DEG2RAD_MULT_D
= cast(double)(0x1.1df46a
2529d39p
-6);
2447 enum RAD2DEG_MULT_D
= cast(double)(0x1.ca5dc1a63c1f8p
+5);
2449 enum DEG2RAD_MULT_F
= cast(float)(0x1.1df46ap
-6f);
2450 enum RAD2DEG_MULT_F
= cast(float)(0x1.ca5dc2p
+5f);
2452 //float deg2rad (in float deg) pure nothrow @safe @nogc { pragma(inline, true); return deg*cast(float)(PI/180.0f); }
2453 //float rad2deg (in float rad) pure nothrow @safe @nogc { pragma(inline, true); return rad*cast(float)(180.0f/PI); }
2454 public T
deg2rad(T
) (in T deg
) if (__traits(isFloating
, T
) && (T
.sizeof
== 4 || T
.sizeof
== 8)) {
2455 pragma(inline
, true);
2456 static if (T
.sizeof
== 4) {
2457 return deg
*DEG2RAD_MULT_F
;
2459 return deg
*DEG2RAD_MULT_D
;
2463 public T
rad2deg(T
) (in T rad
) if (__traits(isFloating
, T
) && (T
.sizeof
== 4 || T
.sizeof
== 8)) {
2464 pragma(inline
, true);
2465 static if (T
.sizeof
== 4) {
2466 return rad
*RAD2DEG_MULT_F
;
2468 return rad
*RAD2DEG_MULT_D
;
2473 float calcPolygonArea(Storage
) (in ref Storage st
) {
2479 foreach (immutable uint i
; 1..st
.length
) {
2485 return (sum
+x
*ys
-y
*xs
)*0.5f;
2489 void shortenPath(VertexSequence
) (ref VertexSequence vs
, float s
, in uint closed
=0) {
2490 alias VertexType
= VertexSequence
.ValueType
;
2491 if (s
> 0 && vs
.length
> 1) {
2493 int n
= cast(int)(vs
.length
-2);
2495 immutable float d
= vs
[n
].dist
;
2501 if (vs
.length
< 2) {
2505 VertexType
* prev
= &vs
[n
-1];
2506 VertexType
* last
= &vs
[n
];
2507 immutable float d
= (prev
.dist
-s
)/prev
.dist
;
2508 immutable float x
= prev
.x
+(last
.x
-prev
.x
)*d
;
2509 immutable float y
= prev
.y
+(last
.y
-prev
.y
)*d
;
2512 if (!(*prev
)(*last
)) vs
.removeLast();
2513 vs
.close(closed
!= 0);
2519 // ////////////////////////////////////////////////////////////////////////// //
2520 // Vertex (x, y) with the distance to the next one. The last vertex has
2521 // distance between the last and the first points if the polygon is closed
2522 // and 0.0 if it's a polyline.
2524 public nothrow @trusted @nogc:
2529 this (in float ax
, in float ay
) pure { x
= ax
; y
= ay
; /*dist = 0.0f;*/ }
2531 bool opCall() (in auto ref VertexDist val
) {
2532 //enum VertexDistEPS = cast(double)1e-14; // Coinciding points maximal distance (Epsilon)
2533 enum VertexDistEPS
= cast(float)0.00001f; // Coinciding points maximal distance (Epsilon)
2534 immutable bool ret = (dist
= distance(x
, y
, val
.x
, val
.y
)) > VertexDistEPS
;
2535 if (!ret) dist
= 1.0f/VertexDistEPS
;
2541 // ////////////////////////////////////////////////////////////////////////// //
2542 struct SimpleVector(T
) {
2543 public nothrow @trusted @nogc:
2544 alias ValueType
= T
;
2546 uint pvecAllot
, pvecSize
;
2548 mixin(DisableCopyingMixin
);
2551 import core
.stdc
.stdlib
: free
;
2552 if (pvec
!is null) free(pvec
);
2554 pvecAllot
= pvecSize
= 0;
2557 @property uint length () const pure { pragma(inline
, true); return pvecSize
; }
2559 ref inout(T
) opIndex (in uint idx
) inout pure { pragma(inline
, true);return pvec
[idx
]; }
2561 ref inout(T
) curr (in uint idx
) inout pure { pragma(inline
, true);return pvec
[idx
]; }
2562 ref inout(T
) prev (in uint idx
) inout pure { pragma(inline
, true);return pvec
[(idx
+pvecSize
-1)%pvecSize
]; }
2563 ref inout(T
) next (in uint idx
) inout pure { pragma(inline
, true);return pvec
[(idx
+1)%pvecSize
]; }
2566 pragma(inline
, true);
2570 void removeLast () {
2571 pragma(inline
, true);
2572 if (pvecSize
> 0 ) --pvecSize
;
2575 void add() (in auto ref T val
) {
2576 import core
.stdc
.stdlib
: realloc
;
2577 import core
.stdc
.string
: memcpy
;
2578 if (pvecSize
+1 > pvecAllot
) {
2579 uint newsz
= (pvecAllot|
0xff)+1;
2580 pvec
= cast(T
*)realloc(pvec
, T
.sizeof
*newsz
);
2581 if (pvec
is null) assert(0, "out of memory");
2584 assert(pvecSize
< pvecAllot
);
2585 memcpy(pvec
+pvecSize
, &val
, T
.sizeof
);
2591 // ////////////////////////////////////////////////////////////////////////// //
2592 struct VertexSequence(T
) {
2593 public nothrow @trusted @nogc:
2596 alias ValueType
= T
;
2598 mixin(DisableCopyingMixin
);
2600 void add() (in auto ref T val
) {
2601 import core
.stdc
.stdlib
: realloc
;
2602 import core
.stdc
.string
: memcpy
;
2604 if (!pvec
[pvecSize
-2](pvec
[pvecSize
-1])) removeLast();
2609 void modifyLast() (in auto ref T val
) {
2610 if (pvecSize
> 0) removeLast();
2614 // closed aka remove_flag
2615 void close (in bool closed
) {
2616 while (pvecSize
> 1) {
2617 if (pvec
[pvecSize
-2](pvec
[pvecSize
-1])) break;
2618 T t
= pvec
[pvecSize
-1];
2623 while (pvecSize
> 1) {
2624 if (pvec
[pvecSize
-1](pvec
[0])) break;
2632 // ////////////////////////////////////////////////////////////////////////// //
2633 // process vertex source [src] with generator [dest]
2634 void feedWith(VSD
, VSS
) (ref VSD dest
, ref VSS src
) {
2639 immutable cmd
= src
.vertex(&x
, &y
);
2640 dest
.addVertex(x
, y
, cmd
);
2641 if (isStop(cmd
)) break;
2646 // ////////////////////////////////////////////////////////////////////////// //
2647 // this connects vertex source to vertex generator
2649 float x
= 0.0f, y
= 0.0f;
2651 @property bool lineto () const pure nothrow @safe @nogc { pragma(inline
, true); return !moveto
; }
2655 struct PathPointRange
{
2657 SimpleVector
!PathPoint pts
;
2660 public nothrow @trusted @nogc:
2661 mixin(DisableCopyingMixin
);
2663 this(VG
) (ref VG vg
) {
2670 auto cmd
= vs
.vertex(&x
, &y
);
2671 if (isStop(cmd
)) break;
2672 if (isMoveTo(cmd
)) {
2678 if (isLineTo(cmd
)) {
2680 import std.math : isNaN;
2684 if (first
) { pts
.add(PathPoint(sx
, sy
, true)); }
2685 pts
.add(PathPoint(x
, y
, false));
2688 if (isEndPoly(cmd
)) {
2689 if (isClose(cmd
) && !first
) {
2690 //writeln("s=(", sx, ",", sy, "); c=(", x, ",", y, ")");
2691 pts
.add(PathPoint(sx
, sy
, false));
2698 void rewind () { pragma(inline
, true); idx
= 0; }
2700 @property bool empty () const pure { pragma(inline
, true); return (idx
>= pts
.length
); }
2701 @property ref inout(PathPoint
) front () inout pure { pragma(inline
, true); return pts
[idx
]; }
2702 @property int length () const pure { pragma(inline
, true); return pts
.length
-idx
; }
2703 void popFront () { if (idx
< pts
.length
) ++idx
; }
2707 // ////////////////////////////////////////////////////////////////////////// //
2708 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 {
2709 //enum IntersectionEPS = cast(double)1.0e-30; // See calc_intersection
2710 enum IntersectionEPS
= cast(float)1.0e-16; // See calc_intersection
2711 //version(aliced) pragma(inline, true);
2712 //import std.math : abs;
2713 import core
.stdc
.math
: fabsf
;
2714 immutable float num
= (ay
-cy
)*(dx
-cx
)-(ax
-cx
)*(dy
-cy
);
2715 immutable float den
= (bx
-ax
)*(dy
-cy
)-(by
-ay
)*(dx
-cx
);
2716 if (fabsf(den
) < IntersectionEPS
) return false;
2717 //if ((den < 0.0f ? (-den < IntersectionEPS) : (den < IntersectionEPS))) return false;
2718 immutable float r
= num
/den
;
2719 if (x
!is null) *x
= ax
+r
*(bx
-ax
);
2720 if (y
!is null) *y
= ay
+r
*(by
-ay
);
2724 float cross (in float x1
, in float y1
, in float x2
, in float y2
, in float x
, in float y
) pure nothrow @safe @nogc {
2725 pragma(inline
, true);
2726 return (x
-x2
)*(y2
-y1
)-(y
-y2
)*(x2
-x1
);
2729 float distance (in float x1
, in float y1
, in float x2
, in float y2
) /*pure*/ nothrow @safe @nogc {
2730 pragma(inline
, true);
2731 import core
.stdc
.math
: sqrtf
;
2732 immutable float dx
= x2
-x1
;
2733 immutable float dy
= y2
-y1
;
2734 return sqrtf(dx
*dx
+dy
*dy
);
2737 float distance() (in auto ref VertexDist v0
, in auto ref VertexDist v1
) /*pure*/ nothrow @safe @nogc {
2738 pragma(inline
, true);
2739 import core
.stdc
.math
: sqrtf
;
2740 immutable float dx
= v1
.x
-v0
.x
;
2741 immutable float dy
= v1
.y
-v0
.y
;
2742 return sqrtf(dx
*dx
+dy
*dy
);
2747 * VertexConsumer API:
2748 * alias value_type = VertexType; // shoud support `VertexType(x, y)`
2749 * vc.remove_all(); -- start new polygon
2750 * vc.add(VT); -- add point to the current polygon
2752 struct StrokeCalc(VertexConsumer
) {
2754 float mWidth
= 0.5f;
2755 float mWidthAbs
= 0.5f;
2756 float mWidthEps
= 0.5f/1024.0f;
2758 float mMiterLimit
= 4.0f;
2759 float mInnerMiterLimit
= 1.01f;
2760 float mApproxScale
= 1.0f;
2761 LineCap mLineCap
= LineCap
.Butt
;
2762 LineJoin mLineJoin
= LineJoin
.Miter
;
2763 InnerJoin mInnerJoin
= InnerJoin
.Miter
;
2765 public nothrow @trusted @nogc:
2766 alias CoordType
= VertexConsumer
.ValueType
;
2768 mixin(DisableCopyingMixin
);
2770 @property void lineCap (in LineCap lc
) { pragma(inline
, true); mLineCap
= lc
; }
2771 @property void lineJoin (in LineJoin lj
) { pragma(inline
, true); mLineJoin
= lj
; }
2772 @property void innerJoin (in InnerJoin ij
) { pragma(inline
, true); mInnerJoin
= ij
; }
2774 @property LineCap
lineCap () const pure { pragma(inline
, true); return mLineCap
; }
2775 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mLineJoin
; }
2776 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mInnerJoin
; }
2778 @property float width () const pure { pragma(inline
, true); return mWidth
*2.0f; }
2779 @property void width (in float w
) {
2781 if (mWidth
< 0.0f) {
2782 mWidthAbs
= -mWidth
;
2788 mWidthEps
= mWidth
/1024.0f;
2791 @property void miterLimit (in float ml
) { pragma(inline
, true); mMiterLimit
= ml
; }
2792 @property void miterLimitTheta (in float t
) { pragma(inline
, true); import core
.stdc
.math
: sinf
; mMiterLimit
= 1.0f/sinf(t
*0.5f); }
2793 @property void innerMiterLimit (in float ml
) { pragma(inline
, true); mInnerMiterLimit
= ml
; }
2794 @property void approximationScale (in float as
) { pragma(inline
, true); mApproxScale
= as
; }
2796 @property float miterLimit () const pure { pragma(inline
, true); return mMiterLimit
; }
2797 @property float innerMiterLimit () const pure { pragma(inline
, true); return mInnerMiterLimit
; }
2798 @property float approximationScale () const pure { pragma(inline
, true); return mApproxScale
; }
2800 void calcCap() (ref VertexConsumer vc
, in auto ref VertexDist v0
, in auto ref VertexDist v1
, in float len
) {
2801 import core
.stdc
.math
: acosf
, atan2f
, cosf
, sinf
;
2805 float dx1
= (v1
.y
-v0
.y
)/len
;
2806 float dy1
= (v1
.x
-v0
.x
)/len
;
2813 if (mLineCap
!= LineCap
.Round
) {
2814 if (mLineCap
== LineCap
.Square
) {
2815 dx2
= dy1
*mWidthSign
;
2816 dy2
= dx1
*mWidthSign
;
2818 addVertex(vc
, v0
.x
-dx1
-dx2
, v0
.y
+dy1
-dy2
);
2819 addVertex(vc
, v0
.x
+dx1
-dx2
, v0
.y
-dy1
-dy2
);
2821 float da = acosf(mWidthAbs
/(mWidthAbs
+0.125f/mApproxScale
))*2.0f;
2822 immutable int n
= cast(int)(FLT_PI
/da);
2824 addVertex(vc
, v0
.x
-dx1
, v0
.y
+dy1
);
2825 if (mWidthSign
> 0.0f) {
2826 float a1
= atan2f(dy1
, -dx1
);
2828 foreach (immutable int i
; 0..n
) {
2829 addVertex(vc
, v0
.x
+cosf(a1
)*mWidth
, v0
.y
+sinf(a1
)*mWidth
);
2833 float a1
= atan2f(-dy1
, dx1
);
2835 foreach (immutable int i
; 0..n
) {
2836 addVertex(vc
, v0
.x
+cosf(a1
)*mWidth
, v0
.y
+sinf(a1
)*mWidth
);
2840 addVertex(vc
, v0
.x
+dx1
, v0
.y
-dy1
);
2844 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
) {
2845 import core
.stdc
.math
: sqrtf
;
2847 immutable float dx1
= mWidth
*(v1
.y
-v0
.y
)/len1
;
2848 immutable float dy1
= mWidth
*(v1
.x
-v0
.x
)/len1
;
2849 immutable float dx2
= mWidth
*(v2
.y
-v1
.y
)/len2
;
2850 immutable float dy2
= mWidth
*(v2
.x
-v1
.x
)/len2
;
2854 float cp
= cross(v0
.x
, v0
.y
, v1
.x
, v1
.y
, v2
.x
, v2
.y
);
2855 if (cp
!= 0.0f && (cp
> 0.0f) == (mWidth
> 0.0f)) {
2857 float limit
= (len1
< len2 ? len1
: len2
)/mWidthAbs
;
2858 if (limit
< mInnerMiterLimit
) limit
= mInnerMiterLimit
;
2860 switch (mInnerJoin
) {
2861 default: // inner_bevel
2862 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2863 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2865 case InnerJoin
.Miter
:
2866 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, LineJoin
.MiterRevert
, limit
, 0.0f);
2869 case InnerJoin
.Round
:
2870 cp
= (dx1
-dx2
)*(dx1
-dx2
)+(dy1
-dy2
)*(dy1
-dy2
);
2871 if (cp
< len1
*len1
&& cp
< len2
*len2
) {
2872 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, LineJoin
.MiterRevert
, limit
, 0.0f);
2874 if (mInnerJoin
== InnerJoin
.Jag
) {
2875 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2876 addVertex(vc
, v1
.x
, v1
.y
);
2877 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2879 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2880 addVertex(vc
, v1
.x
, v1
.y
);
2881 calcArc(vc
, v1
.x
, v1
.y
, dx2
, -dy2
, dx1
, -dy1
);
2882 addVertex(vc
, v1
.x
, v1
.y
);
2883 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2891 // Calculate the distance between v1 and
2892 // the central point of the bevel line segment
2893 float dx
= (dx1
+dx2
)*0.5f;
2894 float dy
= (dy1
+dy2
)*0.5f;
2895 immutable float dbevel
= sqrtf(dx
*dx
+dy
*dy
);
2897 if (mLineJoin
== LineJoin
.Round || mLineJoin
== LineJoin
.Bevel
) {
2898 // This is an optimization that reduces the number of points
2899 // in cases of almost collinear segments. If there's no
2900 // visible difference between bevel and miter joins we'd rather
2901 // use miter join because it adds only one point instead of two.
2903 // Here we calculate the middle point between the bevel points
2904 // and then, the distance between v1 and this middle point.
2905 // At outer joins this distance always less than stroke width,
2906 // because it's actually the height of an isosceles triangle of
2907 // v1 and its two bevel points. If the difference between this
2908 // width and this value is small (no visible bevel) we can
2909 // add just one point.
2911 // The constant in the expression makes the result approximately
2912 // the same as in round joins and caps. You can safely comment
2913 // out this entire "if".
2914 if (mApproxScale
*(mWidthAbs
-dbevel
) < mWidthEps
) {
2915 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
)) {
2916 addVertex(vc
, dx
, dy
);
2918 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2924 switch (mLineJoin
) {
2925 case LineJoin
.Miter
:
2926 case LineJoin
.MiterRevert
:
2927 case LineJoin
.MiterRound
:
2928 calcMiter(vc
, v0
, v1
, v2
, dx1
, dy1
, dx2
, dy2
, mLineJoin
, mMiterLimit
, dbevel
);
2930 case LineJoin
.Round
:
2931 calcArc(vc
, v1
.x
, v1
.y
, dx1
, -dy1
, dx2
, -dy2
);
2933 default: // Bevel join
2934 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
2935 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
2942 void addVertex (ref VertexConsumer vc
, in float x
, in float y
) {
2943 pragma(inline
, true);
2944 vc
.add(CoordType(x
, y
));
2947 void calcArc (ref VertexConsumer vc
, in float x
, in float y
, in float dx1
, in float dy1
, in float dx2
, in float dy2
) {
2948 import core
.stdc
.math
: acosf
, atan2f
, cosf
, sinf
;
2950 float a1
= atan2f(dy1
*mWidthSign
, dx1
*mWidthSign
);
2951 float a2
= atan2f(dy2
*mWidthSign
, dx2
*mWidthSign
);
2953 immutable float da = acosf(mWidthAbs
/(mWidthAbs
+0.125f/mApproxScale
))*2.0f;
2955 addVertex(vc
, x
+dx1
, y
+dy1
);
2956 if (mWidthSign
> 0.0f) {
2957 if (a1
> a2
) a2
+= 2.0f*FLT_PI
;
2958 immutable int n
= cast(int)((a2
-a1
)/da);
2959 immutable float daa = (a2
-a1
)/(n
+1);
2961 foreach (immutable int i
; 0..n
) {
2962 addVertex(vc
, x
+cosf(a1
)*mWidth
, y
+sinf(a1
)*mWidth
);
2966 if (a1
< a2
) a2
-= 2.0f*FLT_PI
;
2967 immutable int n
= cast(int)((a1
-a2
)/da);
2968 immutable float daa = (a1
-a2
)/(n
+1);
2970 foreach (immutable int i
; 0..n
) {
2971 addVertex(vc
, x
+cosf(a1
)*mWidth
, y
+sinf(a1
)*mWidth
);
2975 addVertex(vc
, x
+dx2
, y
+dy2
);
2978 void calcMiter (ref VertexConsumer vc
, in ref VertexDist v0
, in ref VertexDist v1
, in ref VertexDist v2
,
2979 in float dx1
, in float dy1
, in float dx2
, in float dy2
, in LineJoin lj
,
2980 in float mlimit
, in float dbevel
)
2985 immutable float lim
= mWidthAbs
*mlimit
;
2986 bool miterLimitExceeded
= true; // assume the worst
2987 bool intersectionFailed
= true; // assume the worst
2989 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
)) {
2990 // Calculation of the intersection succeeded
2991 di = distance(v1
.x
, v1
.y
, xi
, yi
);
2993 // Inside the miter limit
2994 addVertex(vc
, xi
, yi
);
2995 miterLimitExceeded
= false;
2997 intersectionFailed
= false;
2999 // Calculation of the intersection failed, most probably
3000 // the three points lie one straight line.
3001 // First check if v0 and v2 lie on the opposite sides of vector:
3002 // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
3003 // to the line determined by vertices v0 and v1.
3004 // This condition determines whether the next line segments continues
3005 // the previous one or goes back.
3006 immutable float x2
= v1
.x
+dx1
;
3007 immutable float y2
= v1
.y
-dy1
;
3008 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)) {
3009 // This case means that the next segment continues
3010 // the previous one (straight line)
3011 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
3012 miterLimitExceeded
= false;
3016 if (miterLimitExceeded
) {
3017 // Miter limit exceeded
3018 //------------------------
3020 case LineJoin
.MiterRevert
:
3021 // For the compatibility with SVG, PDF, etc,
3022 // we use a simple bevel join instead of
3024 addVertex(vc
, v1
.x
+dx1
, v1
.y
-dy1
);
3025 addVertex(vc
, v1
.x
+dx2
, v1
.y
-dy2
);
3027 case LineJoin
.MiterRound
:
3028 calcArc(vc
, v1
.x
, v1
.y
, dx1
, -dy1
, dx2
, -dy2
);
3031 // If no miter-revert, calculate new dx1, dy1, dx2, dy2
3032 if (intersectionFailed
) {
3033 immutable float mlimitM
= mlimit
*mWidthSign
;
3034 addVertex(vc
, v1
.x
+dx1
+dy1
*mlimitM
, v1
.y
-dy1
+dx1
*mlimitM
);
3035 addVertex(vc
, v1
.x
+dx2
-dy2
*mlimitM
, v1
.y
-dy2
-dx2
*mlimitM
);
3037 immutable float x1
= v1
.x
+dx1
;
3038 immutable float y1
= v1
.y
-dy1
;
3039 immutable float x2
= v1
.x
+dx2
;
3040 immutable float y2
= v1
.y
-dy2
;
3041 di = (lim
-dbevel
)/(di-dbevel
);
3042 addVertex(vc
, x1
+(xi
-x1
)*di, y1
+(yi
-y1
)*di);
3043 addVertex(vc
, x2
+(xi
-x2
)*di, y2
+(yi
-y2
)*di);
3052 // ////////////////////////////////////////////////////////////////////////// //
3054 public nothrow @trusted @nogc:
3055 alias VertexStorage
= VertexSequence
!VertexDist
;
3056 alias CoordStorage
= SimpleVector
!AGGPoint
;
3074 StrokeCalc
!CoordStorage mStroker
;
3075 VertexStorage mSrcVertices
;
3076 CoordStorage mOutVertices
;
3079 State mStatus
= State
.Initial
;
3081 uint mSrcVertex
= 0;
3082 uint mOutVertex
= 0;
3085 mixin(DisableCopyingMixin
);
3087 @property void lineCap (LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
3088 @property void lineJoin (LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
3089 @property void innerJoin (InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
3091 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
3092 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
3093 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
3095 @property void width (float w
) { pragma(inline
, true); mStroker
.width(w
); }
3096 @property void miterLimit (float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
3097 @property void miterLimitTheta (float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
3098 @property void innerMiterLimit (float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
3099 @property void approximationScale (float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
3101 @property float width () const pure { pragma(inline
, true); return mStroker
.width(); }
3102 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
3103 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
3104 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
3106 @property void shorten (float s
) { pragma(inline
, true); mShorten
= s
; }
3107 @property float shorten () const pure { pragma(inline
, true); return mShorten
; }
3109 // Generator interface
3111 mSrcVertices
.removeAll();
3113 mStatus
= State
.Initial
;
3116 void addVertex (float x
, float y
, uint cmd
) {
3117 mStatus
= State
.Initial
;
3118 if (isMoveTo(cmd
)) {
3119 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3121 if (isVertex(cmd
)) {
3122 mSrcVertices
.add(VertexDist(x
, y
));
3124 mClosed
= getCloseFlag(cmd
);
3129 // Vertex Source Interface
3131 if (mStatus
== State
.Initial
) {
3132 mSrcVertices
.close(mClosed
!= 0);
3133 shortenPath(mSrcVertices
, mShorten
, mClosed
);
3134 if (mSrcVertices
.length
< 3) mClosed
= 0;
3136 mStatus
= State
.Ready
;
3141 uint vertex (float* x
, float* y
) {
3142 uint cmd
= PathCommand
.LineTo
;
3143 while (!isStop(cmd
)) {
3144 final switch (mStatus
) {
3150 if (mSrcVertices
.length
< 2+cast(uint)(mClosed
!= 0)) {
3151 cmd
= PathCommand
.Stop
;
3154 mStatus
= (mClosed ? State
.Outline1
: State
.Cap1
);
3155 cmd
= PathCommand
.MoveTo
;
3161 mStroker
.calcCap(mOutVertices
, mSrcVertices
[0], mSrcVertices
[1], mSrcVertices
[0].dist
);
3163 mPrevStatus
= State
.Outline1
;
3164 mStatus
= State
.OutVertices
;
3169 mStroker
.calcCap(mOutVertices
, mSrcVertices
[mSrcVertices
.length
-1], mSrcVertices
[mSrcVertices
.length
-2], mSrcVertices
[mSrcVertices
.length
-2].dist
);
3170 mPrevStatus
= State
.Outline2
;
3171 mStatus
= State
.OutVertices
;
3175 case State
.Outline1
:
3177 if (mSrcVertex
>= mSrcVertices
.length
) {
3178 mPrevStatus
= State
.CloseFirst
;
3179 mStatus
= State
.End_poly1
;
3183 if (mSrcVertex
>= mSrcVertices
.length
-1) {
3184 mStatus
= State
.Cap2
;
3188 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.next(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
).dist
, mSrcVertices
.curr(mSrcVertex
).dist
);
3190 mPrevStatus
= mStatus
;
3191 mStatus
= State
.OutVertices
;
3195 case State
.CloseFirst
:
3196 mStatus
= State
.Outline2
;
3197 cmd
= PathCommand
.MoveTo
;
3200 case State
.Outline2
:
3201 if (mSrcVertex
<= uint(mClosed
== 0)) {
3202 mStatus
= State
.End_poly2
;
3203 mPrevStatus
= State
.Stop
;
3208 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.next(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
).dist
, mSrcVertices
.prev(mSrcVertex
).dist
);
3210 mPrevStatus
= mStatus
;
3211 mStatus
= State
.OutVertices
;
3215 case State
.OutVertices
:
3216 if (mOutVertex
>= mOutVertices
.length
) {
3217 mStatus
= mPrevStatus
;
3219 const(AGGPoint
)* c
= &mOutVertices
[mOutVertex
++];
3226 case State
.End_poly1
:
3227 mStatus
= mPrevStatus
;
3228 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CCW
;
3230 case State
.End_poly2
:
3231 mStatus
= mPrevStatus
;
3232 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CW
;
3235 cmd
= PathCommand
.Stop
;
3244 // ////////////////////////////////////////////////////////////////////////// //
3246 public nothrow @trusted @nogc:
3247 alias VertexStorage
= VertexSequence
!VertexDist
;
3248 alias CoordStorage
= SimpleVector
!AGGPoint
;
3260 StrokeCalc
!CoordStorage mStroker
;
3262 VertexStorage mSrcVertices
;
3263 CoordStorage mOutVertices
;
3265 uint mSrcVertex
= 0;
3268 uint mOrientation
= 0;
3269 bool mAutoDetect
= false;
3272 mixin(DisableCopyingMixin
);
3274 @property void lineCap (LineCap lc
) { pragma(inline
, true); mStroker
.lineCap(lc
); }
3275 @property void lineJoin (LineJoin lj
) { pragma(inline
, true); mStroker
.lineJoin(lj
); }
3276 @property void innerJoin (InnerJoin ij
) { pragma(inline
, true); mStroker
.innerJoin(ij
); }
3278 @property LineCap
lineCap () const pure { pragma(inline
, true); return mStroker
.lineCap(); }
3279 @property LineJoin
lineJoin () const pure { pragma(inline
, true); return mStroker
.lineJoin(); }
3280 @property InnerJoin
innerJoin () const pure { pragma(inline
, true); return mStroker
.innerJoin(); }
3282 @property void width (float w
) { pragma(inline
, true); mStroker
.width(mWidth
= w
); }
3283 @property void miterLimit (float ml
) { pragma(inline
, true); mStroker
.miterLimit(ml
); }
3284 @property void miterLimitTheta (float t
) { pragma(inline
, true); mStroker
.miterLimitTheta(t
); }
3285 @property void innerMiterLimit (float ml
) { pragma(inline
, true); mStroker
.innerMiterLimit(ml
); }
3286 @property void approximationScale (float as
) { pragma(inline
, true); mStroker
.approximationScale(as
); }
3288 @property float width () const pure { pragma(inline
, true); return mWidth
; }
3289 @property float miterLimit () const pure { pragma(inline
, true); return mStroker
.miterLimit(); }
3290 @property float innerMiterLimit () const pure { pragma(inline
, true); return mStroker
.innerMiterLimit(); }
3291 @property float approximationScale () const pure { pragma(inline
, true); return mStroker
.approximationScale(); }
3293 @property void autoDetectOrientation (bool v
) { pragma(inline
, true); mAutoDetect
= v
; }
3294 @property bool autoDetectOrientation () const pure { pragma(inline
, true); return mAutoDetect
; }
3296 // Generator interface
3298 mSrcVertices
.removeAll();
3301 mStatus
= State
.Initial
;
3304 void addVertex (float x
, float y
, uint cmd
) {
3305 mStatus
= State
.Initial
;
3306 if (isMoveTo(cmd
)) {
3307 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3309 if (isVertex(cmd
)) {
3310 mSrcVertices
.add(VertexDist(x
, y
));
3312 if (isEndPoly(cmd
)) {
3313 mClosed
= getCloseFlag(cmd
);
3314 if (mOrientation
== PathFlag
.None
) {
3315 mOrientation
= getOrientation(cmd
);
3322 // Vertex Source Interface
3324 if (mStatus
== State
.Initial
) {
3325 mSrcVertices
.close(true);
3327 if (!isOriented(mOrientation
)) {
3328 mOrientation
= (calcPolygonArea(mSrcVertices
) > 0 ? PathFlag
.CCW
: PathFlag
.CW
);
3331 if (isOriented(mOrientation
)) {
3332 mStroker
.width(isCCW(mOrientation
) ? mWidth
: -mWidth
);
3335 mStatus
= State
.Ready
;
3339 uint vertex (float* x
, float* y
) {
3340 uint cmd
= PathCommand
.LineTo
;
3341 while (!isStop(cmd
)) {
3342 final switch (mStatus
) {
3348 if (mSrcVertices
.length
< 2+cast(uint)(mClosed
!= 0)) {
3349 cmd
= PathCommand
.Stop
;
3352 mStatus
= State
.Outline
;
3353 cmd
= PathCommand
.MoveTo
;
3359 if (mSrcVertex
>= mSrcVertices
.length
) {
3360 mStatus
= State
.EndPoly
;
3363 mStroker
.calcJoin(mOutVertices
, mSrcVertices
.prev(mSrcVertex
), mSrcVertices
.curr(mSrcVertex
), mSrcVertices
.next(mSrcVertex
), mSrcVertices
.prev(mSrcVertex
).dist
, mSrcVertices
.curr(mSrcVertex
).dist
);
3365 mStatus
= State
.OutVertices
;
3369 case State
.OutVertices
:
3370 if (mOutVertex
>= mOutVertices
.length
) {
3371 mStatus
= State
.Outline
;
3373 const(AGGPoint
)* c
= &mOutVertices
[mOutVertex
++];
3381 if (!mClosed
) return PathCommand
.Stop
;
3382 mStatus
= State
.Stop
;
3383 return PathCommand
.EndPoly|PathFlag
.Close|PathFlag
.CCW
;
3386 return PathCommand
.Stop
;
3394 // ////////////////////////////////////////////////////////////////////////// //
3396 private nothrow @trusted @nogc:
3397 alias VertexStorage
= VertexSequence
!VertexDist
;
3398 enum MaxDashes
= 32;
3408 float[MaxDashes
] mDashes
= 0;
3409 float mTotalDashLen
= 0;
3410 uint mNumDashes
= 0;
3411 float mDashStart
= 0;
3413 float mCurrDashStart
= 0;
3415 float mCurrRest
= 0;
3416 const(VertexDist
)* m_v1
= null;
3417 const(VertexDist
)* m_v2
= null;
3419 VertexStorage mSrcVertices
;
3421 State mStatus
= State
.Initial
;
3422 uint mSrcVertex
= 0;
3425 mixin(DisableCopyingMixin
);
3427 @property void shorten (float s
) { mShorten
= s
; }
3428 @property float shorten () const pure { return mShorten
; }
3430 void removeAllDashes () {
3437 void addDash (float dashLen
, float gapLen
) {
3438 if (mNumDashes
< MaxDashes
) {
3439 mTotalDashLen
+= dashLen
+gapLen
;
3440 mDashes
[mNumDashes
++] = dashLen
;
3441 mDashes
[mNumDashes
++] = gapLen
;
3445 void dashStart (float ds) {
3446 //import std.math : abs;
3447 import core
.stdc
.math
: fabsf
;
3449 calcDashStart(fabsf(ds));
3452 // Vertex Generator Interface
3454 mStatus
= State
.Initial
;
3455 mSrcVertices
.removeAll();
3459 void addVertex (float x
, float y
, uint cmd
) {
3460 mStatus
= State
.Initial
;
3461 if (isMoveTo(cmd
)) {
3462 mSrcVertices
.modifyLast(VertexDist(x
, y
));
3464 if (isVertex(cmd
)) {
3465 mSrcVertices
.add(VertexDist(x
, y
));
3467 mClosed
= getCloseFlag(cmd
);
3472 // Vertex Source Interface
3474 if (mStatus
== State
.Initial
) {
3475 mSrcVertices
.close(mClosed
!= 0);
3476 shortenPath(mSrcVertices
, mShorten
, mClosed
);
3478 mStatus
= State
.Ready
;
3482 uint vertex (float* x
, float* y
) {
3483 uint cmd
= PathCommand
.MoveTo
;
3485 while (!isStop(cmd
)) {
3486 final switch (mStatus
) {
3492 if (mNumDashes
< 2 || mSrcVertices
.length
< 2) {
3493 cmd
= PathCommand
.Stop
;
3496 mStatus
= State
.Polyline
;
3498 m_v1
= &mSrcVertices
[0];
3499 m_v2
= &mSrcVertices
[1];
3500 mCurrRest
= m_v1
.dist
;
3503 if (mDashStart
>= 0) calcDashStart(mDashStart
);
3504 return PathCommand
.MoveTo
;
3506 case State
.Polyline
:
3507 immutable float dashRest
= mDashes
[mCurrDash
]-mCurrDashStart
;
3508 cmd
= (mCurrDash
&1 ? PathCommand
.MoveTo
: PathCommand
.LineTo
);
3509 if (mCurrRest
> dashRest
) {
3510 mCurrRest
-= dashRest
;
3512 if (mCurrDash
>= mNumDashes
) mCurrDash
= 0;
3514 *x
= m_v2
.x
-(m_v2
.x
-m_v1
.x
)*mCurrRest
/m_v1
.dist
;
3515 *y
= m_v2
.y
-(m_v2
.y
-m_v1
.y
)*mCurrRest
/m_v1
.dist
;
3517 mCurrDashStart
+= mCurrRest
;
3522 mCurrRest
= m_v1
.dist
;
3524 if (mSrcVertex
> mSrcVertices
.length
) {
3525 mStatus
= State
.Stop
;
3527 m_v2
= &mSrcVertices
[mSrcVertex
>= mSrcVertices
.length ?
0 :mSrcVertex
];
3530 if (mSrcVertex
>= mSrcVertices
.length
) {
3531 mStatus
= State
.Stop
;
3533 m_v2
= &mSrcVertices
[mSrcVertex
];
3540 cmd
= PathCommand
.Stop
;
3544 return PathCommand
.Stop
;
3548 void calcDashStart (float ds) {
3552 if (ds > mDashes
[mCurrDash
]) {
3553 ds -= mDashes
[mCurrDash
];
3556 if (mCurrDash
>= mNumDashes
) mCurrDash
= 0;
3558 mCurrDashStart
= ds;
3566 // ////////////////////////////////////////////////////////////////////////// //
3567 // Matrices and Transformations
3570 public align(1) struct AGGMatrix
{
3573 static immutable float[6] IdentityMat
= [
3580 /// Matrix values. Initial value is identity matrix.
3587 public nothrow @trusted @nogc:
3588 /// Create Matrix with the given values.
3589 this (const(float)[] amat
...) {
3590 pragma(inline
, true);
3591 if (amat
.length
>= 6) {
3592 mat
.ptr
[0..6] = amat
.ptr
[0..6];
3594 mat
.ptr
[0..6] = 0.0f;
3595 mat
.ptr
[0..amat
.length
] = amat
[];
3599 /// Can be used to check validity of [inverted] result
3600 @property bool valid () const { import core
.stdc
.math
: isfinite
; return (isfinite(mat
.ptr
[0]) != 0); }
3602 /// Returns `true` if this matrix is identity matrix.
3603 @property bool isIdentity () const { version(aliced
) pragma(inline
, true); return (mat
[] == IdentityMat
[]); }
3605 /// Returns new inverse matrix.
3606 /// If inverted matrix cannot be calculated, `res.valid` fill be `false`.
3607 AGGMatrix
inverted () const {
3608 AGGMatrix res
= this;
3613 /// Inverts this matrix.
3614 /// If inverted matrix cannot be calculated, `this.valid` fill be `false`.
3615 ref AGGMatrix
invert () {
3616 float[6] inv
= void;
3617 immutable double det
= cast(double)mat
.ptr
[0]*mat
.ptr
[3]-cast(double)mat
.ptr
[2]*mat
.ptr
[1];
3618 if (det
> -1e-6 && det
< 1e-6) {
3621 immutable double invdet
= 1.0/det
;
3622 inv
.ptr
[0] = cast(float)(mat
.ptr
[3]*invdet
);
3623 inv
.ptr
[2] = cast(float)(-mat
.ptr
[2]*invdet
);
3624 inv
.ptr
[4] = cast(float)((cast(double)mat
.ptr
[2]*mat
.ptr
[5]-cast(double)mat
.ptr
[3]*mat
.ptr
[4])*invdet
);
3625 inv
.ptr
[1] = cast(float)(-mat
.ptr
[1]*invdet
);
3626 inv
.ptr
[3] = cast(float)(mat
.ptr
[0]*invdet
);
3627 inv
.ptr
[5] = cast(float)((cast(double)mat
.ptr
[1]*mat
.ptr
[4]-cast(double)mat
.ptr
[0]*mat
.ptr
[5])*invdet
);
3629 mat
.ptr
[0..6] = inv
.ptr
[0..6];
3633 /// Sets this matrix to identity matrix.
3634 ref AGGMatrix
identity () { version(aliced
) pragma(inline
, true); mat
[] = IdentityMat
[]; return this; }
3636 /// Translate this matrix.
3637 ref AGGMatrix
translate (in float tx
, in float ty
) {
3638 version(aliced
) pragma(inline
, true);
3639 return this.mul(Translated(tx
, ty
));
3642 /// Scale this matrix.
3643 ref AGGMatrix
scale (in float sx
, in float sy
) {
3644 version(aliced
) pragma(inline
, true);
3645 return this.mul(Scaled(sx
, sy
));
3648 /// Rotate this matrix.
3649 ref AGGMatrix
rotate (in float a
) {
3650 version(aliced
) pragma(inline
, true);
3651 return this.mul(Rotated(a
));
3654 /// Skew this matrix by X axis.
3655 ref AGGMatrix
skewX (in float a
) {
3656 version(aliced
) pragma(inline
, true);
3657 return this.mul(SkewedX(a
));
3660 /// Skew this matrix by Y axis.
3661 ref AGGMatrix
skewY (in float a
) {
3662 version(aliced
) pragma(inline
, true);
3663 return this.mul(SkewedY(a
));
3666 /// Skew this matrix by both axes.
3667 ref AGGMatrix
skewY (in float ax
, in float ay
) {
3668 version(aliced
) pragma(inline
, true);
3669 return this.mul(SkewedXY(ax
, ay
));
3672 /// Transform point with this matrix. `null` destinations are allowed.
3673 /// [sx] and [sy] is the source point. [dx] and [dy] may point to the same variables.
3674 void point (float* dx
, float* dy
, float sx
, float sy
) {
3675 version(aliced
) pragma(inline
, true);
3676 if (dx
!is null) *dx
= sx
*mat
.ptr
[0]+sy
*mat
.ptr
[2]+mat
.ptr
[4];
3677 if (dy
!is null) *dy
= sx
*mat
.ptr
[1]+sy
*mat
.ptr
[3]+mat
.ptr
[5];
3680 /// Transform point with this matrix.
3681 void point (ref float x
, ref float y
) {
3682 version(aliced
) pragma(inline
, true);
3683 immutable float nx
= x
*mat
.ptr
[0]+y
*mat
.ptr
[2]+mat
.ptr
[4];
3684 immutable float ny
= x
*mat
.ptr
[1]+y
*mat
.ptr
[3]+mat
.ptr
[5];
3689 /// Sets this matrix to the result of multiplication of `this` and [s] (this * S).
3690 ref AGGMatrix
mul() (in auto ref AGGMatrix s
) {
3691 immutable float t0
= mat
.ptr
[0]*s
.mat
.ptr
[0]+mat
.ptr
[1]*s
.mat
.ptr
[2];
3692 immutable float t2
= mat
.ptr
[2]*s
.mat
.ptr
[0]+mat
.ptr
[3]*s
.mat
.ptr
[2];
3693 immutable float t4
= mat
.ptr
[4]*s
.mat
.ptr
[0]+mat
.ptr
[5]*s
.mat
.ptr
[2]+s
.mat
.ptr
[4];
3694 mat
.ptr
[1] = mat
.ptr
[0]*s
.mat
.ptr
[1]+mat
.ptr
[1]*s
.mat
.ptr
[3];
3695 mat
.ptr
[3] = mat
.ptr
[2]*s
.mat
.ptr
[1]+mat
.ptr
[3]*s
.mat
.ptr
[3];
3696 mat
.ptr
[5] = mat
.ptr
[4]*s
.mat
.ptr
[1]+mat
.ptr
[5]*s
.mat
.ptr
[3]+s
.mat
.ptr
[5];
3703 /// Sets this matrix to the result of multiplication of [s] and `this` (S * this).
3704 /// Sets the transform to the result of multiplication of two transforms, of A = B*A.
3706 ref AGGMatrix
premul() (in auto ref AGGMatrix s
) {
3713 /// Multiply this matrix by [s], return result as new matrix.
3714 /// Performs operations in this left-to-right order.
3715 AGGMatrix
opBinary(string op
="*") (in auto ref AGGMatrix s
) const {
3716 version(aliced
) pragma(inline
, true);
3717 AGGMatrix res
= this;
3722 /// Multiply this matrix by [s].
3723 /// Performs operations in this left-to-right order.
3724 ref AGGMatrix
opOpAssign(string op
="*") (in auto ref AGGMatrix s
) {
3725 version(aliced
) pragma(inline
, true);
3729 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.
3730 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.
3731 float rotation () const { pragma(inline
, true); import core
.stdc
.math
: atan2f
; return atan2f(mat
.ptr
[1], mat
.ptr
[0]); } /// Returns rotation of this matrix.
3732 float tx () const { pragma(inline
, true); return mat
.ptr
[4]; } /// Returns x translation of this matrix.
3733 float ty () const { pragma(inline
, true); return mat
.ptr
[5]; } /// Returns y translation of this matrix.
3735 ref AGGMatrix
scaleX (in float v
) { pragma(inline
, true); return scaleRotateTransform(v
, scaleY
, rotation
, tx
, ty
); } /// Sets x scaling of this matrix.
3736 ref AGGMatrix
scaleY (in float v
) { pragma(inline
, true); return scaleRotateTransform(scaleX
, v
, rotation
, tx
, ty
); } /// Sets y scaling of this matrix.
3737 ref AGGMatrix
rotation (in float v
) { pragma(inline
, true); return scaleRotateTransform(scaleX
, scaleY
, v
, tx
, ty
); } /// Sets rotation of this matrix.
3738 ref AGGMatrix
tx (in float v
) { pragma(inline
, true); mat
.ptr
[4] = v
; return this; } /// Sets x translation of this matrix.
3739 ref AGGMatrix
ty (in float v
) { pragma(inline
, true); mat
.ptr
[5] = v
; return this; } /// Sets y translation of this matrix.
3741 /// Utility function to be used in `setXXX()`.
3742 /// This is the same as doing: `mat.identity.rotate(a).scale(xs, ys).translate(tx, ty)`, only faster
3743 ref AGGMatrix
scaleRotateTransform (in float xscale
, in float yscale
, in float a
, in float tx
, in float ty
) {
3744 import core
.stdc
.math
: sinf
, cosf
;
3745 immutable float cs
= cosf(a
), sn
= sinf(a
);
3746 mat
.ptr
[0] = xscale
*cs
; mat
.ptr
[1] = yscale
*sn
;
3747 mat
.ptr
[2] = xscale
*-sn
; mat
.ptr
[3] = yscale
*cs
;
3748 mat
.ptr
[4] = tx
; mat
.ptr
[5] = ty
;
3752 /// This is the same as doing: `mat.identity.rotate(a).translate(tx, ty)`, only faster
3753 ref AGGMatrix
rotateTransform (in float a
, in float tx
, in float ty
) {
3754 import core
.stdc
.math
: sinf
, cosf
;
3755 immutable float cs
= cosf(a
), sn
= sinf(a
);
3756 mat
.ptr
[0] = cs
; mat
.ptr
[1] = sn
;
3757 mat
.ptr
[2] = -sn
; mat
.ptr
[3] = cs
;
3758 mat
.ptr
[4] = tx
; mat
.ptr
[5] = ty
;
3762 /// Returns new identity matrix.
3763 static AGGMatrix
Identity () { pragma(inline
, true); return AGGMatrix
.init
; }
3765 /// Returns new translation matrix.
3766 static AGGMatrix
Translated (in float tx
, in float ty
) {
3767 version(aliced
) pragma(inline
, true);
3768 AGGMatrix res
= void;
3769 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = 0.0f;
3770 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = 1.0f;
3771 res
.mat
.ptr
[4] = tx
; res
.mat
.ptr
[5] = ty
;
3775 /// Returns new scaling matrix.
3776 static AGGMatrix
Scaled (in float sx
, in float sy
) {
3777 version(aliced
) pragma(inline
, true);
3778 AGGMatrix res
= void;
3779 res
.mat
.ptr
[0] = sx
; res
.mat
.ptr
[1] = 0.0f;
3780 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = sy
;
3781 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3785 /// Returns new rotation matrix. Angle is specified in radians.
3786 static AGGMatrix
Rotated (in float a
) {
3787 version(aliced
) pragma(inline
, true);
3788 import core
.stdc
.math
: sinf
, cosf
;
3789 immutable float cs
= cosf(a
), sn
= sinf(a
);
3790 AGGMatrix res
= void;
3791 res
.mat
.ptr
[0] = cs
; res
.mat
.ptr
[1] = sn
;
3792 res
.mat
.ptr
[2] = -sn
; res
.mat
.ptr
[3] = cs
;
3793 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3797 /// Returns new x-skewing matrix. Angle is specified in radians.
3798 static AGGMatrix
SkewedX (in float a
) {
3799 version(aliced
) pragma(inline
, true);
3800 import core
.stdc
.math
: tanf
;
3801 AGGMatrix res
= void;
3802 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = 0.0f;
3803 res
.mat
.ptr
[2] = tanf(a
); res
.mat
.ptr
[3] = 1.0f;
3804 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3808 /// Returns new y-skewing matrix. Angle is specified in radians.
3809 static AGGMatrix
SkewedY (in float a
) {
3810 version(aliced
) pragma(inline
, true);
3811 import core
.stdc
.math
: tanf
;
3812 AGGMatrix res
= void;
3813 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = tanf(a
);
3814 res
.mat
.ptr
[2] = 0.0f; res
.mat
.ptr
[3] = 1.0f;
3815 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3819 /// Returns new xy-skewing matrix. Angles are specified in radians.
3820 static AGGMatrix
SkewedXY (in float ax
, in float ay
) {
3821 version(aliced
) pragma(inline
, true);
3822 import core
.stdc
.math
: tanf
;
3823 AGGMatrix res
= void;
3824 res
.mat
.ptr
[0] = 1.0f; res
.mat
.ptr
[1] = tanf(ay
);
3825 res
.mat
.ptr
[2] = tanf(ax
); res
.mat
.ptr
[3] = 1.0f;
3826 res
.mat
.ptr
[4] = 0.0f; res
.mat
.ptr
[5] = 0.0f;
3830 /// Utility function to be used in `setXXX()`.
3831 /// This is the same as doing: `AGGMatrix.Identity.rotate(a).scale(xs, ys).translate(tx, ty)`, only faster
3832 static AGGMatrix
ScaledRotatedTransformed (in float xscale
, in float yscale
, in float a
, in float tx
, in float ty
) {
3833 AGGMatrix res
= void;
3834 res
.scaleRotateTransform(xscale
, yscale
, a
, tx
, ty
);
3838 /// This is the same as doing: `AGGMatrix.Identity.rotate(a).translate(tx, ty)`, only faster
3839 static AGGMatrix
RotatedTransformed (in float a
, in float tx
, in float ty
) {
3840 AGGMatrix res
= void;
3841 res
.rotateTransform(a
, tx
, ty
);
3846 // premultiplies current coordinate system by specified matrix
3847 ref AGGMatrix
transform() (in auto ref AGGMatrix mt
) { pragma(inline
, true); this *= mt
; return this; }
3849 // translates current coordinate system
3850 ref AGGMatrix
translatePre (in float x
, in float y
) { pragma(inline
, true); return premul(AGGMatrix
.Translated(x
, y
)); }
3852 // rotates current coordinate system; angle is specified in radians
3853 ref AGGMatrix
rotatePre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.Rotated(angle
)); }
3855 // skews the current coordinate system along X axis; angle is specified in radians
3856 ref AGGMatrix
skewXPre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.SkewedX(angle
)); }
3858 // skews the current coordinate system along Y axis; angle is specified in radians
3859 ref AGGMatrix
skewYPre (in float angle
) { pragma(inline
, true); return premul(AGGMatrix
.SkewedY(angle
)); }
3861 // scales the current coordinate system
3862 ref AGGMatrix
scalePre (in float x
, in float y
) { pragma(inline
, true); return premul(AGGMatrix
.Scaled(x
, y
)); }