rays 0.1.12 → 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
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 +171 -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 +23 -81
  25. data/ext/rays/bounds.cpp +100 -128
  26. data/ext/rays/camera.cpp +186 -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 +74 -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 +24 -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 +23 -0
  107. data/src/ios/bitmap.mm +133 -110
  108. data/src/ios/camera.mm +510 -0
  109. data/src/ios/font.mm +50 -62
  110. data/src/ios/helper.h +4 -4
  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 +23 -0
  119. data/src/osx/bitmap.mm +133 -110
  120. data/src/osx/camera.mm +451 -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