rays 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include <vector>
8
8
  #include <xot/pimpl.h>
9
+ #include <rays/defs.h>
9
10
  #include <rays/bounds.h>
10
11
  #include <rays/polyline.h>
11
12
 
@@ -61,7 +62,12 @@ namespace Rays
61
62
 
62
63
  ~Polygon ();
63
64
 
64
- bool expand (Polygon* result, coord width) const;
65
+ bool expand (
66
+ Polygon* result,
67
+ coord width,
68
+ CapType cap = CAP_DEFAULT,
69
+ JoinType join = JOIN_DEFAULT,
70
+ coord miter_limit = JOIN_DEFAULT_MITER_LIMIT) const;
65
71
 
66
72
  Bounds bounds () const;
67
73
 
@@ -158,6 +164,34 @@ namespace Rays
158
164
  uint nsegment = 0);
159
165
 
160
166
 
167
+ Polygon create_curve (
168
+ coord x1, coord y1, coord x2, coord y2,
169
+ coord x3, coord y3, coord x4, coord y4,
170
+ bool loop = false);
171
+
172
+ Polygon create_curve (
173
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
174
+ bool loop = false);
175
+
176
+ Polygon create_curve (
177
+ const Point* points, size_t size,
178
+ bool loop = false);
179
+
180
+
181
+ Polygon create_bezier (
182
+ coord x1, coord y1, coord x2, coord y2,
183
+ coord x3, coord y3, coord x4, coord y4,
184
+ bool loop = false);
185
+
186
+ Polygon create_bezier (
187
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
188
+ bool loop = false);
189
+
190
+ Polygon create_bezier (
191
+ const Point* points, size_t size,
192
+ bool loop = false);
193
+
194
+
161
195
  }// Rays
162
196
 
163
197
 
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include <vector>
8
8
  #include <xot/pimpl.h>
9
+ #include <rays/defs.h>
9
10
  #include <rays/point.h>
10
11
  #include <rays/bounds.h>
11
12
 
@@ -32,7 +33,12 @@ namespace Rays
32
33
 
33
34
  ~Polyline ();
34
35
 
35
- bool expand (Polygon* result, coord width) const;
36
+ bool expand (
37
+ Polygon* result,
38
+ coord width,
39
+ CapType cap = CAP_DEFAULT,
40
+ JoinType join = JOIN_DEFAULT,
41
+ coord miter_limit = JOIN_DEFAULT_MITER_LIMIT) const;
36
42
 
37
43
  Bounds bounds () const;
38
44
 
@@ -4,7 +4,10 @@
4
4
  #define __RAYS_RUBY_RAYS_H__
5
5
 
6
6
 
7
+ #include <rucy/rucy.h>
7
8
  #include <rucy/module.h>
9
+ #include <rucy/extension.h>
10
+ #include <rays/rays.h>
8
11
 
9
12
 
10
13
  namespace Rays
@@ -18,4 +21,9 @@ namespace Rays
18
21
  }// Rays
19
22
 
20
23
 
24
+ RUCY_DECLARE_VALUE_OR_ARRAY_TO(Rays::CapType)
25
+
26
+ RUCY_DECLARE_VALUE_OR_ARRAY_TO(Rays::JoinType)
27
+
28
+
21
29
  #endif//EOH
data/lib/rays/image.rb CHANGED
@@ -24,7 +24,7 @@ module Rays
24
24
  end
25
25
 
26
26
  def bounds ()
27
- Bounds.new 0, 0, *size
27
+ Bounds.new 0, 0, width, height
28
28
  end
29
29
 
30
30
  end# Image
data/lib/rays/painter.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
 
4
+ require 'xot/const_symbol_accessor'
4
5
  require 'xot/universal_accessor'
5
6
  require 'xot/block_util'
6
7
  require 'rays/ext'
@@ -73,6 +74,14 @@ module Rays
73
74
  draw_ellipse args, center, radius, hole, from, to
74
75
  end
75
76
 
77
+ def curve (*args, loop: false)
78
+ draw_curve args, loop
79
+ end
80
+
81
+ def bezier (*args, loop: false)
82
+ draw_bezier args, loop
83
+ end
84
+
76
85
  def color= (fill, stroke = nil)
77
86
  self.fill fill
78
87
  self.stroke stroke
@@ -87,8 +96,21 @@ module Rays
87
96
  set_shader shader
88
97
  end
89
98
 
99
+ const_symbol_accessor :stroke_cap, {
100
+ butt: CAP_BUTT,
101
+ round: CAP_ROUND,
102
+ square: CAP_SQUARE
103
+ }
104
+
105
+ const_symbol_accessor :stroke_join, {
106
+ miter: JOIN_MITER,
107
+ round: JOIN_ROUND,
108
+ square: JOIN_SQUARE
109
+ }
110
+
90
111
  universal_accessor :background, :fill, :stroke, :color,
91
- :stroke_width, :nsegment, :shader, :clip, :font
112
+ :stroke_width, :stroke_cap, :stroke_join, :miter_limit,
113
+ :nsegment, :shader, :clip, :font
92
114
 
93
115
  private
94
116
 
data/lib/rays/polygon.rb CHANGED
@@ -44,6 +44,14 @@ module Rays
44
44
  create_ellipse args, center, radius, hole, from, to, nsegment
45
45
  end
46
46
 
47
+ def self.curve (*args, loop: false)
48
+ create_curve args, loop
49
+ end
50
+
51
+ def self.bezier (*args, loop: false)
52
+ create_bezier args, loop
53
+ end
54
+
47
55
  end# Polygon
48
56
 
49
57
 
data/src/color_space.cpp CHANGED
@@ -55,7 +55,7 @@ namespace Rays
55
55
  32, 32, 32, // RGB(A) float
56
56
  32, 32, 32, // BGR(A) float
57
57
  };
58
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
58
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
59
59
  return BPPS[type_];
60
60
  }
61
61
 
@@ -78,7 +78,7 @@ namespace Rays
78
78
  96, 128, 128, // RGB(A) float
79
79
  96, 128, 128, // BGR(A) float
80
80
  };
81
- if (type_ < 0 || COLORSPACE_LAST <= type_) return BPPS[COLORSPACE_UNKNOWN];
81
+ if (type_ < 0 || COLORSPACE_MAX <= type_) return BPPS[COLORSPACE_UNKNOWN];
82
82
  return BPPS[type_];
83
83
  }
84
84
 
data/src/ios/bitmap.mm CHANGED
@@ -27,14 +27,14 @@ namespace Rays
27
27
  if (cs.is_alpha_first())
28
28
  {
29
29
  info |= cs.is_premult()
30
- ? kCGImageAlphaPremultipliedFirst
31
- : kCGImageAlphaFirst;
30
+ ? kCGImageAlphaPremultipliedFirst
31
+ : kCGImageAlphaFirst;
32
32
  }
33
33
  else if (cs.is_alpha_last())
34
34
  {
35
35
  info |= cs.is_premult()
36
- ? kCGImageAlphaPremultipliedLast
37
- : kCGImageAlphaLast;
36
+ ? kCGImageAlphaPremultipliedLast
37
+ : kCGImageAlphaLast;
38
38
  }
39
39
  else if (cs.is_skip_first())
40
40
  info |= kCGImageAlphaNoneSkipFirst;
data/src/ios/font.mm CHANGED
@@ -72,8 +72,8 @@ namespace Rays
72
72
  RawFont::RawFont (const char* name, coord size)
73
73
  {
74
74
  self->font = name
75
- ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
76
- : CTFontCreateUIFontForLanguage(kCTFontSystemFontType, size, NULL);
75
+ ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
76
+ : CTFontCreateUIFontForLanguage(kCTFontSystemFontType, size, NULL);
77
77
  }
78
78
 
79
79
  RawFont::~RawFont ()
data/src/osx/bitmap.mm CHANGED
@@ -26,14 +26,14 @@ namespace Rays
26
26
  if (cs.is_alpha_first())
27
27
  {
28
28
  info |= cs.is_premult()
29
- ? kCGImageAlphaPremultipliedFirst
30
- : kCGImageAlphaFirst;
29
+ ? kCGImageAlphaPremultipliedFirst
30
+ : kCGImageAlphaFirst;
31
31
  }
32
32
  else if (cs.is_alpha_last())
33
33
  {
34
34
  info |= cs.is_premult()
35
- ? kCGImageAlphaPremultipliedLast
36
- : kCGImageAlphaLast;
35
+ ? kCGImageAlphaPremultipliedLast
36
+ : kCGImageAlphaLast;
37
37
  }
38
38
  else if (cs.is_skip_first())
39
39
  info |= kCGImageAlphaNoneSkipFirst;
data/src/osx/font.mm CHANGED
@@ -71,8 +71,8 @@ namespace Rays
71
71
  RawFont::RawFont (const char* name, coord size)
72
72
  {
73
73
  self->font = name
74
- ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
75
- : CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, NULL);
74
+ ? CTFontCreateWithName(cfstring(name).get(), size, NULL)
75
+ : CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, NULL);
76
76
  }
77
77
 
78
78
  RawFont::~RawFont ()
data/src/painter.cpp CHANGED
@@ -48,6 +48,12 @@ namespace Rays
48
48
 
49
49
  coord stroke_width;
50
50
 
51
+ CapType stroke_cap;
52
+
53
+ JoinType stroke_join;
54
+
55
+ coord miter_limit;
56
+
51
57
  uint nsegment;
52
58
 
53
59
  Bounds clip;
@@ -62,6 +68,9 @@ namespace Rays
62
68
  colors[FILL] .reset(1, 1);
63
69
  colors[STROKE] .reset(1, 0);
64
70
  stroke_width = 0;
71
+ stroke_cap = CAP_DEFAULT;
72
+ stroke_join = JOIN_DEFAULT;
73
+ miter_limit = JOIN_DEFAULT_MITER_LIMIT;
65
74
  nsegment = 0;
66
75
  clip .reset(-1);
67
76
  font = default_font();
@@ -641,6 +650,11 @@ namespace Rays
641
650
 
642
651
  self->opengl_state.push();
643
652
 
653
+ //glEnable(GL_CULL_FACE);
654
+ glEnable(GL_BLEND);
655
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
656
+ OpenGL_check_error(__FILE__, __LINE__);
657
+
644
658
  FrameBuffer& fb = self->frame_buffer;
645
659
  if (fb) FrameBuffer_bind(fb.id());
646
660
 
@@ -649,6 +663,7 @@ namespace Rays
649
663
  glViewport(
650
664
  (int) (vp.x * density), (int) (vp.y * density),
651
665
  (int) (vp.width * density), (int) (vp.height * density));
666
+ OpenGL_check_error(__FILE__, __LINE__);
652
667
 
653
668
  coord x1 = vp.x, x2 = vp.x + vp.width;
654
669
  coord y1 = vp.y, y2 = vp.y + vp.height;
@@ -656,20 +671,13 @@ namespace Rays
656
671
  if (z1 == 0 && z2 == 0) {z1 = -100; z2 = 200;}
657
672
  if (!fb) std::swap(y1, y2);
658
673
 
659
- self->state.init();
660
-
661
674
  self->position_matrix.reset(1);
662
675
  self->position_matrix *= to_rays(glm::ortho(x1, x2, y1, y2));
663
676
  //self->position_matrix.translate(0.375f, 0.375f);
664
677
 
665
- //glEnable(GL_CULL_FACE);
666
- glEnable(GL_BLEND);
667
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
668
- OpenGL_check_error(__FILE__, __LINE__);
678
+ self->update_clip();
669
679
 
670
680
  self->painting = true;
671
-
672
- no_clip();
673
681
  }
674
682
 
675
683
  void
@@ -847,6 +855,52 @@ namespace Rays
847
855
  center, radius, hole_radius, angle_from, angle_to, nsegment()));
848
856
  }
849
857
 
858
+ void
859
+ Painter::curve (
860
+ coord x1, coord y1, coord x2, coord y2,
861
+ coord x3, coord y3, coord x4, coord y4,
862
+ bool loop)
863
+ {
864
+ polygon(create_curve(x1, y1, x2, y2, x3, y3, x4, y4, loop));
865
+ }
866
+
867
+ void
868
+ Painter::curve (
869
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
870
+ bool loop)
871
+ {
872
+ polygon(create_curve(p1, p2, p3, p4, loop));
873
+ }
874
+
875
+ void
876
+ Painter::curve (const Point* points, size_t size, bool loop)
877
+ {
878
+ polygon(create_curve(points, size, loop));
879
+ }
880
+
881
+ void
882
+ Painter::bezier (
883
+ coord x1, coord y1, coord x2, coord y2,
884
+ coord x3, coord y3, coord x4, coord y4,
885
+ bool loop)
886
+ {
887
+ polygon(create_bezier(x1, y1, x2, y2, x3, y3, x4, y4, loop));
888
+ }
889
+
890
+ void
891
+ Painter::bezier (
892
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
893
+ bool loop)
894
+ {
895
+ polygon(create_bezier(p1, p2, p3, p4, loop));
896
+ }
897
+
898
+ void
899
+ Painter::bezier (const Point* points, size_t size, bool loop)
900
+ {
901
+ polygon(create_bezier(points, size, loop));
902
+ }
903
+
850
904
  static void
851
905
  draw_image (
852
906
  Painter* painter, const Image& image,
@@ -1202,6 +1256,42 @@ namespace Rays
1202
1256
  return self->state.stroke_width;
1203
1257
  }
1204
1258
 
1259
+ void
1260
+ Painter::set_stroke_cap (CapType cap)
1261
+ {
1262
+ self->state.stroke_cap = cap;
1263
+ }
1264
+
1265
+ CapType
1266
+ Painter::stroke_cap () const
1267
+ {
1268
+ return self->state.stroke_cap;
1269
+ }
1270
+
1271
+ void
1272
+ Painter::set_stroke_join (JoinType join)
1273
+ {
1274
+ self->state.stroke_join = join;
1275
+ }
1276
+
1277
+ JoinType
1278
+ Painter::stroke_join () const
1279
+ {
1280
+ return self->state.stroke_join;
1281
+ }
1282
+
1283
+ void
1284
+ Painter::set_miter_limit (coord limit)
1285
+ {
1286
+ self->state.miter_limit = limit;
1287
+ }
1288
+
1289
+ coord
1290
+ Painter::miter_limit () const
1291
+ {
1292
+ return self->state.miter_limit;
1293
+ }
1294
+
1205
1295
  void
1206
1296
  Painter::set_nsegment (int nsegment)
1207
1297
  {
@@ -1279,7 +1369,7 @@ namespace Rays
1279
1369
  void
1280
1370
  Painter::push_state ()
1281
1371
  {
1282
- self->state_stack.push_back(self->state);
1372
+ self->state_stack.emplace_back(self->state);
1283
1373
  }
1284
1374
 
1285
1375
  void
@@ -1370,7 +1460,7 @@ namespace Rays
1370
1460
  void
1371
1461
  Painter::push_matrix ()
1372
1462
  {
1373
- self->position_matrix_stack.push_back(self->position_matrix);
1463
+ self->position_matrix_stack.emplace_back(self->position_matrix);
1374
1464
  }
1375
1465
 
1376
1466
  void
data/src/polygon.cpp CHANGED
@@ -5,6 +5,7 @@
5
5
  #include <assert.h>
6
6
  #include <utility>
7
7
  #include <poly2tri.h>
8
+ #include <Splines.h>
8
9
  #include "xot/util.h"
9
10
  #include "rays/color.h"
10
11
  #include "rays/exception.h"
@@ -13,7 +14,7 @@
13
14
  #include "painter.h"
14
15
 
15
16
 
16
- using namespace ClipperLib;
17
+ namespace clip = ClipperLib;
17
18
 
18
19
 
19
20
  namespace Rays
@@ -155,6 +156,10 @@ namespace Rays
155
156
 
156
157
  if (!polygon || polygon.empty()) return;
157
158
 
159
+ CapType cap = painter->stroke_cap();
160
+ JoinType join = painter->stroke_join();
161
+ coord ml = painter->miter_limit();
162
+
158
163
  bool has_loop = false;
159
164
  for (const auto& polyline : polygon)
160
165
  {
@@ -168,7 +173,7 @@ namespace Rays
168
173
  }
169
174
 
170
175
  Polygon stroke;
171
- if (!polyline.expand(&stroke, stroke_width / 2))
176
+ if (!polyline.expand(&stroke, stroke_width / 2, cap, join, ml))
172
177
  continue;
173
178
 
174
179
  Polygon_fill(stroke, painter, color);
@@ -177,7 +182,7 @@ namespace Rays
177
182
  if (has_loop)
178
183
  {
179
184
  Polygon hole;
180
- if (polygon.expand(&hole, -stroke_width))
185
+ if (polygon.expand(&hole, -stroke_width, cap, join, ml))
181
186
  Polygon_fill(polygon - hole, painter, color);
182
187
  }
183
188
  }
@@ -251,11 +256,11 @@ namespace Rays
251
256
 
252
257
  static void
253
258
  add_polygon_to_clipper (
254
- Clipper* clipper, const Polygon& polygon, PolyType type)
259
+ clip::Clipper* clipper, const Polygon& polygon, clip::PolyType type)
255
260
  {
256
261
  assert(clipper);
257
262
 
258
- Path path;
263
+ clip::Path path;
259
264
  for (const auto& line : polygon)
260
265
  {
261
266
  if (!line) continue;
@@ -267,42 +272,68 @@ namespace Rays
267
272
  }
268
273
  }
269
274
 
270
- static EndType
271
- get_end_type (const Polyline& polyline, bool fill)
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
+ }
284
+
285
+ argument_error(__FILE__, __LINE__);
286
+ }
287
+
288
+ static clip::EndType
289
+ get_end_type (const Polyline& polyline, CapType cap, bool fill)
272
290
  {
273
291
  if (polyline.loop())
274
- return fill ? etClosedPolygon : etClosedLine;
275
- else
276
- return etOpenButt;
292
+ return fill ? clip::etClosedPolygon : clip::etClosedLine;
293
+ else switch (cap)
294
+ {
295
+ case CAP_BUTT: return clip::etOpenButt;
296
+ case CAP_ROUND: return clip::etOpenRound;
297
+ case CAP_SQUARE: return clip::etOpenSquare;
298
+ }
299
+
300
+ argument_error(__FILE__, __LINE__);
277
301
  }
278
302
 
279
303
  static bool
280
304
  add_polyline_to_offsetter (
281
- ClipperOffset* offsetter, const Polyline& polyline, bool hole, bool fill)
305
+ clip::ClipperOffset* offsetter, const Polyline& polyline,
306
+ CapType cap, JoinType join, bool hole, bool fill)
282
307
  {
283
308
  assert(offsetter);
284
309
 
285
310
  if (!polyline) return false;
286
311
 
287
- Path path;
312
+ clip::Path path;
288
313
  Polyline_get_path(&path, polyline, hole);
289
- offsetter->AddPath(path, jtMiter, get_end_type(polyline, fill));
314
+ offsetter->AddPath(
315
+ path, get_join_type(join), get_end_type(polyline, cap, fill));
290
316
  return true;
291
317
  }
292
318
 
293
319
  static bool
294
- add_polygon_to_offsetter (ClipperOffset* offsetter, const Polygon& polygon)
320
+ add_polygon_to_offsetter (
321
+ clip::ClipperOffset* offsetter, const Polygon& polygon,
322
+ CapType cap, JoinType join)
295
323
  {
296
324
  assert(offsetter);
297
325
 
298
326
  bool added = false;
299
327
  for (const auto& line : polygon.self->lines)
300
- added |= add_polyline_to_offsetter(offsetter, line, line.hole(), true);
328
+ {
329
+ added |= add_polyline_to_offsetter(
330
+ offsetter, line, cap, join, line.hole(), true);
331
+ }
301
332
  return added;
302
333
  }
303
334
 
304
335
  static bool
305
- append_outline (Polygon* polygon, const PolyNode& node)
336
+ append_outline (Polygon* polygon, const clip::PolyNode& node)
306
337
  {
307
338
  assert(polygon);
308
339
 
@@ -319,7 +350,7 @@ namespace Rays
319
350
  }
320
351
 
321
352
  static void
322
- append_hole (Polygon* polygon, const PolyNode& node)
353
+ append_hole (Polygon* polygon, const clip::PolyNode& node)
323
354
  {
324
355
  assert(polygon);
325
356
 
@@ -338,7 +369,7 @@ namespace Rays
338
369
  }
339
370
 
340
371
  static void
341
- get_polygon (Polygon* polygon, const PolyNode& node)
372
+ get_polygon (Polygon* polygon, const clip::PolyNode& node)
342
373
  {
343
374
  assert(polygon);
344
375
 
@@ -350,15 +381,16 @@ namespace Rays
350
381
  }
351
382
 
352
383
  static Polygon
353
- clip_polygons (const Polygon& subject, const Polygon& clip, ClipType type)
384
+ clip_polygons (
385
+ const Polygon& subject, const Polygon& clip, clip::ClipType type)
354
386
  {
355
- Clipper c;
387
+ clip::Clipper c;
356
388
  c.StrictlySimple(true);
357
389
 
358
- add_polygon_to_clipper(&c, subject, ptSubject);
359
- add_polygon_to_clipper(&c, clip, ptClip);
390
+ add_polygon_to_clipper(&c, subject, clip::ptSubject);
391
+ add_polygon_to_clipper(&c, clip, clip::ptClip);
360
392
 
361
- PolyTree tree;
393
+ clip::PolyTree tree;
362
394
  c.Execute(type, tree);
363
395
  assert(tree.Contour.empty());
364
396
 
@@ -369,16 +401,19 @@ namespace Rays
369
401
  }
370
402
 
371
403
  static bool
372
- expand_polygon (Polygon* result, const Polygon& polygon, coord width)
404
+ expand_polygon (
405
+ Polygon* result, const Polygon& polygon,
406
+ coord width, CapType cap, JoinType join, coord miter_limit)
373
407
  {
374
408
  if (width == 0)
375
409
  return false;
376
410
 
377
- ClipperOffset co;
378
- if (!add_polygon_to_offsetter(&co, polygon))
411
+ clip::ClipperOffset co;
412
+ co.MiterLimit = miter_limit;
413
+ if (!add_polygon_to_offsetter(&co, polygon, cap, join))
379
414
  return false;
380
415
 
381
- PolyTree tree;
416
+ clip::PolyTree tree;
382
417
  co.Execute(tree, to_clipper(width));
383
418
  assert(tree.Contour.empty());
384
419
 
@@ -387,16 +422,19 @@ namespace Rays
387
422
  }
388
423
 
389
424
  bool
390
- Polyline_expand (Polygon* result, const Polyline& polyline, coord width)
425
+ Polyline_expand (
426
+ Polygon* result, const Polyline& polyline,
427
+ coord width, CapType cap, JoinType join, coord miter_limit)
391
428
  {
392
429
  if (width == 0)
393
430
  return false;
394
431
 
395
- ClipperOffset co;
396
- if (!add_polyline_to_offsetter(&co, polyline, false, false))
432
+ clip::ClipperOffset co;
433
+ co.MiterLimit = miter_limit;
434
+ if (!add_polyline_to_offsetter(&co, polyline, cap, join, false, false))
397
435
  return false;
398
436
 
399
- PolyTree tree;
437
+ clip::PolyTree tree;
400
438
  co.Execute(tree, to_clipper(width));
401
439
  assert(tree.Contour.empty());
402
440
 
@@ -865,6 +903,128 @@ namespace Rays
865
903
  hole_radius * 2, angle_from, angle_to, nsegment);
866
904
  }
867
905
 
906
+ static inline const SplineLib::Vec3f&
907
+ to_splinelib (const Point& val)
908
+ {
909
+ return *(const SplineLib::Vec3f*) &val;
910
+ }
911
+
912
+ static inline const Point&
913
+ to_rays (const SplineLib::Vec3f& val)
914
+ {
915
+ return *(const Point*) &val;
916
+ }
917
+
918
+ enum SplineType {BEZIER, HERMITE, CATMULLROM};
919
+
920
+ typedef SplineLib::cSpline3 (*SplineFun) (
921
+ const SplineLib::Vec3f&, const SplineLib::Vec3f&,
922
+ const SplineLib::Vec3f&, const SplineLib::Vec3f&);
923
+
924
+ static SplineFun
925
+ get_spline_fun (SplineType type)
926
+ {
927
+ switch (type)
928
+ {
929
+ case BEZIER: return SplineLib::BezierSpline;
930
+ case HERMITE: return SplineLib::HermiteSpline;
931
+ case CATMULLROM: return SplineLib::CatmullRomSpline;
932
+ default:
933
+ argument_error(__FILE__, __LINE__, "unknown spline type %d.", type);
934
+ }
935
+ }
936
+
937
+ static Polygon
938
+ create_spline (
939
+ SplineType type,
940
+ const Point* points, size_t size, bool loop,
941
+ uint nsegment = 16)
942
+ {
943
+ if (size % 4 != 0)
944
+ argument_error(__FILE__, __LINE__);
945
+
946
+ size_t count = size / 4;
947
+ auto spline_fun = get_spline_fun(type);
948
+
949
+ std::vector<Point> result;
950
+ result.reserve(nsegment * count);
951
+ for (size_t i = 0; i < count; ++i)
952
+ {
953
+ SplineLib::cSpline3 spline = spline_fun(
954
+ to_splinelib(points[i * 4 + 0]),
955
+ to_splinelib(points[i * 4 + 1]),
956
+ to_splinelib(points[i * 4 + 2]),
957
+ to_splinelib(points[i * 4 + 3]));
958
+ for (uint j = 0; j <= nsegment; ++j)
959
+ {
960
+ float t = (float) j / nsegment;
961
+ result.emplace_back(to_rays(SplineLib::Position(spline, t)));
962
+ }
963
+ }
964
+
965
+ return create_line(&result[0], result.size(), loop);
966
+ }
967
+
968
+ Polygon
969
+ create_curve (
970
+ coord x1, coord y1, coord x2, coord y2,
971
+ coord x3, coord y3, coord x4, coord y4,
972
+ bool loop)
973
+ {
974
+ const Point points[] = {
975
+ Point(x1, y1),
976
+ Point(x2, y2),
977
+ Point(x3, y3),
978
+ Point(x4, y4)
979
+ };
980
+ return create_spline(CATMULLROM, points, 4, loop);
981
+ }
982
+
983
+ Polygon
984
+ create_curve (
985
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
986
+ bool loop)
987
+ {
988
+ const Point points[] = {p1, p2, p3, p4};
989
+ return create_spline(CATMULLROM, points, 4, loop);
990
+ }
991
+
992
+ Polygon
993
+ create_curve (const Point* points, size_t size, bool loop)
994
+ {
995
+ return create_spline(CATMULLROM, points, size, loop);
996
+ }
997
+
998
+ Polygon
999
+ create_bezier (
1000
+ coord x1, coord y1, coord x2, coord y2,
1001
+ coord x3, coord y3, coord x4, coord y4,
1002
+ bool loop)
1003
+ {
1004
+ const Point points[] = {
1005
+ Point(x1, y1),
1006
+ Point(x2, y2),
1007
+ Point(x3, y3),
1008
+ Point(x4, y4)
1009
+ };
1010
+ return create_spline(BEZIER, points, 4, loop);
1011
+ }
1012
+
1013
+ Polygon
1014
+ create_bezier (
1015
+ const Point& p1, const Point& p2, const Point& p3, const Point& p4,
1016
+ bool loop)
1017
+ {
1018
+ const Point points[] = {p1, p2, p3, p4};
1019
+ return create_spline(BEZIER, points, 4, loop);
1020
+ }
1021
+
1022
+ Polygon
1023
+ create_bezier (const Point* points, size_t size, bool loop)
1024
+ {
1025
+ return create_spline(BEZIER, points, size, loop);
1026
+ }
1027
+
868
1028
  void
869
1029
  Polygon_fill (const Polygon& polygon, Painter* painter, const Color& color)
870
1030
  {
@@ -935,9 +1095,11 @@ namespace Rays
935
1095
  }
936
1096
 
937
1097
  bool
938
- Polygon::expand (Polygon* result, coord width) const
1098
+ Polygon::expand (
1099
+ Polygon* result,
1100
+ coord width, CapType cap, JoinType join, coord miter_limit) const
939
1101
  {
940
- return expand_polygon(result, *this, width);
1102
+ return expand_polygon(result, *this, width, cap, join, miter_limit);
941
1103
  }
942
1104
 
943
1105
  Bounds
@@ -1029,7 +1191,7 @@ namespace Rays
1029
1191
  {
1030
1192
  if (lhs.self == rhs.self) return Polygon();
1031
1193
 
1032
- return clip_polygons(lhs, rhs, ctDifference);
1194
+ return clip_polygons(lhs, rhs, clip::ctDifference);
1033
1195
  }
1034
1196
 
1035
1197
  Polygon
@@ -1037,7 +1199,7 @@ namespace Rays
1037
1199
  {
1038
1200
  if (lhs.self == rhs.self) return lhs;
1039
1201
 
1040
- return clip_polygons(lhs, rhs, ctIntersection);
1202
+ return clip_polygons(lhs, rhs, clip::ctIntersection);
1041
1203
  }
1042
1204
 
1043
1205
  Polygon
@@ -1045,7 +1207,7 @@ namespace Rays
1045
1207
  {
1046
1208
  if (lhs.self == rhs.self) return lhs;
1047
1209
 
1048
- return clip_polygons(lhs, rhs, ctUnion);
1210
+ return clip_polygons(lhs, rhs, clip::ctUnion);
1049
1211
  }
1050
1212
 
1051
1213
  Polygon
@@ -1053,7 +1215,7 @@ namespace Rays
1053
1215
  {
1054
1216
  if (lhs.self == rhs.self) return Polygon();
1055
1217
 
1056
- return clip_polygons(lhs, rhs, ctXor);
1218
+ return clip_polygons(lhs, rhs, clip::ctXor);
1057
1219
  }
1058
1220
 
1059
1221