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