rays 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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