rays 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +5 -5
  2. data/.doc/ext/rays/bitmap.cpp +22 -76
  3. data/.doc/ext/rays/bounds.cpp +95 -125
  4. data/.doc/ext/rays/color.cpp +224 -45
  5. data/.doc/ext/rays/color_space.cpp +137 -45
  6. data/.doc/ext/rays/defs.cpp +183 -0
  7. data/.doc/ext/rays/font.cpp +39 -21
  8. data/.doc/ext/rays/image.cpp +26 -37
  9. data/.doc/ext/rays/matrix.cpp +186 -29
  10. data/.doc/ext/rays/native.cpp +12 -6
  11. data/.doc/ext/rays/noise.cpp +53 -0
  12. data/.doc/ext/rays/painter.cpp +120 -308
  13. data/.doc/ext/rays/point.cpp +82 -77
  14. data/.doc/ext/rays/polygon.cpp +287 -0
  15. data/.doc/ext/rays/polygon_line.cpp +96 -0
  16. data/.doc/ext/rays/polyline.cpp +161 -0
  17. data/.doc/ext/rays/rays.cpp +0 -13
  18. data/.doc/ext/rays/shader.cpp +83 -9
  19. data/README.md +1 -1
  20. data/Rakefile +21 -9
  21. data/VERSION +1 -1
  22. data/ext/rays/bitmap.cpp +22 -80
  23. data/ext/rays/bounds.cpp +100 -128
  24. data/ext/rays/color.cpp +232 -51
  25. data/ext/rays/color_space.cpp +140 -46
  26. data/ext/rays/defs.cpp +183 -0
  27. data/ext/rays/defs.h +26 -2
  28. data/ext/rays/extconf.rb +1 -2
  29. data/ext/rays/font.cpp +39 -22
  30. data/ext/rays/image.cpp +27 -39
  31. data/ext/rays/matrix.cpp +198 -30
  32. data/ext/rays/native.cpp +12 -6
  33. data/ext/rays/noise.cpp +55 -0
  34. data/ext/rays/painter.cpp +129 -315
  35. data/ext/rays/point.cpp +89 -81
  36. data/ext/rays/polygon.cpp +301 -0
  37. data/ext/rays/polygon_line.cpp +99 -0
  38. data/ext/rays/polyline.cpp +170 -0
  39. data/ext/rays/rays.cpp +0 -14
  40. data/ext/rays/shader.cpp +84 -9
  41. data/include/rays.h +10 -2
  42. data/include/rays/bitmap.h +14 -26
  43. data/include/rays/bounds.h +21 -4
  44. data/include/rays/color.h +25 -14
  45. data/include/rays/color_space.h +11 -8
  46. data/include/rays/coord.h +114 -0
  47. data/include/rays/debug.h +22 -0
  48. data/include/rays/defs.h +3 -0
  49. data/include/rays/font.h +4 -4
  50. data/include/rays/image.h +11 -17
  51. data/include/rays/matrix.h +50 -24
  52. data/include/rays/noise.h +42 -0
  53. data/include/rays/opengl.h +2 -50
  54. data/include/rays/painter.h +57 -99
  55. data/include/rays/point.h +44 -51
  56. data/include/rays/polygon.h +164 -0
  57. data/include/rays/polyline.h +65 -0
  58. data/include/rays/rays.h +3 -0
  59. data/include/rays/ruby.h +7 -1
  60. data/include/rays/ruby/bounds.h +1 -1
  61. data/include/rays/ruby/color.h +1 -1
  62. data/include/rays/ruby/color_space.h +1 -1
  63. data/include/rays/ruby/font.h +1 -1
  64. data/include/rays/ruby/matrix.h +1 -1
  65. data/include/rays/ruby/point.h +1 -1
  66. data/include/rays/ruby/polygon.h +52 -0
  67. data/include/rays/ruby/polyline.h +41 -0
  68. data/include/rays/ruby/shader.h +1 -1
  69. data/include/rays/shader.h +36 -8
  70. data/lib/rays.rb +6 -1
  71. data/lib/rays/bitmap.rb +0 -15
  72. data/lib/rays/bounds.rb +17 -23
  73. data/lib/rays/color.rb +20 -47
  74. data/lib/rays/color_space.rb +13 -13
  75. data/lib/rays/image.rb +2 -6
  76. data/lib/rays/matrix.rb +28 -0
  77. data/lib/rays/module.rb +4 -19
  78. data/lib/rays/painter.rb +60 -97
  79. data/lib/rays/point.rb +13 -21
  80. data/lib/rays/polygon.rb +50 -0
  81. data/lib/rays/polygon_line.rb +36 -0
  82. data/lib/rays/polyline.rb +32 -0
  83. data/lib/rays/shader.rb +20 -1
  84. data/rays.gemspec +5 -7
  85. data/src/bitmap.h +36 -0
  86. data/src/bounds.cpp +74 -11
  87. data/src/color.cpp +58 -23
  88. data/src/color_space.cpp +50 -32
  89. data/src/color_space.h +22 -0
  90. data/src/coord.cpp +170 -0
  91. data/src/coord.h +35 -0
  92. data/src/font.cpp +118 -0
  93. data/src/font.h +64 -0
  94. data/src/frame_buffer.cpp +37 -71
  95. data/src/frame_buffer.h +4 -4
  96. data/src/image.cpp +171 -97
  97. data/src/image.h +25 -0
  98. data/src/ios/bitmap.mm +107 -105
  99. data/src/ios/font.mm +48 -60
  100. data/src/ios/helper.h +2 -2
  101. data/src/ios/opengl.mm +19 -4
  102. data/src/ios/rays.mm +3 -0
  103. data/src/matrix.cpp +111 -26
  104. data/src/matrix.h +30 -0
  105. data/src/noise.cpp +74 -0
  106. data/src/opengl.cpp +9 -27
  107. data/src/opengl.h +37 -0
  108. data/src/osx/bitmap.mm +111 -106
  109. data/src/osx/font.mm +48 -61
  110. data/src/osx/helper.h +2 -2
  111. data/src/osx/opengl.mm +19 -83
  112. data/src/osx/rays.mm +3 -0
  113. data/src/painter.cpp +780 -696
  114. data/src/painter.h +24 -0
  115. data/src/point.cpp +140 -119
  116. data/src/polygon.cpp +1100 -0
  117. data/src/polygon.h +32 -0
  118. data/src/polyline.cpp +158 -0
  119. data/src/polyline.h +67 -0
  120. data/src/render_buffer.cpp +11 -4
  121. data/src/render_buffer.h +2 -2
  122. data/src/shader.cpp +163 -106
  123. data/src/shader.h +38 -0
  124. data/src/shader_program.cpp +533 -0
  125. data/src/{program.h → shader_program.h} +28 -16
  126. data/src/shader_source.cpp +140 -0
  127. data/src/shader_source.h +52 -0
  128. data/src/texture.cpp +136 -160
  129. data/src/texture.h +65 -0
  130. data/src/win32/bitmap.cpp +62 -52
  131. data/src/win32/font.cpp +11 -13
  132. data/src/win32/font.h +24 -0
  133. data/src/win32/gdi.h +6 -6
  134. data/test/helper.rb +0 -3
  135. data/test/test_bitmap.rb +31 -7
  136. data/test/test_bounds.rb +36 -0
  137. data/test/test_color.rb +59 -19
  138. data/test/test_color_space.rb +95 -0
  139. data/test/test_image.rb +24 -20
  140. data/test/test_matrix.rb +106 -0
  141. data/test/test_painter.rb +92 -46
  142. data/test/test_painter_shape.rb +57 -0
  143. data/test/test_point.rb +21 -0
  144. data/test/test_polygon.rb +234 -0
  145. data/test/test_polygon_line.rb +167 -0
  146. data/test/test_polyline.rb +145 -0
  147. data/test/test_shader.rb +9 -9
  148. metadata +88 -67
  149. data/.doc/ext/rays/texture.cpp +0 -138
  150. data/ext/rays/texture.cpp +0 -149
  151. data/include/rays/ruby/texture.h +0 -41
  152. data/include/rays/texture.h +0 -71
  153. data/lib/rays/texture.rb +0 -24
  154. data/src/program.cpp +0 -648
  155. data/test/test_texture.rb +0 -27
@@ -0,0 +1,24 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_SRC_PAINTER_H__
4
+ #define __RAYS_SRC_PAINTER_H__
5
+
6
+
7
+ #include <rays/painter.h>
8
+ #include "opengl.h"
9
+
10
+
11
+ namespace Rays
12
+ {
13
+
14
+
15
+ void Painter_draw_polygon (
16
+ Painter* painter, GLenum mode, const Color& color,
17
+ const Coord3* points, size_t npoints,
18
+ const uint* indices = NULL, size_t nindices = 0);
19
+
20
+
21
+ }// Rays
22
+
23
+
24
+ #endif//EOH
@@ -2,88 +2,44 @@
2
2
 
3
3
 
4
4
  #include <math.h>
5
- #include <xot/string.h>
5
+ #include <glm/geometric.hpp>
6
+ #include <glm/gtx/rotate_vector.hpp>
7
+ #include <xot/util.h>
6
8
  #include "rays/exception.h"
9
+ #include "coord.h"
7
10
 
8
11
 
9
12
  namespace Rays
10
13
  {
11
14
 
12
15
 
13
- Coord2&
14
- Coord2::reset (coord value)
15
- {
16
- return reset(value, value);
17
- }
18
-
19
- Coord2&
20
- Coord2::reset (coord x, coord y)
21
- {
22
- this->x = x;
23
- this->y = y;
24
- return *this;
25
- }
26
-
27
- coord&
28
- Coord2::operator [] (size_t index)
29
- {
30
- if (index >= 2)
31
- argument_error(__FILE__, __LINE__);
32
-
33
- return array[index];
34
- }
35
-
36
- const coord&
37
- Coord2::operator [] (size_t index) const
16
+ Point::Point (coord value)
38
17
  {
39
- return const_cast<Coord2*>(this)->operator[](index);
18
+ reset(value);
40
19
  }
41
20
 
42
-
43
- Coord3&
44
- Coord3::reset (coord value)
21
+ Point::Point (coord x, coord y, coord z)
45
22
  {
46
- return reset(value, value, 0);
23
+ reset(x, y, z);
47
24
  }
48
25
 
49
- Coord3&
50
- Coord3::reset (coord x, coord y, coord z)
26
+ Point
27
+ Point::dup () const
51
28
  {
52
- this->x = x;
53
- this->y = y;
54
- this->z = z;
55
29
  return *this;
56
30
  }
57
31
 
58
- coord&
59
- Coord3::operator [] (size_t index)
60
- {
61
- if (index >= 3)
62
- argument_error(__FILE__, __LINE__);
63
-
64
- return array[index];
65
- }
66
-
67
- const coord&
68
- Coord3::operator [] (size_t index) const
69
- {
70
- return const_cast<Coord3*>(this)->operator[](index);
71
- }
72
-
73
-
74
- Point::Point (coord value)
75
- {
76
- reset(value);
77
- }
78
-
79
- Point::Point (coord x, coord y, coord z)
32
+ Point&
33
+ Point::reset (coord value)
80
34
  {
81
- reset(x, y, z);
35
+ Super::reset(value);
36
+ return *this;
82
37
  }
83
38
 
84
- Point
85
- Point::dup () const
39
+ Point&
40
+ Point::reset (coord x, coord y, coord z)
86
41
  {
42
+ Super::reset(x, y, z);
87
43
  return *this;
88
44
  }
89
45
 
@@ -95,7 +51,7 @@ namespace Rays
95
51
  }
96
52
 
97
53
  Point&
98
- Point::move_to (const Point& point)
54
+ Point::move_to (const This& point)
99
55
  {
100
56
  reset(point.x, point.y, point.z);
101
57
  return *this;
@@ -109,146 +65,211 @@ namespace Rays
109
65
  }
110
66
 
111
67
  Point&
112
- Point::move_by (const Point& point)
68
+ Point::move_by (const This& point)
113
69
  {
114
70
  reset(this->x + point.x, this->y + point.y, this->z + point.z);
115
71
  return *this;
116
72
  }
117
73
 
74
+ void
75
+ Point::rotate (float degree)
76
+ {
77
+ to_glm(*this) = glm::rotateZ(to_glm(*this), (float) Xot::deg2rad(degree));
78
+ }
79
+
118
80
  coord
119
81
  Point::length () const
120
82
  {
121
- return sqrt(x * x + y * y + z * z);
83
+ return glm::length(to_glm(*this));
122
84
  }
123
85
 
124
- void
125
- Point::normalize ()
86
+ Point
87
+ Point::normal () const
126
88
  {
127
- coord len = length();
128
- if (len == 0)
89
+ if (dot(*this, *this) == 0)
129
90
  invalid_state_error(__FILE__, __LINE__);
130
91
 
131
- *this /= len;
92
+ return to_rays<Point>(glm::normalize(to_glm(*this)));
93
+ }
94
+
95
+ void
96
+ Point::normalize ()
97
+ {
98
+ *this = normal();
132
99
  }
133
100
 
134
101
  Point
135
- Point::normal () const
102
+ Point::operator - () const
136
103
  {
137
- Point t = *this;
138
- t.normalize();
139
- return t;
104
+ return to_rays<Point>(-to_glm(*this));
140
105
  }
141
106
 
142
- String
143
- Point::inspect () const
107
+ Point&
108
+ Point::operator += (coord rhs)
144
109
  {
145
- return Xot::stringf("x=%f y=%f z=%f", x, y, z);
110
+ to_glm(*this) += rhs;
111
+ return *this;
146
112
  }
147
113
 
148
- Point
149
- Point::operator - () const
114
+ Point&
115
+ Point::operator += (const This& rhs)
150
116
  {
151
- return Point(-x, -y, -z);
117
+ to_glm(*this) += to_glm(rhs);
118
+ return *this;
152
119
  }
153
120
 
154
121
  Point&
155
- Point::operator += (const Point& rhs)
122
+ Point::operator -= (coord rhs)
156
123
  {
157
- x += rhs.x;
158
- y += rhs.y;
159
- z += rhs.z;
124
+ to_glm(*this) -= rhs;
160
125
  return *this;
161
126
  }
162
127
 
163
128
  Point&
164
- Point::operator -= (const Point& rhs)
129
+ Point::operator -= (const This& rhs)
165
130
  {
166
- x -= rhs.x;
167
- y -= rhs.y;
168
- z -= rhs.z;
131
+ to_glm(*this) -= to_glm(rhs);
169
132
  return *this;
170
133
  }
171
134
 
172
135
  Point&
173
- Point::operator *= (const Point& rhs)
136
+ Point::operator *= (coord rhs)
174
137
  {
175
- x *= rhs.x;
176
- y *= rhs.y;
177
- z *= rhs.z;
138
+ to_glm(*this) *= rhs;
178
139
  return *this;
179
140
  }
180
141
 
181
142
  Point&
182
- Point::operator /= (const Point& rhs)
143
+ Point::operator *= (const This& rhs)
183
144
  {
184
- x /= rhs.x;
185
- y /= rhs.y;
186
- z /= rhs.z;
145
+ to_glm(*this) *= to_glm(rhs);
187
146
  return *this;
188
147
  }
189
148
 
190
149
  Point&
191
150
  Point::operator /= (coord rhs)
192
151
  {
193
- x /= rhs;
194
- y /= rhs;
195
- z /= rhs;
152
+ if (rhs == 0)
153
+ argument_error(__FILE__, __LINE__);
154
+
155
+ to_glm(*this) /= rhs;
156
+ return *this;
157
+ }
158
+
159
+ Point&
160
+ Point::operator /= (const This& rhs)
161
+ {
162
+ if (rhs.x == 0 || rhs.y == 0 || rhs.z == 0)
163
+ argument_error(__FILE__, __LINE__);
164
+
165
+ to_glm(*this) /= to_glm(rhs);
196
166
  return *this;
197
167
  }
198
168
 
199
169
  bool
200
170
  operator == (const Point& lhs, const Point& rhs)
201
171
  {
202
- return
203
- lhs.x == rhs.x &&
204
- lhs.y == rhs.y &&
205
- lhs.z == rhs.z;
172
+ return to_glm(lhs) == to_glm(rhs);
206
173
  }
207
174
 
208
175
  bool
209
176
  operator != (const Point& lhs, const Point& rhs)
210
177
  {
211
- return !operator==(lhs, rhs);
178
+ return to_glm(lhs) != to_glm(rhs);
179
+ }
180
+
181
+ Point
182
+ operator + (coord lhs, const Point& rhs)
183
+ {
184
+ return to_rays<Point>(lhs + to_glm(rhs));
185
+ }
186
+
187
+ Point
188
+ operator + (const Point& lhs, coord rhs)
189
+ {
190
+ return to_rays<Point>(to_glm(lhs) + rhs);
212
191
  }
213
192
 
214
193
  Point
215
194
  operator + (const Point& lhs, const Point& rhs)
216
195
  {
217
- Point t = lhs;
218
- t += rhs;
219
- return t;
196
+ return to_rays<Point>(to_glm(lhs) + to_glm(rhs));
197
+ }
198
+
199
+ Point
200
+ operator - (coord lhs, const Point& rhs)
201
+ {
202
+ return to_rays<Point>(lhs - to_glm(rhs));
203
+ }
204
+
205
+ Point
206
+ operator - (const Point& lhs, coord rhs)
207
+ {
208
+ return to_rays<Point>(to_glm(lhs) - rhs);
220
209
  }
221
210
 
222
211
  Point
223
212
  operator - (const Point& lhs, const Point& rhs)
224
213
  {
225
- Point t = lhs;
226
- t -= rhs;
227
- return t;
214
+ return to_rays<Point>(to_glm(lhs) - to_glm(rhs));
215
+ }
216
+
217
+ Point
218
+ operator * (coord lhs, const Point& rhs)
219
+ {
220
+ return to_rays<Point>(lhs * to_glm(rhs));
221
+ }
222
+
223
+ Point
224
+ operator * (const Point& lhs, coord rhs)
225
+ {
226
+ return to_rays<Point>(to_glm(lhs) * rhs);
228
227
  }
229
228
 
230
229
  Point
231
230
  operator * (const Point& lhs, const Point& rhs)
232
231
  {
233
- Point t = lhs;
234
- t *= rhs;
235
- return t;
232
+ return to_rays<Point>(to_glm(lhs) * to_glm(rhs));
236
233
  }
237
234
 
238
235
  Point
239
- operator / (const Point& lhs, const Point& rhs)
236
+ operator / (coord lhs, const Point& rhs)
240
237
  {
241
- Point t = lhs;
242
- t /= rhs;
243
- return t;
238
+ if (rhs.x == 0 || rhs.y == 0 || rhs.z == 0)
239
+ argument_error(__FILE__, __LINE__);
240
+
241
+ return to_rays<Point>(lhs / to_glm(rhs));
244
242
  }
245
243
 
246
244
  Point
247
245
  operator / (const Point& lhs, coord rhs)
248
246
  {
249
- Point t = lhs;
250
- t /= rhs;
251
- return t;
247
+ if (rhs == 0)
248
+ argument_error(__FILE__, __LINE__);
249
+
250
+ return to_rays<Point>(to_glm(lhs) / rhs);
251
+ }
252
+
253
+ Point
254
+ operator / (const Point& lhs, const Point& rhs)
255
+ {
256
+ if (rhs.x == 0 || rhs.y == 0 || rhs.z == 0)
257
+ argument_error(__FILE__, __LINE__);
258
+
259
+ return to_rays<Point>(to_glm(lhs) / to_glm(rhs));
260
+ }
261
+
262
+
263
+ coord
264
+ dot (const Point& p1, const Point& p2)
265
+ {
266
+ return glm::dot(to_glm(p1), to_glm(p2));
267
+ }
268
+
269
+ Point
270
+ cross (const Point& p1, const Point& p2)
271
+ {
272
+ return to_rays<Point>(glm::cross(to_glm(p1), to_glm(p2)));
252
273
  }
253
274
 
254
275
 
@@ -0,0 +1,1100 @@
1
+ #include "polygon.h"
2
+
3
+
4
+ #include <math.h>
5
+ #include <assert.h>
6
+ #include <utility>
7
+ #include <poly2tri.h>
8
+ #include "xot/util.h"
9
+ #include "rays/color.h"
10
+ #include "rays/exception.h"
11
+ #include "rays/debug.h"
12
+ #include "polyline.h"
13
+ #include "painter.h"
14
+
15
+
16
+ using namespace ClipperLib;
17
+
18
+
19
+ namespace Rays
20
+ {
21
+
22
+
23
+ static inline p2t::Point
24
+ to_poly2tri (const Point& point)
25
+ {
26
+ return p2t::Point(point.x, point.y);
27
+ }
28
+
29
+ static inline Point
30
+ from_poly2tri (const p2t::Point& point)
31
+ {
32
+ return Point(point.x, point.y);
33
+ }
34
+
35
+
36
+ struct Polygon::Data
37
+ {
38
+
39
+ LineList lines;
40
+
41
+ virtual ~Data ()
42
+ {
43
+ }
44
+
45
+ void append (const Polyline& polyline, bool hole = false)
46
+ {
47
+ if (polyline.empty())
48
+ return;
49
+
50
+ lines.emplace_back(Line(polyline, hole));
51
+ }
52
+
53
+ void append (const Line& line)
54
+ {
55
+ if (line.empty())
56
+ return;
57
+
58
+ lines.emplace_back(line);
59
+ }
60
+
61
+ bool triangulate (TrianglePointList* triangles) const
62
+ {
63
+ assert(triangles);
64
+
65
+ triangles->clear();
66
+
67
+ if (!can_triangulate())
68
+ return false;
69
+
70
+ size_t npoint = count_points();
71
+ if (npoint <= 0)
72
+ return true;
73
+
74
+ std::unique_ptr<p2t::CDT> cdt;
75
+ std::vector<p2t::Point> points;
76
+ std::vector<p2t::Point*> pointers;
77
+
78
+ points.reserve(npoint);
79
+ for (const auto& line : lines)
80
+ {
81
+ pointers.clear();
82
+ pointers.reserve(line.size());
83
+ for (const auto& point : line)
84
+ {
85
+ points.emplace_back(to_poly2tri(point));
86
+ pointers.emplace_back(&points.back());
87
+ }
88
+
89
+ if (!line.hole())
90
+ {
91
+ if (cdt) triangulate(triangles, cdt.get());
92
+ cdt.reset(new p2t::CDT(pointers));
93
+ }
94
+ else if (cdt)
95
+ cdt->AddHole(pointers);
96
+ }
97
+
98
+ if (cdt) triangulate(triangles, cdt.get());
99
+
100
+ return true;
101
+ }
102
+
103
+ virtual void fill (Painter* painter, const Color& color) const = 0;
104
+
105
+ virtual void stroke (
106
+ const Polygon& polygon, Painter* painter, const Color& color) const
107
+ {
108
+ assert(painter && color);
109
+
110
+ coord stroke_width = painter->stroke_width();
111
+ if (stroke_width > 0)
112
+ stroke_with_width(polygon, painter, color, stroke_width);
113
+ else
114
+ stroke_without_width(painter, color);
115
+ }
116
+
117
+ private:
118
+
119
+ bool can_triangulate () const
120
+ {
121
+ for (const auto& line : lines)
122
+ {
123
+ if (line.loop() && !line.hole() && !line.empty())
124
+ return true;
125
+ }
126
+ return false;
127
+ }
128
+
129
+ size_t count_points () const
130
+ {
131
+ size_t count = 0;
132
+ for (const auto& line : lines)
133
+ count += line.size();
134
+ return count;
135
+ }
136
+
137
+ void triangulate (TrianglePointList* triangles, p2t::CDT* cdt) const
138
+ {
139
+ assert(triangles && cdt);
140
+
141
+ cdt->Triangulate();
142
+
143
+ for (auto* triangle : cdt->GetTriangles())
144
+ {
145
+ for (int i = 0; i < 3; ++i)
146
+ triangles->emplace_back(from_poly2tri(*triangle->GetPoint(i)));
147
+ }
148
+ }
149
+
150
+ void stroke_with_width (
151
+ const Polygon& polygon, Painter* painter,
152
+ const Color& color, coord stroke_width) const
153
+ {
154
+ assert(painter && color && stroke_width > 0);
155
+
156
+ if (!polygon || polygon.empty()) return;
157
+
158
+ bool has_loop = false;
159
+ for (const auto& polyline : polygon)
160
+ {
161
+ if (!polyline || polyline.empty())
162
+ continue;
163
+
164
+ if (polyline.loop())
165
+ {
166
+ has_loop = true;
167
+ continue;
168
+ }
169
+
170
+ Polygon stroke;
171
+ if (!polyline.expand(&stroke, stroke_width / 2))
172
+ continue;
173
+
174
+ Polygon_fill(stroke, painter, color);
175
+ }
176
+
177
+ if (has_loop)
178
+ {
179
+ Polygon hole;
180
+ if (polygon.expand(&hole, -stroke_width))
181
+ Polygon_fill(polygon - hole, painter, color);
182
+ }
183
+ }
184
+
185
+ void stroke_without_width (Painter* painter, const Color& color) const
186
+ {
187
+ assert(painter && color);
188
+
189
+ for (const auto& line : lines)
190
+ {
191
+ Painter_draw_polygon(
192
+ painter, line.loop() ? GL_LINE_LOOP : GL_LINE_STRIP, color,
193
+ &line[0], line.size());
194
+ }
195
+ }
196
+
197
+ };// Polygon::Data
198
+
199
+
200
+ #if 0
201
+ static String
202
+ path2str (const Path& path)
203
+ {
204
+ String s;
205
+ for (const auto& point : path)
206
+ {
207
+ if (!s.empty()) s += ", ";
208
+
209
+ Point p = from_clipper(point);
210
+ s += Xot::stringf("[%d,%d]", p.x, p.y);
211
+ }
212
+ return s;
213
+ }
214
+
215
+ static void
216
+ dout_node (const PolyNode& node)
217
+ {
218
+ doutln(
219
+ "path(open: %d, hole: %d, Contour: %s)",
220
+ (int) node.IsOpen(),
221
+ (int) node.IsHole(),
222
+ path2str(node.Contour).c_str());
223
+ }
224
+
225
+ static void
226
+ dout_tree (const PolyNode& node, int level = 0)
227
+ {
228
+ for (int i = 0; i < level; ++i) dout(" ");
229
+ dout_node(node);
230
+
231
+ for (const auto* child : node.Childs)
232
+ dout_tree(*child, level + 1);
233
+ }
234
+ #endif
235
+
236
+ static uint
237
+ get_nsegment (
238
+ uint nsegment, uint nsegment_min, float angle_from, float angle_to)
239
+ {
240
+ float angle = angle_to - angle_from;
241
+ assert(0 <= angle && angle <= 360);
242
+
243
+ if (nsegment <= 0)
244
+ nsegment = 32;
245
+ else if (nsegment < nsegment_min)
246
+ nsegment = nsegment_min;
247
+
248
+ nsegment *= angle / 360;
249
+ return nsegment > 0 ? nsegment : 1;
250
+ }
251
+
252
+ static void
253
+ add_polygon_to_clipper (
254
+ Clipper* clipper, const Polygon& polygon, PolyType type)
255
+ {
256
+ assert(clipper);
257
+
258
+ Path path;
259
+ for (const auto& line : polygon)
260
+ {
261
+ if (!line) continue;
262
+
263
+ Polyline_get_path(&path, line, line.hole());
264
+ if (path.empty()) continue;
265
+
266
+ clipper->AddPath(path, type, line.loop());
267
+ }
268
+ }
269
+
270
+ static EndType
271
+ get_end_type (const Polyline& polyline, bool fill)
272
+ {
273
+ if (polyline.loop())
274
+ return fill ? etClosedPolygon : etClosedLine;
275
+ else
276
+ return etOpenButt;
277
+ }
278
+
279
+ static bool
280
+ add_polyline_to_offsetter (
281
+ ClipperOffset* offsetter, const Polyline& polyline, bool hole, bool fill)
282
+ {
283
+ assert(offsetter);
284
+
285
+ if (!polyline) return false;
286
+
287
+ Path path;
288
+ Polyline_get_path(&path, polyline, hole);
289
+ offsetter->AddPath(path, jtMiter, get_end_type(polyline, fill));
290
+ return true;
291
+ }
292
+
293
+ static bool
294
+ add_polygon_to_offsetter (ClipperOffset* offsetter, const Polygon& polygon)
295
+ {
296
+ assert(offsetter);
297
+
298
+ bool added = false;
299
+ for (const auto& line : polygon.self->lines)
300
+ added |= add_polyline_to_offsetter(offsetter, line, line.hole(), true);
301
+ return added;
302
+ }
303
+
304
+ static bool
305
+ append_outline (Polygon* polygon, const PolyNode& node)
306
+ {
307
+ assert(polygon);
308
+
309
+ if (node.Contour.empty() || node.IsHole())
310
+ return false;
311
+
312
+ Polyline polyline;
313
+ Polyline_create(&polyline, node.Contour, !node.IsOpen(), false);
314
+ if (!polyline)
315
+ return false;
316
+
317
+ polygon->self->append(polyline, false);
318
+ return true;
319
+ }
320
+
321
+ static void
322
+ append_hole (Polygon* polygon, const PolyNode& node)
323
+ {
324
+ assert(polygon);
325
+
326
+ for (const auto* child : node.Childs)
327
+ {
328
+ if (!child->IsHole())
329
+ return;
330
+
331
+ Polyline polyline;
332
+ Polyline_create(&polyline, child->Contour, !child->IsOpen(), true);
333
+ if (!polyline)
334
+ continue;
335
+
336
+ polygon->self->append(polyline, true);
337
+ }
338
+ }
339
+
340
+ static void
341
+ get_polygon (Polygon* polygon, const PolyNode& node)
342
+ {
343
+ assert(polygon);
344
+
345
+ if (append_outline(polygon, node))
346
+ append_hole(polygon, node);
347
+
348
+ for (const auto* child : node.Childs)
349
+ get_polygon(polygon, *child);
350
+ }
351
+
352
+ static Polygon
353
+ clip_polygons (const Polygon& subject, const Polygon& clip, ClipType type)
354
+ {
355
+ Clipper c;
356
+ c.StrictlySimple(true);
357
+
358
+ add_polygon_to_clipper(&c, subject, ptSubject);
359
+ add_polygon_to_clipper(&c, clip, ptClip);
360
+
361
+ PolyTree tree;
362
+ c.Execute(type, tree);
363
+ assert(tree.Contour.empty());
364
+
365
+ Polygon result;
366
+ get_polygon(&result, tree);
367
+
368
+ return result;
369
+ }
370
+
371
+ static bool
372
+ expand_polygon (Polygon* result, const Polygon& polygon, coord width)
373
+ {
374
+ if (width == 0)
375
+ return false;
376
+
377
+ ClipperOffset co;
378
+ if (!add_polygon_to_offsetter(&co, polygon))
379
+ return false;
380
+
381
+ PolyTree tree;
382
+ co.Execute(tree, to_clipper(width));
383
+ assert(tree.Contour.empty());
384
+
385
+ get_polygon(result, tree);
386
+ return true;
387
+ }
388
+
389
+ bool
390
+ Polyline_expand (Polygon* result, const Polyline& polyline, coord width)
391
+ {
392
+ if (width == 0)
393
+ return false;
394
+
395
+ ClipperOffset co;
396
+ if (!add_polyline_to_offsetter(&co, polyline, false, false))
397
+ return false;
398
+
399
+ PolyTree tree;
400
+ co.Execute(tree, to_clipper(width));
401
+ assert(tree.Contour.empty());
402
+
403
+ get_polygon(result, tree);
404
+ return true;
405
+ }
406
+
407
+
408
+ struct PolygonData : public Polygon::Data
409
+ {
410
+
411
+ mutable Polygon::TrianglePointList triangles;
412
+
413
+ void fill (Painter* painter, const Color& color) const
414
+ {
415
+ if (triangles.empty())
416
+ {
417
+ if (!triangulate(&triangles))
418
+ return;
419
+ }
420
+
421
+ Painter_draw_polygon(
422
+ painter, GL_TRIANGLES, color, &triangles[0], triangles.size());
423
+ }
424
+
425
+ };// PolygonData
426
+
427
+
428
+ struct RectData : public Polygon::Data
429
+ {
430
+
431
+ RectData (
432
+ coord x, coord y, coord width, coord height,
433
+ coord round_left_top, coord round_right_top,
434
+ coord round_left_bottom, coord round_right_bottom,
435
+ uint nsegment)
436
+ {
437
+ if (
438
+ round_left_top == 0 && round_right_top == 0 &&
439
+ round_left_bottom == 0 && round_right_bottom == 0)
440
+ {
441
+ setup_rect(x, y, width, height, nsegment);
442
+ }
443
+ else
444
+ {
445
+ setup_round_rect(
446
+ x, y, width, height,
447
+ round_left_top, round_right_top,
448
+ round_left_bottom, round_right_bottom,
449
+ nsegment);
450
+ }
451
+ }
452
+
453
+ void fill (Painter* painter, const Color& color) const
454
+ {
455
+ if (lines.size() != 1)
456
+ invalid_state_error(__FILE__, __LINE__);
457
+
458
+ const auto& outline = lines[0];
459
+ Painter_draw_polygon(
460
+ painter, GL_TRIANGLE_FAN, color, &outline[0], outline.size());
461
+ }
462
+
463
+ private:
464
+
465
+ struct RoundedCorner
466
+ {
467
+ coord x, y, offset_sign_x, offset_sign_y, round;
468
+ };
469
+
470
+ void setup_rect (
471
+ coord x, coord y, coord width, coord height,
472
+ uint nsegment)
473
+ {
474
+ const Point points[] = {
475
+ Point(x, y),
476
+ Point(x, y + height),
477
+ Point(x + width, y + height),
478
+ Point(x + width, y),
479
+ };
480
+ append(Polyline(points, 4, true));
481
+ }
482
+
483
+ void setup_round_rect (
484
+ coord x, coord y, coord width, coord height,
485
+ coord left_top, coord right_top, coord left_bottom, coord right_bottom,
486
+ uint nsegment)
487
+ {
488
+ assert(width != 0 && height != 0);
489
+ assert(
490
+ left_top != 0 || right_top != 0 ||
491
+ left_bottom != 0 || right_bottom != 0);
492
+
493
+ nsegment = get_nsegment(nsegment, 1, 0, 90);
494
+
495
+ fix_rounds(
496
+ &left_top, &right_top,
497
+ &left_bottom, &right_bottom,
498
+ width, height);
499
+
500
+ coord sign_x = width >= 0 ? +1 : -1;
501
+ coord sign_y = height >= 0 ? +1 : -1;
502
+ RoundedCorner corners[] =
503
+ {
504
+ {width, 0, -1, +1, right_top},
505
+ { 0, 0, +1, +1, left_top},
506
+ { 0, height, +1, -1, left_bottom},
507
+ {width, height, -1, -1, right_bottom}
508
+ };
509
+
510
+ size_t npoints = 0;
511
+ for (size_t i = 0; i < 4; ++i)
512
+ npoints += corners[i].round > 0 ? nsegment + 1 : 1;
513
+
514
+ std::unique_ptr<Point[]> points(new Point[npoints]);
515
+ Point* point = points.get();
516
+
517
+ for (size_t i = 0; i < 4; ++i)
518
+ {
519
+ point += setup_round(
520
+ point, x, y, corners[i], sign_x, sign_y, (M_PI / 2) * i, nsegment);
521
+ }
522
+
523
+ append(Polyline(points.get(), npoints, true));
524
+ }
525
+
526
+ void fix_rounds (
527
+ coord* left_top, coord* right_top,
528
+ coord* left_bottom, coord* right_bottom,
529
+ coord width, coord height)
530
+ {
531
+ assert(
532
+ left_top && right_top &&
533
+ left_bottom && right_bottom);
534
+
535
+ if (width < 0) width = -width;
536
+ if (height < 0) height = -height;
537
+
538
+ coord* rounds[] = {
539
+ left_top,
540
+ right_top,
541
+ right_bottom,
542
+ left_bottom,
543
+ left_top};
544
+ coord sizes[] = {width, height, width, height};
545
+
546
+ for (size_t i = 0; i < 4; ++i)
547
+ {
548
+ const coord& size = sizes[i];
549
+
550
+ coord* a = rounds[i];
551
+ coord* b = rounds[i + 1];
552
+ if (*a + *b <= size)
553
+ continue;
554
+
555
+ if (*a > *b)
556
+ std::swap(a, b);
557
+
558
+ if (*a * 2 > size)
559
+ *a = *b = size / 2;
560
+ else
561
+ *b = size - *a;
562
+ }
563
+ }
564
+
565
+ int setup_round (
566
+ Point* point, coord x, coord y, const RoundedCorner& corner,
567
+ coord sign_x, coord sign_y, float radian_offset, uint nsegment)
568
+ {
569
+ if (corner.round <= 0)
570
+ {
571
+ point->reset(x + corner.x, y + corner.y);
572
+ return 1;
573
+ }
574
+
575
+ coord offset_x = corner.x + corner.round * corner.offset_sign_x * sign_x;
576
+ coord offset_y = corner.y + corner.round * corner.offset_sign_y * sign_y;
577
+
578
+ for (uint seg = 0; seg <= nsegment; ++seg, ++point)
579
+ {
580
+ float pos = (float) seg / (float) nsegment;
581
+ float radian = radian_offset + pos * (M_PI / 2);
582
+ point->reset(
583
+ x + offset_x + cos(radian) * corner.round * sign_x,
584
+ y + offset_y - sin(radian) * corner.round * sign_y);
585
+ }
586
+ return nsegment + 1;
587
+ }
588
+
589
+ };// RectData
590
+
591
+
592
+ struct EllipseData : public PolygonData
593
+ {
594
+
595
+ typedef PolygonData Super;
596
+
597
+ GLenum mode = 0;
598
+
599
+ EllipseData (
600
+ coord x, coord y, coord width, coord height,
601
+ const Point& hole_size,
602
+ float angle_from, float angle_to,
603
+ uint nsegment)
604
+ {
605
+ normalize_angle(&angle_from, &angle_to);
606
+
607
+ if ((angle_to - angle_from) >= 360)
608
+ setup_ellipse(x, y, width, height, hole_size, nsegment);
609
+ else
610
+ {
611
+ setup_arc(
612
+ x, y, width, height, hole_size, angle_from, angle_to, nsegment);
613
+ }
614
+ }
615
+
616
+ void fill (Painter* painter, const Color& color) const
617
+ {
618
+ if (lines.size() <= 0)
619
+ invalid_state_error(__FILE__, __LINE__);
620
+
621
+ if (mode == 0)
622
+ {
623
+ Super::fill(painter, color);
624
+ return;
625
+ }
626
+
627
+ if (lines.size() >= 2)
628
+ invalid_state_error(__FILE__, __LINE__);
629
+
630
+ const auto& outline = lines[0];
631
+ Painter_draw_polygon(painter, mode, color, &outline[0], outline.size());
632
+ }
633
+
634
+ private:
635
+
636
+ void normalize_angle (float* angle_from, float* angle_to)
637
+ {
638
+ assert(angle_from && angle_to);
639
+
640
+ float& from = *angle_from;
641
+ float& to = *angle_to;
642
+
643
+ if (from > to)
644
+ std::swap(from, to);
645
+
646
+ if (to - from > 360)
647
+ to = from + 360;
648
+ }
649
+
650
+ void setup_ellipse (
651
+ coord x, coord y, coord width, coord height,
652
+ const Point& hole_size, uint nsegment)
653
+ {
654
+ assert(width != 0 && height != 0);
655
+
656
+ nsegment = get_nsegment(nsegment, 3, 0, 360);
657
+
658
+ bool has_hole = hole_size != 0;
659
+ float radian_from = Xot::deg2rad(0);
660
+ float radian_to = Xot::deg2rad(360);
661
+
662
+ if (!has_hole) mode = GL_TRIANGLE_FAN;
663
+
664
+ std::vector<Point> points;
665
+ points.reserve(nsegment);
666
+
667
+ for (uint seg = 0; seg < nsegment; ++seg)
668
+ {
669
+ points.emplace_back(make_ellipse_point(
670
+ x, y, width, height, radian_from, radian_to, nsegment, seg));
671
+ }
672
+ append(Polyline(&points[0], points.size(), true));
673
+
674
+ if (has_hole)
675
+ {
676
+ points.clear();
677
+
678
+ coord hole_x = x + (width - hole_size.x) / 2;
679
+ coord hole_y = y + (height - hole_size.y) / 2;
680
+ for (uint seg = 0; seg < nsegment; ++seg)
681
+ {
682
+ points.emplace_back(make_ellipse_point(
683
+ hole_x, hole_y, hole_size.x, hole_size.y,
684
+ radian_from, radian_to, nsegment, seg));
685
+ }
686
+ append(Polyline(&points[0], points.size(), true), true);
687
+ }
688
+ }
689
+
690
+ void setup_arc (
691
+ coord x, coord y, coord width, coord height,
692
+ const Point& hole_size, float angle_from, float angle_to,
693
+ uint nsegment)
694
+ {
695
+ assert(width != 0 && height != 0 && angle_from != angle_to);
696
+
697
+ nsegment = get_nsegment(nsegment, 3, angle_from, angle_to);
698
+
699
+ bool has_hole = hole_size != 0;
700
+ float radian_from = Xot::deg2rad(angle_from);
701
+ float radian_to = Xot::deg2rad(angle_to);
702
+ uint npoint = nsegment + 1;
703
+
704
+ std::vector<Point> points;
705
+ points.reserve(has_hole ? npoint * 2 : npoint + 1);
706
+
707
+ if (!has_hole)
708
+ {
709
+ points.emplace_back(Point(x + width / 2, y + height / 2));
710
+ mode = GL_TRIANGLE_FAN;
711
+ }
712
+
713
+ for (uint seg = 0; seg <= nsegment; ++seg)
714
+ {
715
+ points.emplace_back(make_ellipse_point(
716
+ x, y, width, height, radian_from, radian_to, nsegment, seg));
717
+ }
718
+
719
+ if (has_hole)
720
+ {
721
+ coord hole_x = x + (width - hole_size.x) / 2;
722
+ coord hole_y = y + (height - hole_size.y) / 2;
723
+ for (uint seg = 0; seg <= nsegment; ++seg)
724
+ {
725
+ points.emplace_back(make_ellipse_point(
726
+ hole_x, hole_y, hole_size.x, hole_size.y,
727
+ radian_from, radian_to, nsegment, nsegment - seg));
728
+ }
729
+ }
730
+
731
+ append(Polyline(&points[0], points.size(), true));
732
+ }
733
+
734
+ Point make_ellipse_point (
735
+ coord x, coord y, coord width, coord height,
736
+ float radian_from, float radian_to,
737
+ uint segment_max, uint segment_index)
738
+ {
739
+ float pos = (float) segment_index / (float) segment_max;
740
+ float radian = radian_from + (radian_to - radian_from) * pos;
741
+ float cos_ = (cos(radian) + 1) / 2.;
742
+ float sin_ = (-sin(radian) + 1) / 2.;
743
+ return Point(
744
+ x + width * cos_,
745
+ y + height * sin_);
746
+ }
747
+
748
+ };// EllipseData
749
+
750
+
751
+ Polygon
752
+ create_line (coord x1, coord y1, coord x2, coord y2)
753
+ {
754
+ const Point points[] = {
755
+ Point(x1, y1),
756
+ Point(x2, y2)
757
+ };
758
+ return create_line(points, 2);
759
+ }
760
+
761
+ Polygon
762
+ create_line (const Point& p1, const Point& p2)
763
+ {
764
+ const Point points[] = {p1, p2};
765
+ return create_line(points, 2);
766
+ }
767
+
768
+ Polygon
769
+ create_line (const Point* points, size_t size, bool loop)
770
+ {
771
+ return Polygon(points, size, loop);
772
+ }
773
+
774
+ Polygon
775
+ create_line (const Polyline& polyline)
776
+ {
777
+ return Polygon(polyline);
778
+ }
779
+
780
+ Polygon
781
+ create_rect (
782
+ coord x, coord y, coord width, coord height,
783
+ coord round, uint nsegment)
784
+ {
785
+ return create_rect(
786
+ x, y, width, height, round, round, round, round, nsegment);
787
+ }
788
+
789
+ Polygon
790
+ create_rect (
791
+ coord x, coord y, coord width, coord height,
792
+ coord round_left_top, coord round_right_top,
793
+ coord round_left_bottom, coord round_right_bottom,
794
+ uint nsegment)
795
+ {
796
+ if (width == 0 || height == 0)
797
+ return Polygon();
798
+
799
+ return Polygon(new RectData(
800
+ x, y, width, height,
801
+ round_left_top, round_right_top,
802
+ round_left_bottom, round_right_bottom,
803
+ nsegment));
804
+ }
805
+
806
+ Polygon
807
+ create_rect(const Bounds& bounds, coord round, uint nsegment)
808
+ {
809
+ return create_rect(
810
+ bounds.x, bounds.y, bounds.width, bounds.height,
811
+ round, round, round, round,
812
+ nsegment);
813
+ }
814
+
815
+ Polygon
816
+ create_rect (
817
+ const Bounds& bounds,
818
+ coord round_left_top, coord round_right_top,
819
+ coord round_left_bottom, coord round_right_bottom,
820
+ uint nsegment)
821
+ {
822
+ return create_rect(
823
+ bounds.x, bounds.y, bounds.width, bounds.height,
824
+ round_left_top, round_right_top,
825
+ round_left_bottom, round_right_bottom,
826
+ nsegment);
827
+ }
828
+
829
+ Polygon
830
+ create_ellipse (
831
+ coord x, coord y, coord width, coord height,
832
+ const Point& hole_size,
833
+ float angle_from, float angle_to,
834
+ uint nsegment)
835
+ {
836
+ if (width == 0 || height == 0 || angle_from == angle_to)
837
+ return Polygon();
838
+
839
+ return Polygon(new EllipseData(
840
+ x, y, width, height, hole_size, angle_from, angle_to, nsegment));
841
+ }
842
+
843
+ Polygon
844
+ create_ellipse (
845
+ const Bounds& bounds,
846
+ const Point& hole_size,
847
+ float angle_from, float angle_to,
848
+ uint nsegment)
849
+ {
850
+ return create_ellipse(
851
+ bounds.x, bounds.y, bounds.width, bounds.height,
852
+ hole_size, angle_from, angle_to, nsegment);
853
+ }
854
+
855
+ Polygon
856
+ create_ellipse (
857
+ const Point& center, const Point& radius,
858
+ const Point& hole_radius,
859
+ float angle_from, float angle_to,
860
+ uint nsegment)
861
+ {
862
+ return create_ellipse(
863
+ center.x - radius.x, center.y - radius.y,
864
+ radius.x * 2, radius.y * 2,
865
+ hole_radius * 2, angle_from, angle_to, nsegment);
866
+ }
867
+
868
+ void
869
+ Polygon_fill (const Polygon& polygon, Painter* painter, const Color& color)
870
+ {
871
+ if (!painter)
872
+ argument_error(__FILE__, __LINE__);
873
+
874
+ if (!color || !polygon || polygon.empty())
875
+ return;
876
+
877
+ polygon.self->fill(painter, color);
878
+ }
879
+
880
+ void
881
+ Polygon_stroke (const Polygon& polygon, Painter* painter, const Color& color)
882
+ {
883
+ if (!painter)
884
+ argument_error(__FILE__, __LINE__);
885
+
886
+ if (!color || !polygon || polygon.empty())
887
+ return;
888
+
889
+ polygon.self->stroke(polygon, painter, color);
890
+ }
891
+
892
+ bool
893
+ Polygon_triangulate (
894
+ Polygon::TrianglePointList* triangles, const Polygon& polygon)
895
+ {
896
+ return polygon.self->triangulate(triangles);
897
+ }
898
+
899
+
900
+ Polygon::Polygon ()
901
+ : self(new PolygonData())
902
+ {
903
+ }
904
+
905
+ Polygon::Polygon (const Point* points, size_t size, bool loop)
906
+ : self(new PolygonData())
907
+ {
908
+ if (!points || size <= 0) return;
909
+
910
+ self->append(Polyline(points, size, loop));
911
+ }
912
+
913
+ Polygon::Polygon (const Polyline& polyline)
914
+ : self(new PolygonData())
915
+ {
916
+ self->append(polyline);
917
+ }
918
+
919
+ Polygon::Polygon (const Line* lines, size_t size)
920
+ : self(new PolygonData())
921
+ {
922
+ if (!lines || size <= 0) return;
923
+
924
+ for (size_t i = 0; i < size; ++i)
925
+ self->append(lines[i]);
926
+ }
927
+
928
+ Polygon::Polygon (Data* data)
929
+ : self(data)
930
+ {
931
+ }
932
+
933
+ Polygon::~Polygon ()
934
+ {
935
+ }
936
+
937
+ bool
938
+ Polygon::expand (Polygon* result, coord width) const
939
+ {
940
+ return expand_polygon(result, *this, width);
941
+ }
942
+
943
+ Bounds
944
+ Polygon::bounds () const
945
+ {
946
+ if (empty()) return Bounds(-1, -1, -1);
947
+
948
+ Bounds b(self->lines[0][0], 0);
949
+ for (const auto& line : *this)
950
+ {
951
+ for (const auto& point : line)
952
+ b |= point;
953
+ }
954
+ return b;
955
+ }
956
+
957
+ size_t
958
+ Polygon::size () const
959
+ {
960
+ return self->lines.size();
961
+ }
962
+
963
+ bool
964
+ Polygon::empty (bool deep) const
965
+ {
966
+ if (deep)
967
+ {
968
+ for (const auto& line : self->lines)
969
+ {
970
+ if (!line.empty())
971
+ return false;
972
+ }
973
+ }
974
+
975
+ return size() <= 0;
976
+ }
977
+
978
+ Polygon::const_iterator
979
+ Polygon::begin () const
980
+ {
981
+ return self->lines.begin();
982
+ }
983
+
984
+ Polygon::const_iterator
985
+ Polygon::end () const
986
+ {
987
+ return self->lines.end();
988
+ }
989
+
990
+ const Polygon::Line&
991
+ Polygon::operator [] (size_t index) const
992
+ {
993
+ return self->lines[index];
994
+ }
995
+
996
+ Polygon::operator bool () const
997
+ {
998
+ if (self->lines.empty())
999
+ return true;
1000
+
1001
+ for (const auto& line : self->lines)
1002
+ {
1003
+ if (line) return true;
1004
+ }
1005
+
1006
+ return false;
1007
+ }
1008
+
1009
+ bool
1010
+ Polygon::operator ! () const
1011
+ {
1012
+ return !operator bool();
1013
+ }
1014
+
1015
+ bool
1016
+ Polygon::triangulate (TrianglePointList* triangles) const
1017
+ {
1018
+ return self->triangulate(triangles);
1019
+ }
1020
+
1021
+ Polygon
1022
+ operator + (const Polygon& lhs, const Polygon& rhs)
1023
+ {
1024
+ return lhs | rhs;
1025
+ }
1026
+
1027
+ Polygon
1028
+ operator - (const Polygon& lhs, const Polygon& rhs)
1029
+ {
1030
+ if (lhs.self == rhs.self) return Polygon();
1031
+
1032
+ return clip_polygons(lhs, rhs, ctDifference);
1033
+ }
1034
+
1035
+ Polygon
1036
+ operator & (const Polygon& lhs, const Polygon& rhs)
1037
+ {
1038
+ if (lhs.self == rhs.self) return lhs;
1039
+
1040
+ return clip_polygons(lhs, rhs, ctIntersection);
1041
+ }
1042
+
1043
+ Polygon
1044
+ operator | (const Polygon& lhs, const Polygon& rhs)
1045
+ {
1046
+ if (lhs.self == rhs.self) return lhs;
1047
+
1048
+ return clip_polygons(lhs, rhs, ctUnion);
1049
+ }
1050
+
1051
+ Polygon
1052
+ operator ^ (const Polygon& lhs, const Polygon& rhs)
1053
+ {
1054
+ if (lhs.self == rhs.self) return Polygon();
1055
+
1056
+ return clip_polygons(lhs, rhs, ctXor);
1057
+ }
1058
+
1059
+
1060
+ Polygon::Line::Line ()
1061
+ : Super(), hole_(false)
1062
+ {
1063
+ }
1064
+
1065
+ Polygon::Line::Line (const Point* points, size_t size, bool loop, bool hole)
1066
+ : Super(points, size, loop), hole_(hole)
1067
+ {
1068
+ if (!*this)
1069
+ argument_error(__FILE__, __LINE__);
1070
+ }
1071
+
1072
+ Polygon::Line::Line (const Polyline& polyline, bool hole)
1073
+ : Super(polyline), hole_(hole)
1074
+ {
1075
+ if (!*this)
1076
+ argument_error(__FILE__, __LINE__);
1077
+ }
1078
+
1079
+ bool
1080
+ Polygon::Line::hole () const
1081
+ {
1082
+ return hole_;
1083
+ }
1084
+
1085
+ Polygon::Line::operator bool () const
1086
+ {
1087
+ if (!Super::operator bool())
1088
+ return false;
1089
+
1090
+ return loop() || !hole();
1091
+ }
1092
+
1093
+ bool
1094
+ Polygon::Line::operator ! () const
1095
+ {
1096
+ return !operator bool();
1097
+ }
1098
+
1099
+
1100
+ }// Rays