1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4 (Public License)
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
6 // Pascal Port By: Milan Marusinec alias Milano
7 //                 milan@marusinec.sk
8 //                 http://www.aggpas.org
9 // Copyright (c) 2005-2006
10 //
11 // Permission to copy, use, modify, sell and distribute this software
12 // is granted provided this copyright notice appears in all copies.
13 // This software is provided "as is" without express or implied
14 // warranty, and with no claim as to its suitability for any purpose.
15 //
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 //          mcseemagg@yahoo.com
19 //          http://www.antigrain.com
20 //
21 //----------------------------------------------------------------------------
22 //
23 // Stroke generator
24 //
25 // [Pascal Port History] -----------------------------------------------------
26 //
27 // 18.10.2007-Milano: vcgen_stroke_math
28 // 21.12.2005-Milano: Unit port establishment
29 //
30 { agg_vcgen_stroke.pas }
31 unit
32  agg_vcgen_stroke ;
33 
34 INTERFACE
35 
36 {$I agg_mode.inc }
37 
38 uses
39  agg_basics ,
40  agg_array ,
41  agg_vertex_source ,
42  agg_vertex_sequence ,
43  agg_math_stroke ,
44  agg_shorten_path ;
45 
46 { TYPES DEFINITION }
47 type
48  status_e = (
49   initial ,
50   ready ,
51   cap1 ,
52   cap2 ,
53   outline1 ,
54   close_first ,
55   outline2 ,
56   out_vertices ,
57   end_poly1 ,
58   end_poly2 ,
59   stop );
60 
61  vcgen_stroke_ptr = ^vcgen_stroke;
62  vcgen_stroke = object(vertex_source )
63    m_src_vertices      : vertex_sequence;
64    m_out_vertices      : pod_deque;
65    m_width             ,
66    m_miter_limit       ,
67    m_inner_miter_limit ,
68    m_approx_scale      ,
69    m_shorten           : double;
70    m_line_cap          ,
71    m_line_join         ,
72    m_inner_join        ,
73    m_closed            : unsigned;
74    m_status            ,
75    m_prev_status       : status_e;
76    m_src_vertex        ,
77    m_out_vertex        : unsigned;
78 
79    constructor Construct;
80    destructor  Destruct; virtual;
81 
82    procedure line_cap_  (lc : unsigned );
83    procedure line_join_ (lj : unsigned );
84    procedure inner_join_(ij : unsigned );
85 
_line_capnull86    function  _line_cap : unsigned;
_line_joinnull87    function  _line_join : unsigned;
_inner_joinnull88    function  _inner_join : unsigned;
89 
90    procedure width_              (w : double );
91    procedure miter_limit_        (ml : double );
92    procedure miter_limit_theta_  (t : double );
93    procedure inner_miter_limit_  (ml : double );
94    procedure approximation_scale_(as_ : double );
95 
_widthnull96    function  _width : double;
_miter_limitnull97    function  _miter_limit : double;
_inner_miter_limitnull98    function  _inner_miter_limit : double;
_approximation_scalenull99    function  _approximation_scale : double;
100 
101    procedure shorten_(s : double );
_shortennull102    function  _shorten : double;
103 
104   // Vertex Generator Interface
105    procedure remove_all; virtual;
106    procedure add_vertex(x ,y : double; cmd : unsigned ); virtual;
107 
108   // Vertex Source Interface
109    procedure rewind(path_id : unsigned ); virtual;
vertexnull110    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
111 
112   end;
113 
114  vcgen_stroke_math_ptr = ^vcgen_stroke_math;
115  vcgen_stroke_math = object(vertex_source )
116    m_stroker      : math_stroke;
117    m_src_vertices : vertex_sequence;
118    m_out_vertices : pod_deque;
119 
120    m_shorten : double;
121    m_closed  : unsigned;
122 
123    m_status      ,
124    m_prev_status : status_e;
125 
126    m_src_vertex ,
127    m_out_vertex : unsigned;
128 
129    constructor Construct;
130    destructor  Destruct; virtual;
131 
132    procedure line_cap_  (lc : unsigned );
133    procedure line_join_ (lj : unsigned );
134    procedure inner_join_(ij : unsigned );
135 
_line_capnull136    function  _line_cap : unsigned;
_line_joinnull137    function  _line_join : unsigned;
_inner_joinnull138    function  _inner_join : unsigned;
139 
140    procedure width_              (w : double );
141    procedure miter_limit_        (ml : double );
142    procedure miter_limit_theta_  (t : double );
143    procedure inner_miter_limit_  (ml : double );
144    procedure approximation_scale_(as_ : double );
145 
_widthnull146    function  _width : double;
_miter_limitnull147    function  _miter_limit : double;
_inner_miter_limitnull148    function  _inner_miter_limit : double;
_approximation_scalenull149    function  _approximation_scale : double;
150 
151    procedure shorten_(s : double );
_shortennull152    function  _shorten : double;
153 
154   // Vertex Generator Interface
155    procedure remove_all; virtual;
156    procedure add_vertex(x ,y : double; cmd : unsigned ); virtual;
157 
158   // Vertex Source Interface
159    procedure rewind(path_id : unsigned ); virtual;
vertexnull160    function  vertex(x ,y : double_ptr ) : unsigned; virtual;
161 
162   end;
163 
164 { GLOBAL PROCEDURES }
165 
166 
167 IMPLEMENTATION
168 { LOCAL VARIABLES & CONSTANTS }
169 { UNIT IMPLEMENTATION }
170 { CONSTRUCT }
171 constructor vcgen_stroke.Construct;
172 begin
173  m_src_vertices.Construct(sizeof(vertex_dist ) );
174  m_out_vertices.Construct(sizeof(point_type ) );
175 
176  m_width            :=0.5;
177  m_miter_limit      :=4.0;
178  m_inner_miter_limit:=1.01;
179  m_approx_scale     :=1.0;
180  m_shorten          :=0.0;
181  m_line_cap         :=butt_cap;
182  m_line_join        :=miter_join;
183  m_inner_join       :=inner_miter;
184  m_closed           :=0;
185  m_status           :=initial;
186  m_src_vertex       :=0;
187  m_out_vertex       :=0;
188 
189 end;
190 
191 { DESTRUCT }
192 destructor vcgen_stroke.Destruct;
193 begin
194  m_src_vertices.Destruct;
195  m_out_vertices.Destruct;
196 
197 end;
198 
199 { LINE_CAP_ }
200 procedure vcgen_stroke.line_cap_;
201 begin
202  m_line_cap:=lc;
203 
204 end;
205 
206 { LINE_JOIN_ }
207 procedure vcgen_stroke.line_join_;
208 begin
209  m_line_join:=lj;
210 
211 end;
212 
213 { INNER_JOIN_ }
214 procedure vcgen_stroke.inner_join_;
215 begin
216  m_inner_join:=ij;
217 
218 end;
219 
220 { _LINE_CAP }
vcgen_stroke._line_capnull221 function vcgen_stroke._line_cap;
222 begin
223  result:=m_line_cap;
224 
225 end;
226 
227 { _LINE_JOIN }
vcgen_stroke._line_joinnull228 function vcgen_stroke._line_join;
229 begin
230  result:=m_line_join;
231 
232 end;
233 
234 { _INNER_JOIN }
vcgen_stroke._inner_joinnull235 function vcgen_stroke._inner_join;
236 begin
237  result:=m_inner_join;
238 
239 end;
240 
241 { WIDTH_ }
242 procedure vcgen_stroke.width_(w : double );
243 begin
244  m_width:=w * 0.5;
245 
246 end;
247 
248 { MITER_LIMIT_ }
249 procedure vcgen_stroke.miter_limit_(ml : double );
250 begin
251  m_miter_limit:=ml;
252 
253 end;
254 
255 { MITER_LIMIT_THETA_ }
256 procedure vcgen_stroke.miter_limit_theta_(t : double );
257 begin
258  m_miter_limit:=1.0 / Sin(t * 0.5 );
259 
260 end;
261 
262 { INNER_MITER_LIMIT_ }
263 procedure vcgen_stroke.inner_miter_limit_(ml : double );
264 begin
265  m_inner_miter_limit:=ml;
266 
267 end;
268 
269 { APPROXIMATION_SCALE_ }
270 procedure vcgen_stroke.approximation_scale_(as_ : double );
271 begin
272  m_approx_scale:=as_;
273 
274 end;
275 
276 { _WIDTH }
vcgen_stroke._widthnull277 function vcgen_stroke._width;
278 begin
279  result:=m_width * 2.0;
280 
281 end;
282 
283 { _MITER_LIMIT }
vcgen_stroke._miter_limitnull284 function vcgen_stroke._miter_limit;
285 begin
286  result:=m_miter_limit;
287 
288 end;
289 
290 { _INNER_MITER_LIMIT }
vcgen_stroke._inner_miter_limitnull291 function vcgen_stroke._inner_miter_limit;
292 begin
293  result:=m_inner_miter_limit;
294 
295 end;
296 
297 { _APPROXIMATION_SCALE }
vcgen_stroke._approximation_scalenull298 function vcgen_stroke._approximation_scale;
299 begin
300  result:=m_approx_scale;
301 
302 end;
303 
304 { SHORTEN_ }
305 procedure vcgen_stroke.shorten_;
306 begin
307  m_shorten:=s;
308 
309 end;
310 
311 { _SHORTEN }
vcgen_stroke._shortennull312 function vcgen_stroke._shorten;
313 begin
314  result:=m_shorten;
315 
316 end;
317 
318 { REMOVE_ALL }
319 procedure vcgen_stroke.remove_all;
320 begin
321  m_src_vertices.remove_all;
322 
323  m_closed:=0;
324  m_status:=initial;
325 
326 end;
327 
328 { ADD_VERTEX }
329 procedure vcgen_stroke.add_vertex(x ,y : double; cmd : unsigned );
330 var
331  vd : vertex_dist;
332 
333 begin
334  m_status:=initial;
335 
336  vd.x:=x;
337  vd.y:=y;
338 
339  vd.dist:=0;
340 
341  if is_move_to(cmd ) then
342   m_src_vertices.modify_last(@vd )
343  else
344   if is_vertex(cmd ) then
345    m_src_vertices.add(@vd )
346   else
347    m_closed:=get_close_flag(cmd );
348 
349 end;
350 
351 { calc_butt_cap }
352 procedure calc_butt_cap(cap : double_00_ptr; v0 ,v1 : vertex_dist_ptr; len ,width : double );
353 var
354  dx ,dy : double;
355 
356 begin
357  dx:=(v1.y - v0.y ) * width / len;
358  dy:=(v1.x - v0.x ) * width / len;
359 
360  cap^[0 ]:=v0.x - dx;
361  cap^[1 ]:=v0.y + dy;
362  cap^[2 ]:=v0.x + dx;
363  cap^[3 ]:=v0.y - dy;
364 
365 end;
366 
367 { REWIND }
368 procedure vcgen_stroke.rewind(path_id : unsigned );
369 begin
370  if m_status = initial then
371   begin
372    m_src_vertices.close(boolean(m_closed <> 0 ) );
373 
374    shorten_path(@m_src_vertices ,m_shorten ,m_closed );
375 
376    if m_src_vertices.size < 3 then
377     m_closed:=0;
378 
379   end;
380 
381  m_status:=ready;
382 
383  m_src_vertex:=0;
384  m_out_vertex:=0;
385 
386 end;
387 
388 { VERTEX }
vcgen_stroke.vertexnull389 function vcgen_stroke.vertex(x ,y : double_ptr ) : unsigned;
390 var
391  c : point_type_ptr;
392 
393  cmd : unsigned;
394 
395 label
396  _rdy ,_out2 ,_end ;
397 
398 begin
399  cmd:=path_cmd_line_to;
400 
401  while not is_stop(cmd ) do
402   begin
403    case m_status of
404     initial :
405      begin
406       rewind(0 );
407 
408       goto _rdy;
409 
410      end;
411 
412     ready :
413      begin
414      _rdy:
415       if m_src_vertices.size < 2 + unsigned(m_closed <> 0 ) then
416        begin
417         cmd:=path_cmd_stop;
418 
419         goto _end;
420 
421        end;
422 
423       if (m_closed <> 0 ) then
424        m_status:=outline1
425       else
426        m_status:=cap1;
427 
428       cmd:=path_cmd_move_to;
429 
430       m_src_vertex:=0;
431       m_out_vertex:=0;
432 
433      end;
434 
435     cap1 :
436      begin
437       stroke_calc_cap(
438        @m_out_vertices ,
439        m_src_vertices.array_operator(0 ) ,
440        m_src_vertices.array_operator(1 ) ,
441        vertex_dist_ptr(m_src_vertices.array_operator(0 ) )^.dist ,
442        m_line_cap ,
443        m_width ,
444        m_approx_scale );
445 
446       m_src_vertex :=1;
447       m_prev_status:=outline1;
448       m_status     :=out_vertices;
449       m_out_vertex :=0;
450 
451      end;
452 
453     cap2 :
454      begin
455       stroke_calc_cap(
456        @m_out_vertices ,
457        m_src_vertices.array_operator(m_src_vertices.size - 1 ) ,
458        m_src_vertices.array_operator(m_src_vertices.size - 2 ) ,
459        vertex_dist_ptr(m_src_vertices.array_operator(m_src_vertices.size - 2 ) )^.dist ,
460        m_line_cap ,
461        m_width ,
462        m_approx_scale );
463 
464       m_prev_status:=outline2;
465       m_status     :=out_vertices;
466       m_out_vertex :=0;
467 
468      end;
469 
470     outline1 :
471      begin
472       if m_closed <> 0 then
473        if m_src_vertex >= m_src_vertices.size then
474         begin
475          m_prev_status:=close_first;
476          m_status     :=end_poly1;
477 
478          goto _end;
479 
480         end
481        else
482       else
483        if m_src_vertex >= m_src_vertices.size - 1 then
484         begin
485          m_status:=cap2;
486 
487          goto _end;
488 
489         end;
490 
491       stroke_calc_join(
492        @m_out_vertices ,
493        m_src_vertices.prev(m_src_vertex ) ,
494        m_src_vertices.curr(m_src_vertex ) ,
495        m_src_vertices.next(m_src_vertex ) ,
496        vertex_dist_ptr(m_src_vertices.prev(m_src_vertex ) )^.dist ,
497        vertex_dist_ptr(m_src_vertices.curr(m_src_vertex ) )^.dist ,
498        m_width ,
499        m_line_join ,
500        m_inner_join ,
501        m_miter_limit ,
502        m_inner_miter_limit ,
503        m_approx_scale );
504 
505       inc(m_src_vertex );
506 
507       m_prev_status:=m_status;
508       m_status     :=out_vertices;
509       m_out_vertex :=0;
510 
511      end;
512 
513     close_first :
514      begin
515       m_status:=outline2;
516 
517       cmd:=path_cmd_move_to;
518 
519       goto _out2;
520 
521      end;
522 
523     outline2 :
524      begin
525      _out2:
526       if m_src_vertex <= unsigned(m_closed = 0 ) then
527        begin
528         m_status     :=end_poly2;
529         m_prev_status:=stop;
530 
531         goto _end;
532 
533        end;
534 
535       dec(m_src_vertex );
536 
537       stroke_calc_join(
538        @m_out_vertices ,
539        m_src_vertices.next(m_src_vertex ) ,
540        m_src_vertices.curr(m_src_vertex ) ,
541        m_src_vertices.prev(m_src_vertex ) ,
542        vertex_dist_ptr(m_src_vertices.curr(m_src_vertex ) )^.dist ,
543        vertex_dist_ptr(m_src_vertices.prev(m_src_vertex ) )^.dist ,
544        m_width ,
545        m_line_join  ,
546        m_inner_join ,
547        m_miter_limit ,
548        m_inner_miter_limit ,
549        m_approx_scale );
550 
551       m_prev_status:=m_status;
552       m_status     :=out_vertices;
553       m_out_vertex :=0;
554 
555      end;
556 
557     out_vertices :
558      if m_out_vertex >= m_out_vertices.size then
559       m_status:=m_prev_status
560 
561      else
562       begin
563        c:=m_out_vertices.array_operator(m_out_vertex );
564 
565        inc(m_out_vertex );
566 
567        x^:=c.x;
568        y^:=c.y;
569 
570        result:=cmd;
571 
572        exit;
573 
574       end;
575 
576     end_poly1 :
577      begin
578       m_status:=m_prev_status;
579 
580       result:=path_cmd_end_poly or path_flags_close or path_flags_ccw;
581 
582       exit;
583 
584      end;
585 
586     end_poly2 :
587      begin
588       m_status:=m_prev_status;
589 
590       result:=path_cmd_end_poly or path_flags_close or path_flags_cw;
591 
592       exit;
593 
594      end;
595 
596     stop :
597      cmd:=path_cmd_stop;
598 
599    end;
600 
601   _end:
602   end;
603 
604  result:=cmd;
605 
606 end;
607 
608 { CONSTRUCT }
609 constructor vcgen_stroke_math.Construct;
610 begin
611  m_stroker.Construct;
612  m_src_vertices.Construct(sizeof(vertex_dist ) );
613  m_out_vertices.Construct(sizeof(point_type ) );
614 
615  m_shorten:=0.0;
616  m_closed :=0;
617  m_status :=initial;
618 
619  m_src_vertex:=0;
620  m_out_vertex:=0;
621 
622 end;
623 
624 { DESTRUCT }
625 destructor vcgen_stroke_math.Destruct;
626 begin
627  m_src_vertices.Destruct;
628  m_out_vertices.Destruct;
629 
630 end;
631 
632 { LINE_CAP_ }
633 procedure vcgen_stroke_math.line_cap_(lc : unsigned );
634 begin
635  m_stroker.line_cap_(lc );
636 
637 end;
638 
639 { LINE_JOIN_ }
640 procedure vcgen_stroke_math.line_join_(lj : unsigned );
641 begin
642  m_stroker.line_join_(lj );
643 
644 end;
645 
646 { INNER_JOIN_ }
647 procedure vcgen_stroke_math.inner_join_(ij : unsigned );
648 begin
649  m_stroker.inner_join_(ij );
650 
651 end;
652 
653 { _LINE_CAP }
vcgen_stroke_math._line_capnull654 function vcgen_stroke_math._line_cap : unsigned;
655 begin
656  result:=m_stroker._line_cap;
657 
658 end;
659 
660 { _LINE_JOIN }
vcgen_stroke_math._line_joinnull661 function vcgen_stroke_math._line_join : unsigned;
662 begin
663  result:=m_stroker._line_join;
664 
665 end;
666 
667 { _INNER_JOIN }
vcgen_stroke_math._inner_joinnull668 function vcgen_stroke_math._inner_join : unsigned;
669 begin
670  result:=m_stroker._inner_join;
671 
672 end;
673 
674 { WIDTH_ }
675 procedure vcgen_stroke_math.width_(w : double );
676 begin
677  m_stroker.width_(w );
678 
679 end;
680 
681 { MITER_LIMIT_ }
682 procedure vcgen_stroke_math.miter_limit_(ml : double );
683 begin
684  m_stroker.miter_limit_(ml );
685 
686 end;
687 
688 { MITER_LIMIT_THETA_ }
689 procedure vcgen_stroke_math.miter_limit_theta_(t : double );
690 begin
691  m_stroker.miter_limit_theta_(t );
692 
693 end;
694 
695 { INNER_MITER_LIMIT_ }
696 procedure vcgen_stroke_math.inner_miter_limit_(ml : double );
697 begin
698  m_stroker.inner_miter_limit_(ml );
699 
700 end;
701 
702 { APPROXIMATION_SCALE_ }
703 procedure vcgen_stroke_math.approximation_scale_(as_ : double );
704 begin
705  m_stroker.approximation_scale_(as_ );
706 
707 end;
708 
709 { _WIDTH }
vcgen_stroke_math._widthnull710 function vcgen_stroke_math._width : double;
711 begin
712  result:=m_stroker._width;
713 
714 end;
715 
716 { _MITER_LIMIT }
vcgen_stroke_math._miter_limitnull717 function vcgen_stroke_math._miter_limit : double;
718 begin
719  result:=m_stroker._miter_limit;
720 
721 end;
722 
723 { _INNER_MITER_LIMIT }
vcgen_stroke_math._inner_miter_limitnull724 function vcgen_stroke_math._inner_miter_limit : double;
725 begin
726  result:=m_stroker._inner_miter_limit;
727 
728 end;
729 
730 { _APPROXIMATION_SCALE }
vcgen_stroke_math._approximation_scalenull731 function vcgen_stroke_math._approximation_scale : double;
732 begin
733  result:=m_stroker._approximation_scale;
734 
735 end;
736 
737 { SHORTEN_ }
738 procedure vcgen_stroke_math.shorten_(s : double );
739 begin
740  m_shorten:=s;
741 
742 end;
743 
744 { _SHORTEN }
vcgen_stroke_math._shortennull745 function vcgen_stroke_math._shorten : double;
746 begin
747  result:=m_shorten;
748 
749 end;
750 
751 { REMOVE_ALL }
752 procedure vcgen_stroke_math.remove_all;
753 begin
754  m_src_vertices.remove_all;
755 
756  m_closed:=0;
757  m_status:=initial;
758 
759 end;
760 
761 { ADD_VERTEX }
762 procedure vcgen_stroke_math.add_vertex(x ,y : double; cmd : unsigned );
763 var
764  vd : vertex_dist;
765 
766 begin
767  m_status:=initial;
768 
769  vd.x:=x;
770  vd.y:=y;
771 
772  vd.dist:=0;
773 
774  if is_move_to(cmd ) then
775   m_src_vertices.modify_last(@vd )
776  else
777   if is_vertex(cmd ) then
778    m_src_vertices.add(@vd )
779   else
780    m_closed:=get_close_flag(cmd );
781 
782 end;
783 
784 { REWIND }
785 procedure vcgen_stroke_math.rewind(path_id : unsigned );
786 begin
787  if m_status = initial then
788   begin
789    m_src_vertices.close(boolean(m_closed <> 0 ) );
790 
791    shorten_path(@m_src_vertices ,m_shorten ,m_closed );
792 
793    if m_src_vertices.size < 3 then
794     m_closed:=0;
795 
796   end;
797 
798  m_status:=ready;
799 
800  m_src_vertex:=0;
801  m_out_vertex:=0;
802 
803 end;
804 
805 { VERTEX }
vcgen_stroke_math.vertexnull806 function vcgen_stroke_math.vertex(x ,y : double_ptr ) : unsigned;
807 var
808  cmd : unsigned;
809 
810  c : point_type_ptr;
811 
812 label
813  _rdy ,_out2 ,_end ;
814 
815 begin
816  cmd:=path_cmd_line_to;
817 
818  while not is_stop(cmd ) do
819   begin
820    case m_status of
821     initial :
822      begin
823       rewind(0 );
824 
825       goto _rdy;
826 
827      end;
828 
829     ready :
830      begin
831      _rdy:
832       if m_src_vertices.size < 2 + unsigned(m_closed <> 0 ) then
833        begin
834         cmd:=path_cmd_stop;
835 
836         goto _end;
837 
838        end;
839 
840       if (m_closed <> 0 ) then
841        m_status:=outline1
842       else
843        m_status:=cap1;
844 
845       cmd:=path_cmd_move_to;
846 
847       m_src_vertex:=0;
848       m_out_vertex:=0;
849 
850      end;
851 
852     cap1 :
853      begin
854       m_stroker.calc_cap(
855        @m_out_vertices ,
856        m_src_vertices.array_operator(0 ) ,
857        m_src_vertices.array_operator(1 ) ,
858        vertex_dist_ptr(m_src_vertices.array_operator(0 ) )^.dist );
859 
860       m_src_vertex :=1;
861       m_prev_status:=outline1;
862       m_status     :=out_vertices;
863       m_out_vertex :=0;
864 
865      end;
866 
867     cap2 :
868      begin
869       m_stroker.calc_cap(
870        @m_out_vertices ,
871        m_src_vertices.array_operator(m_src_vertices.size - 1 ) ,
872        m_src_vertices.array_operator(m_src_vertices.size - 2 ) ,
873        vertex_dist_ptr(m_src_vertices.array_operator(m_src_vertices.size - 2 ) )^.dist );
874 
875       m_prev_status:=outline2;
876       m_status     :=out_vertices;
877       m_out_vertex :=0;
878 
879      end;
880 
881     outline1 :
882      begin
883       if m_closed <> 0 then
884        if m_src_vertex >= m_src_vertices.size then
885         begin
886          m_prev_status:=close_first;
887          m_status     :=end_poly1;
888 
889          goto _end;
890 
891         end
892        else
893       else
894        if m_src_vertex >= m_src_vertices.size - 1 then
895         begin
896          m_status:=cap2;
897 
898          goto _end;
899 
900         end;
901 
902       m_stroker.calc_join(
903        @m_out_vertices ,
904        m_src_vertices.prev(m_src_vertex ) ,
905        m_src_vertices.curr(m_src_vertex ) ,
906        m_src_vertices.next(m_src_vertex ) ,
907        vertex_dist_ptr(m_src_vertices.prev(m_src_vertex ) )^.dist ,
908        vertex_dist_ptr(m_src_vertices.curr(m_src_vertex ) )^.dist );
909 
910       inc(m_src_vertex );
911 
912       m_prev_status:=m_status;
913       m_status     :=out_vertices;
914       m_out_vertex :=0;
915 
916      end;
917 
918     close_first :
919      begin
920       m_status:=outline2;
921 
922       cmd:=path_cmd_move_to;
923 
924       goto _out2;
925 
926      end;
927 
928     outline2 :
929      begin
930      _out2:
931       if m_src_vertex <= unsigned(m_closed = 0 ) then
932        begin
933         m_status     :=end_poly2;
934         m_prev_status:=stop;
935 
936         goto _end;
937 
938        end;
939 
940       dec(m_src_vertex );
941 
942       m_stroker.calc_join(
943        @m_out_vertices ,
944        m_src_vertices.next(m_src_vertex ) ,
945        m_src_vertices.curr(m_src_vertex ) ,
946        m_src_vertices.prev(m_src_vertex ) ,
947        vertex_dist_ptr(m_src_vertices.curr(m_src_vertex ) )^.dist ,
948        vertex_dist_ptr(m_src_vertices.prev(m_src_vertex ) )^.dist );
949 
950       m_prev_status:=m_status;
951       m_status     :=out_vertices;
952       m_out_vertex :=0;
953 
954      end;
955 
956     out_vertices :
957      if m_out_vertex >= m_out_vertices.size then
958       m_status:=m_prev_status
959 
960      else
961       begin
962        c:=m_out_vertices.array_operator(m_out_vertex );
963 
964        inc(m_out_vertex );
965 
966        x^:=c.x;
967        y^:=c.y;
968 
969        result:=cmd;
970 
971        exit;
972 
973       end;
974 
975     end_poly1 :
976      begin
977       m_status:=m_prev_status;
978 
979       result:=path_cmd_end_poly or path_flags_close or path_flags_ccw;
980 
981       exit;
982 
983      end;
984 
985     end_poly2 :
986      begin
987       m_status:=m_prev_status;
988 
989       result:=path_cmd_end_poly or path_flags_close or path_flags_cw;
990 
991       exit;
992 
993      end;
994 
995     stop :
996      cmd:=path_cmd_stop;
997 
998    end;
999 
1000   _end:
1001   end;
1002 
1003  result:=cmd;
1004 
1005 end;
1006 
1007 END.
1008 
1009