rays 0.1.11 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.doc/ext/rays/bitmap.cpp +22 -76
- data/.doc/ext/rays/bounds.cpp +95 -125
- data/.doc/ext/rays/camera.cpp +88 -0
- data/.doc/ext/rays/color.cpp +223 -45
- data/.doc/ext/rays/color_space.cpp +146 -46
- data/.doc/ext/rays/defs.cpp +183 -0
- data/.doc/ext/rays/font.cpp +69 -21
- data/.doc/ext/rays/image.cpp +26 -37
- data/.doc/ext/rays/matrix.cpp +186 -29
- data/.doc/ext/rays/native.cpp +14 -8
- data/.doc/ext/rays/noise.cpp +53 -0
- data/.doc/ext/rays/painter.cpp +187 -292
- data/.doc/ext/rays/point.cpp +96 -77
- data/.doc/ext/rays/polygon.cpp +313 -0
- data/.doc/ext/rays/polygon_line.cpp +96 -0
- data/.doc/ext/rays/polyline.cpp +167 -0
- data/.doc/ext/rays/rays.cpp +103 -12
- data/.doc/ext/rays/shader.cpp +83 -9
- data/LICENSE +21 -0
- data/README.md +1 -1
- data/Rakefile +24 -9
- data/VERSION +1 -1
- data/ext/rays/bitmap.cpp +22 -80
- data/ext/rays/bounds.cpp +100 -128
- data/ext/rays/camera.cpp +94 -0
- data/ext/rays/color.cpp +231 -51
- data/ext/rays/color_space.cpp +149 -47
- data/ext/rays/defs.cpp +183 -0
- data/ext/rays/defs.h +26 -2
- data/ext/rays/extconf.rb +2 -3
- data/ext/rays/font.cpp +74 -24
- data/ext/rays/image.cpp +28 -40
- data/ext/rays/matrix.cpp +198 -30
- data/ext/rays/native.cpp +14 -8
- data/ext/rays/noise.cpp +55 -0
- data/ext/rays/painter.cpp +203 -298
- data/ext/rays/point.cpp +105 -81
- data/ext/rays/polygon.cpp +329 -0
- data/ext/rays/polygon_line.cpp +99 -0
- data/ext/rays/polyline.cpp +176 -0
- data/ext/rays/rays.cpp +103 -13
- 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/camera.h +49 -0
- data/include/rays/color.h +25 -14
- data/include/rays/color_space.h +15 -10
- data/include/rays/coord.h +114 -0
- data/include/rays/debug.h +22 -0
- data/include/rays/defs.h +36 -0
- data/include/rays/exception.h +6 -2
- data/include/rays/font.h +4 -4
- data/include/rays/image.h +12 -18
- 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 +89 -93
- data/include/rays/point.h +44 -51
- data/include/rays/polygon.h +198 -0
- data/include/rays/polyline.h +71 -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/camera.h +41 -0
- 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/rays.h +8 -0
- data/include/rays/ruby/shader.h +1 -1
- data/include/rays/shader.h +36 -8
- data/lib/rays.rb +7 -2
- data/lib/rays/bitmap.rb +0 -15
- data/lib/rays/bounds.rb +17 -23
- data/lib/rays/camera.rb +21 -0
- data/lib/rays/color.rb +20 -47
- data/lib/rays/color_space.rb +13 -13
- data/lib/rays/image.rb +3 -7
- data/lib/rays/matrix.rb +28 -0
- data/lib/rays/module.rb +4 -19
- data/lib/rays/painter.rb +78 -93
- data/lib/rays/point.rb +13 -21
- data/lib/rays/polygon.rb +58 -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 +52 -34
- 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 +172 -98
- data/src/image.h +25 -0
- data/src/ios/bitmap.h +21 -0
- data/src/ios/bitmap.mm +129 -110
- data/src/ios/camera.mm +236 -0
- data/src/ios/font.mm +50 -62
- 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.h +21 -0
- data/src/osx/bitmap.mm +129 -110
- data/src/osx/camera.mm +236 -0
- data/src/osx/font.mm +49 -62
- 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 +845 -671
- data/src/painter.h +24 -0
- data/src/point.cpp +140 -119
- data/src/polygon.cpp +1266 -0
- data/src/polygon.h +32 -0
- data/src/polyline.cpp +160 -0
- data/src/polyline.h +69 -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_font.rb +5 -0
- data/test/test_image.rb +24 -20
- data/test/test_matrix.rb +106 -0
- data/test/test_painter.rb +157 -51
- data/test/test_painter_shape.rb +102 -0
- data/test/test_point.rb +29 -0
- data/test/test_polygon.rb +234 -0
- data/test/test_polygon_line.rb +167 -0
- data/test/test_polyline.rb +171 -0
- data/test/test_shader.rb +9 -9
- metadata +102 -70
- 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,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
|