1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.4
3// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15#ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED
16#define AGG_RASTERIZER_OUTLINE_AA_INCLUDED
17
18#include "agg_basics.h"
19#include "agg_line_aa_basics.h"
20#include "agg_vertex_sequence.h"
21
22namespace agg
23{
24
25    //-------------------------------------------------------------------------
26    inline bool cmp_dist_start(int d) { return d > 0;  }
27    inline bool cmp_dist_end(int d)   { return d <= 0; }
28
29
30
31    //-----------------------------------------------------------line_aa_vertex
32    // Vertex (x, y) with the distance to the next one. The last vertex has
33    // the distance between the last and the first points
34    struct line_aa_vertex
35    {
36        int x;
37        int y;
38        int len;
39
40        line_aa_vertex() {}
41        line_aa_vertex(int x_, int y_) :
42            x(x_),
43            y(y_),
44            len(0)
45        {
46        }
47
48        bool operator () (const line_aa_vertex& val)
49        {
50            double dx = val.x - x;
51            double dy = val.y - y;
52            return (len = uround(sqrt(dx * dx + dy * dy))) >
53                   (line_subpixel_scale + line_subpixel_scale / 2);
54        }
55    };
56
57
58    //----------------------------------------------------------outline_aa_join_e
59    enum outline_aa_join_e
60    {
61        outline_no_join,             //-----outline_no_join
62        outline_miter_join,          //-----outline_miter_join
63        outline_round_join,          //-----outline_round_join
64        outline_miter_accurate_join  //-----outline_accurate_join
65    };
66
67    //=======================================================rasterizer_outline_aa
68    template<class Renderer, class Coord=line_coord> class rasterizer_outline_aa
69    {
70    private:
71        //------------------------------------------------------------------------
72        struct draw_vars
73        {
74            unsigned idx;
75            int x1, y1, x2, y2;
76            line_parameters curr, next;
77            int lcurr, lnext;
78            int xb1, yb1, xb2, yb2;
79            unsigned flags;
80        };
81
82        void draw(draw_vars& dv, unsigned start, unsigned end);
83
84    public:
85        typedef line_aa_vertex                  vertex_type;
86        typedef vertex_sequence<vertex_type, 6> vertex_storage_type;
87
88        rasterizer_outline_aa(Renderer& ren) :
89            m_ren(&ren),
90            m_line_join(ren.accurate_join_only() ?
91                            outline_miter_accurate_join :
92                            outline_round_join),
93            m_round_cap(false),
94            m_start_x(0),
95            m_start_y(0)
96        {}
97        void attach(Renderer& ren) { m_ren = &ren; }
98
99        //------------------------------------------------------------------------
100        void line_join(outline_aa_join_e join)
101        {
102            m_line_join = m_ren->accurate_join_only() ?
103                outline_miter_accurate_join :
104                join;
105        }
106        bool line_join() const { return m_line_join; }
107
108        //------------------------------------------------------------------------
109        void round_cap(bool v) { m_round_cap = v; }
110        bool round_cap() const { return m_round_cap; }
111
112        //------------------------------------------------------------------------
113        void move_to(int x, int y)
114        {
115            m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y));
116        }
117
118        //------------------------------------------------------------------------
119        void line_to(int x, int y)
120        {
121            m_src_vertices.add(vertex_type(x, y));
122        }
123
124        //------------------------------------------------------------------------
125        void move_to_d(double x, double y)
126        {
127            move_to(Coord::conv(x), Coord::conv(y));
128        }
129
130        //------------------------------------------------------------------------
131        void line_to_d(double x, double y)
132        {
133            line_to(Coord::conv(x), Coord::conv(y));
134        }
135
136        //------------------------------------------------------------------------
137        void render(bool close_polygon);
138
139        //------------------------------------------------------------------------
140        void add_vertex(double x, double y, unsigned cmd)
141        {
142            if(is_move_to(cmd))
143            {
144                render(false);
145                move_to_d(x, y);
146            }
147            else
148            {
149                if(is_end_poly(cmd))
150                {
151                    render(is_closed(cmd));
152                    if(is_closed(cmd))
153                    {
154                        move_to(m_start_x, m_start_y);
155                    }
156                }
157                else
158                {
159                    line_to_d(x, y);
160                }
161            }
162        }
163
164        //------------------------------------------------------------------------
165        template<class VertexSource>
166        void add_path(VertexSource& vs, unsigned path_id=0)
167        {
168            double x;
169            double y;
170
171            unsigned cmd;
172            vs.rewind(path_id);
173            while(!is_stop(cmd = vs.vertex(&x, &y)))
174            {
175                add_vertex(x, y, cmd);
176            }
177            render(false);
178        }
179
180
181        //------------------------------------------------------------------------
182        template<class VertexSource, class ColorStorage, class PathId>
183        void render_all_paths(VertexSource& vs,
184                              const ColorStorage& colors,
185                              const PathId& path_id,
186                              unsigned num_paths)
187        {
188            for(unsigned i = 0; i < num_paths; i++)
189            {
190                m_ren->color(colors[i]);
191                add_path(vs, path_id[i]);
192            }
193        }
194
195
196        //------------------------------------------------------------------------
197        template<class Ctrl> void render_ctrl(Ctrl& c)
198        {
199            unsigned i;
200            for(i = 0; i < c.num_paths(); i++)
201            {
202                m_ren->color(c.color(i));
203                add_path(c, i);
204            }
205        }
206
207    private:
208        rasterizer_outline_aa(const rasterizer_outline_aa<Renderer, Coord>&);
209        const rasterizer_outline_aa<Renderer, Coord>& operator =
210            (const rasterizer_outline_aa<Renderer, Coord>&);
211
212        Renderer*           m_ren;
213        vertex_storage_type m_src_vertices;
214        outline_aa_join_e   m_line_join;
215        bool                m_round_cap;
216        int                 m_start_x;
217        int                 m_start_y;
218    };
219
220
221
222
223
224
225
226
227    //----------------------------------------------------------------------------
228    template<class Renderer, class Coord>
229    void rasterizer_outline_aa<Renderer, Coord>::draw(draw_vars& dv,
230                                                      unsigned start,
231                                                      unsigned end)
232    {
233        unsigned i;
234        const vertex_storage_type::value_type* v;
235
236        for(i = start; i < end; i++)
237        {
238            if(m_line_join == outline_round_join)
239            {
240                dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1);
241                dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1);
242                dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1);
243                dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1);
244            }
245
246            switch(dv.flags)
247            {
248            case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break;
249            case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break;
250            case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break;
251            case 3: m_ren->line0(dv.curr); break;
252            }
253
254            if(m_line_join == outline_round_join && (dv.flags & 2) == 0)
255            {
256                m_ren->pie(dv.curr.x2, dv.curr.y2,
257                           dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
258                           dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
259                           dv.curr.x2 + (dv.next.y2 - dv.next.y1),
260                           dv.curr.y2 - (dv.next.x2 - dv.next.x1));
261            }
262
263            dv.x1 = dv.x2;
264            dv.y1 = dv.y2;
265            dv.lcurr = dv.lnext;
266            dv.lnext = m_src_vertices[dv.idx].len;
267
268            ++dv.idx;
269            if(dv.idx >= m_src_vertices.size()) dv.idx = 0;
270
271            v = &m_src_vertices[dv.idx];
272            dv.x2 = v->x;
273            dv.y2 = v->y;
274
275            dv.curr = dv.next;
276            dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
277            dv.xb1 = dv.xb2;
278            dv.yb1 = dv.yb2;
279
280            switch(m_line_join)
281            {
282            case outline_no_join:
283                dv.flags = 3;
284                break;
285
286            case outline_miter_join:
287                dv.flags >>= 1;
288                dv.flags |= ((dv.curr.diagonal_quadrant() ==
289                              dv.next.diagonal_quadrant()) << 1);
290                if((dv.flags & 2) == 0)
291                {
292                    bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
293                }
294                break;
295
296            case outline_round_join:
297                dv.flags >>= 1;
298                dv.flags |= ((dv.curr.diagonal_quadrant() ==
299                              dv.next.diagonal_quadrant()) << 1);
300                break;
301
302            case outline_miter_accurate_join:
303                dv.flags = 0;
304                bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
305                break;
306            }
307        }
308    }
309
310
311
312
313    //----------------------------------------------------------------------------
314    template<class Renderer, class Coord>
315    void rasterizer_outline_aa<Renderer, Coord>::render(bool close_polygon)
316    {
317        m_src_vertices.close(close_polygon);
318        draw_vars dv;
319        const vertex_storage_type::value_type* v;
320        int x1;
321        int y1;
322        int x2;
323        int y2;
324        int lprev;
325
326        if(close_polygon)
327        {
328            if(m_src_vertices.size() >= 3)
329            {
330                dv.idx = 2;
331
332                v     = &m_src_vertices[m_src_vertices.size() - 1];
333                x1    = v->x;
334                y1    = v->y;
335                lprev = v->len;
336
337                v  = &m_src_vertices[0];
338                x2 = v->x;
339                y2 = v->y;
340                dv.lcurr = v->len;
341                line_parameters prev(x1, y1, x2, y2, lprev);
342
343                v = &m_src_vertices[1];
344                dv.x1    = v->x;
345                dv.y1    = v->y;
346                dv.lnext = v->len;
347                dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
348
349                v = &m_src_vertices[dv.idx];
350                dv.x2 = v->x;
351                dv.y2 = v->y;
352                dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
353
354                dv.xb1 = 0;
355                dv.yb1 = 0;
356                dv.xb2 = 0;
357                dv.yb2 = 0;
358
359                switch(m_line_join)
360                {
361                case outline_no_join:
362                    dv.flags = 3;
363                    break;
364
365                case outline_miter_join:
366                case outline_round_join:
367                    dv.flags =
368                            (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
369                        ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
370                    break;
371
372                case outline_miter_accurate_join:
373                    dv.flags = 0;
374                    break;
375                }
376
377                if((dv.flags & 1) == 0 && m_line_join != outline_round_join)
378                {
379                    bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
380                }
381
382                if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
383                {
384                    bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
385                }
386                draw(dv, 0, m_src_vertices.size());
387            }
388        }
389        else
390        {
391            switch(m_src_vertices.size())
392            {
393                case 0:
394                case 1:
395                    break;
396
397                case 2:
398                {
399                    v     = &m_src_vertices[0];
400                    x1    = v->x;
401                    y1    = v->y;
402                    lprev = v->len;
403                    v     = &m_src_vertices[1];
404                    x2    = v->x;
405                    y2    = v->y;
406                    line_parameters lp(x1, y1, x2, y2, lprev);
407                    if(m_round_cap)
408                    {
409                        m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
410                    }
411                    m_ren->line3(lp,
412                                 x1 + (y2 - y1),
413                                 y1 - (x2 - x1),
414                                 x2 + (y2 - y1),
415                                 y2 - (x2 - x1));
416                    if(m_round_cap)
417                    {
418                        m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1));
419                    }
420                }
421                break;
422
423                case 3:
424                {
425                    int x3, y3;
426                    int lnext;
427                    v     = &m_src_vertices[0];
428                    x1    = v->x;
429                    y1    = v->y;
430                    lprev = v->len;
431                    v     = &m_src_vertices[1];
432                    x2    = v->x;
433                    y2    = v->y;
434                    lnext = v->len;
435                    v     = &m_src_vertices[2];
436                    x3    = v->x;
437                    y3    = v->y;
438                    line_parameters lp1(x1, y1, x2, y2, lprev);
439                    line_parameters lp2(x2, y2, x3, y3, lnext);
440
441                    if(m_round_cap)
442                    {
443                        m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
444                    }
445
446                    if(m_line_join == outline_round_join)
447                    {
448                        m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
449                                          x2 + (y2 - y1), y2 - (x2 - x1));
450
451                        m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1),
452                                           x2 + (y3 - y2), y2 - (x3 - x2));
453
454                        m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2),
455                                          x3 + (y3 - y2), y3 - (x3 - x2));
456                    }
457                    else
458                    {
459                        bisectrix(lp1, lp2, &dv.xb1, &dv.yb1);
460                        m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
461                                          dv.xb1,         dv.yb1);
462
463                        m_ren->line3(lp2, dv.xb1,         dv.yb1,
464                                          x3 + (y3 - y2), y3 - (x3 - x2));
465                    }
466                    if(m_round_cap)
467                    {
468                        m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2));
469                    }
470                }
471                break;
472
473                default:
474                {
475                    dv.idx = 3;
476
477                    v     = &m_src_vertices[0];
478                    x1    = v->x;
479                    y1    = v->y;
480                    lprev = v->len;
481
482                    v  = &m_src_vertices[1];
483                    x2 = v->x;
484                    y2 = v->y;
485                    dv.lcurr = v->len;
486                    line_parameters prev(x1, y1, x2, y2, lprev);
487
488                    v = &m_src_vertices[2];
489                    dv.x1    = v->x;
490                    dv.y1    = v->y;
491                    dv.lnext = v->len;
492                    dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
493
494                    v = &m_src_vertices[dv.idx];
495                    dv.x2 = v->x;
496                    dv.y2 = v->y;
497                    dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
498
499                    dv.xb1 = 0;
500                    dv.yb1 = 0;
501                    dv.xb2 = 0;
502                    dv.yb2 = 0;
503
504                    switch(m_line_join)
505                    {
506                    case outline_no_join:
507                        dv.flags = 3;
508                        break;
509
510                    case outline_miter_join:
511                    case outline_round_join:
512                        dv.flags =
513                                (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
514                            ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
515                        break;
516
517                    case outline_miter_accurate_join:
518                        dv.flags = 0;
519                        break;
520                    }
521
522                    if(m_round_cap)
523                    {
524                        m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
525                    }
526                    if((dv.flags & 1) == 0)
527                    {
528                        if(m_line_join == outline_round_join)
529                        {
530                            m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
531                                               x2 + (y2 - y1), y2 - (x2 - x1));
532                            m_ren->pie(prev.x2, prev.y2,
533                                       x2 + (y2 - y1), y2 - (x2 - x1),
534                                       dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
535                                       dv.curr.y1 - (dv.curr.x2 - dv.curr.x1));
536                        }
537                        else
538                        {
539                            bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
540                            m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
541                                               dv.xb1,         dv.yb1);
542                        }
543                    }
544                    else
545                    {
546                        m_ren->line1(prev,
547                                     x1 + (y2 - y1),
548                                     y1 - (x2 - x1));
549                    }
550                    if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
551                    {
552                        bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
553                    }
554
555                    draw(dv, 1, m_src_vertices.size() - 2);
556
557                    if((dv.flags & 1) == 0)
558                    {
559                        if(m_line_join == outline_round_join)
560                        {
561                            m_ren->line3(dv.curr,
562                                         dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
563                                         dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
564                                         dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
565                                         dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
566                        }
567                        else
568                        {
569                            m_ren->line3(dv.curr, dv.xb1, dv.yb1,
570                                         dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
571                                         dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
572                        }
573                    }
574                    else
575                    {
576                        m_ren->line2(dv.curr,
577                                     dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
578                                     dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
579                    }
580                    if(m_round_cap)
581                    {
582                        m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2,
583                                       dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
584                                       dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
585                    }
586
587                }
588                break;
589            }
590        }
591        m_src_vertices.remove_all();
592    }
593
594
595}
596
597
598#endif
599
600