rays 0.1.11 → 0.1.16

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