fix crash when copy'ing latent plugins
[ardour.git] / libs / canvas / polygon.cc
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "canvas/polygon.h"
21
22 using namespace ArdourCanvas;
23
24 Polygon::Polygon (Canvas* c)
25         : PolyItem (c)
26         , multiple (0)
27         , constant (0)
28         , cached_size (0)
29 {
30 }
31
32 Polygon::Polygon (Item* parent)
33         : PolyItem (parent)
34         , multiple (0)
35         , constant (0)
36         , cached_size (0)
37 {
38 }
39
40 Polygon::~Polygon ()
41 {
42         delete [] multiple;
43         delete [] constant;
44 }
45
46 void
47 Polygon::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
48 {
49         if (_outline || _fill) {
50                 render_path (area, context);
51
52                 if (!_points.empty ()) {
53                         /* close path */
54                         Duple p = item_to_window (Duple (_points.front().x, _points.front().y));
55                         context->line_to (p.x, p.y);
56                 }
57
58         }
59
60         if (_outline) {
61                 setup_outline_context (context);
62                 if (_fill) {
63                         context->stroke_preserve ();
64                 } else {
65                         context->stroke ();
66                 }
67         }
68
69         if (_fill) {
70                 setup_fill_context (context);
71                 context->fill ();
72         }
73 }
74
75 void
76 Polygon::cache_shape_computation () const
77 {
78         Points::size_type npoints = _points.size();
79
80         if (npoints == 0) {
81                 return;
82         }
83
84         Points::size_type i;
85         Points::size_type j = npoints -1;
86
87         if (cached_size < npoints) {
88                 cached_size = npoints;
89                 delete [] multiple;
90                 multiple = new float[cached_size];
91                 delete [] constant;
92                 constant = new float[cached_size];
93         }
94
95         for (i = 0; i < npoints; i++) {
96                 if (_points[j].y == _points[i].y) {
97                         constant[i] = _points[i].x;
98                         multiple[i] = 0;
99                 } else {
100                         constant[i] = _points[i].x-(_points[i].y*_points[j].x)/(_points[j].y-_points[i].y)+(_points[i].y*_points[i].x)/(_points[j].y-_points[i].y);
101                         multiple[i] = (_points[j].x-_points[i].x)/(_points[j].y-_points[i].y);
102                 }
103
104                 j = i;
105         }
106 }
107
108 bool
109 Polygon::covers (Duple const & point) const
110 {
111         Duple p = window_to_item (point);
112
113         Points::size_type npoints = _points.size();
114
115         if (npoints == 0) {
116                 return false;
117         }
118
119         Points::size_type i;
120         Points::size_type j = npoints -1;
121         bool oddNodes = false;
122
123         if (_bounding_box_dirty) {
124                 compute_bounding_box ();
125         }
126
127         for (i = 0; i < npoints; i++) {
128                 if (((_points[i].y < p.y && _points[j].y >= p.y) || (_points[j].y < p.y && _points[i].y >= p.y))) {
129                         oddNodes ^= (p.y * multiple[i] + constant[i] < p.x);
130                 }
131                 j = i;
132         }
133
134         return oddNodes;
135 }
136
137 void
138 Polygon::compute_bounding_box () const
139 {
140         PolyItem::compute_bounding_box ();
141         cache_shape_computation ();
142 }
143