1 | // [Blend2D] |
2 | // 2D Vector Graphics Powered by a JIT Compiler. |
3 | // |
4 | // [License] |
5 | // Zlib - See LICENSE.md file in the package. |
6 | |
7 | #ifndef BLEND2D_BLPATH_H |
8 | #define BLEND2D_BLPATH_H |
9 | |
10 | #include "./blarray.h" |
11 | #include "./blgeometry.h" |
12 | #include "./blvariant.h" |
13 | |
14 | //! \addtogroup blend2d_api_geometry |
15 | //! \{ |
16 | |
17 | // ============================================================================ |
18 | // [Constants] |
19 | // ============================================================================ |
20 | |
21 | //! Path command. |
22 | BL_DEFINE_ENUM(BLPathCmd) { |
23 | //! Move-to command (starts a new figure). |
24 | BL_PATH_CMD_MOVE = 0, |
25 | //! On-path command (interpreted as line-to or the end of a curve). |
26 | BL_PATH_CMD_ON = 1, |
27 | //! Quad-to control point. |
28 | BL_PATH_CMD_QUAD = 2, |
29 | //! Cubic-to control point (always used as a pair of commands). |
30 | BL_PATH_CMD_CUBIC = 3, |
31 | //! Close path. |
32 | BL_PATH_CMD_CLOSE = 4, |
33 | |
34 | //! Count of path commands. |
35 | BL_PATH_CMD_COUNT = 5 |
36 | }; |
37 | |
38 | //! Path command (never stored in path). |
39 | BL_DEFINE_ENUM() { |
40 | //! Used by `BLPath::setVertexAt` to preserve the current command value. |
41 | BL_PATH_CMD_PRESERVE = 0xFFFFFFFFu |
42 | }; |
43 | |
44 | //! Path flags. |
45 | BL_DEFINE_ENUM(BLPathFlags) { |
46 | //! Path is empty (no commands or close commands only). |
47 | BL_PATH_FLAG_EMPTY = 0x00000001u, |
48 | //! Path contains multiple figures. |
49 | BL_PATH_FLAG_MULTIPLE = 0x00000002u, |
50 | //! Path contains quad curves (at least one). |
51 | BL_PATH_FLAG_QUADS = 0x00000004u, |
52 | //! Path contains cubic curves (at least one). |
53 | BL_PATH_FLAG_CUBICS = 0x00000008u, |
54 | //! Path is invalid. |
55 | BL_PATH_FLAG_INVALID = 0x40000000u, |
56 | //! Flags are dirty (not reflecting the current status). |
57 | BL_PATH_FLAG_DIRTY = 0x80000000u |
58 | }; |
59 | |
60 | //! Path reversal mode. |
61 | BL_DEFINE_ENUM(BLPathReverseMode) { |
62 | //! Reverse each figure and their order as well (default). |
63 | BL_PATH_REVERSE_MODE_COMPLETE = 0, |
64 | //! Reverse each figure separately (keeps their order). |
65 | BL_PATH_REVERSE_MODE_SEPARATE = 1, |
66 | |
67 | //! Count of path-reversal modes |
68 | BL_PATH_REVERSE_MODE_COUNT = 2 |
69 | }; |
70 | |
71 | //! Stroke join type. |
72 | BL_DEFINE_ENUM(BLStrokeJoin) { |
73 | //! Miter-join possibly clipped at `miterLimit` [default]. |
74 | BL_STROKE_JOIN_MITER_CLIP = 0, |
75 | //! Miter-join or bevel-join depending on miterLimit condition. |
76 | BL_STROKE_JOIN_MITER_BEVEL = 1, |
77 | //! Miter-join or round-join depending on miterLimit condition. |
78 | BL_STROKE_JOIN_MITER_ROUND = 2, |
79 | //! Bevel-join. |
80 | BL_STROKE_JOIN_BEVEL = 3, |
81 | //! Round-join. |
82 | BL_STROKE_JOIN_ROUND = 4, |
83 | |
84 | //! Count of stroke join types. |
85 | BL_STROKE_JOIN_COUNT = 5 |
86 | }; |
87 | |
88 | //! Position of a stroke-cap. |
89 | BL_DEFINE_ENUM(BLStrokeCapPosition) { |
90 | //! Start of the path. |
91 | BL_STROKE_CAP_POSITION_START = 0, |
92 | //! End of the path. |
93 | BL_STROKE_CAP_POSITION_END = 1, |
94 | |
95 | //! Count of stroke position options. |
96 | BL_STROKE_CAP_POSITION_COUNT = 2 |
97 | }; |
98 | |
99 | //! A presentation attribute defining the shape to be used at the end of open subpaths. |
100 | BL_DEFINE_ENUM(BLStrokeCap) { |
101 | //! Butt cap [default]. |
102 | BL_STROKE_CAP_BUTT = 0, |
103 | //! Square cap. |
104 | BL_STROKE_CAP_SQUARE = 1, |
105 | //! Round cap. |
106 | BL_STROKE_CAP_ROUND = 2, |
107 | //! Round cap reversed. |
108 | BL_STROKE_CAP_ROUND_REV = 3, |
109 | //! Triangle cap. |
110 | BL_STROKE_CAP_TRIANGLE = 4, |
111 | //! Triangle cap reversed. |
112 | BL_STROKE_CAP_TRIANGLE_REV = 5, |
113 | |
114 | //! Used to catch invalid arguments. |
115 | BL_STROKE_CAP_COUNT = 6 |
116 | }; |
117 | |
118 | //! Stroke transform order. |
119 | BL_DEFINE_ENUM(BLStrokeTransformOrder) { |
120 | //! Transform after stroke => `Transform(Stroke(Input))` [default]. |
121 | BL_STROKE_TRANSFORM_ORDER_AFTER = 0, |
122 | //! Transform before stroke => `Stroke(Transform(Input))`. |
123 | BL_STROKE_TRANSFORM_ORDER_BEFORE = 1, |
124 | |
125 | //! Count of transform order types. |
126 | BL_STROKE_TRANSFORM_ORDER_COUNT = 2 |
127 | }; |
128 | |
129 | //! Mode that specifies how curves are approximated to line segments. |
130 | BL_DEFINE_ENUM(BLFlattenMode) { |
131 | //! Use default mode (decided by Blend2D). |
132 | BL_FLATTEN_MODE_DEFAULT = 0, |
133 | //! Recursive subdivision flattening. |
134 | BL_FLATTEN_MODE_RECURSIVE = 1, |
135 | |
136 | //! Count of flatten modes. |
137 | BL_FLATTEN_MODE_COUNT = 2 |
138 | }; |
139 | |
140 | //! Mode that specifies how to construct offset curves. |
141 | BL_DEFINE_ENUM(BLOffsetMode) { |
142 | //! Use default mode (decided by Blend2D). |
143 | BL_OFFSET_MODE_DEFAULT = 0, |
144 | //! Iterative offset construction. |
145 | BL_OFFSET_MODE_ITERATIVE = 1, |
146 | |
147 | //! Count of offset modes. |
148 | BL_OFFSET_MODE_COUNT = 2 |
149 | }; |
150 | |
151 | // ============================================================================ |
152 | // [BLApproximationOptions] |
153 | // ============================================================================ |
154 | |
155 | //! Options used to describe how geometry is approximated. |
156 | //! |
157 | //! This struct cannot be simply zeroed and then passed to functions that accept |
158 | //! approximation options. Use `blDefaultApproximationOptions` to setup defaults |
159 | //! and then alter values you want to change. |
160 | //! |
161 | //! Example of using `BLApproximationOptions`: |
162 | //! |
163 | //! ``` |
164 | //! // Initialize with defaults first. |
165 | //! BLApproximationOptions approx = blDefaultApproximationOptions; |
166 | //! |
167 | //! // Override values you want to change. |
168 | //! approx.simplifyTolerance = 0.02; |
169 | //! |
170 | //! // ... now safely use approximation options in your code ... |
171 | //! ``` |
172 | struct BLApproximationOptions { |
173 | //! Specifies how curves are flattened, see `BLFlattenMode`. |
174 | uint8_t flattenMode; |
175 | //! Specifies how curves are offsetted (used by stroking), see `BLOffsetMode`. |
176 | uint8_t offsetMode; |
177 | //! Reserved for future use, must be zero. |
178 | uint8_t reservedFlags[6]; |
179 | |
180 | //! Tolerance used to flatten curves. |
181 | double flattenTolerance; |
182 | //! Tolerance used to approximatecubic curves qith quadratic curves. |
183 | double simplifyTolerance; |
184 | //! Curve offsetting parameter, exact meaning depends on `offsetMode`. |
185 | double offsetParameter; |
186 | }; |
187 | |
188 | #ifdef __cplusplus |
189 | extern "C" { |
190 | #endif |
191 | |
192 | //! Default approximation options used by Blend2D. |
193 | extern BL_API const BLApproximationOptions blDefaultApproximationOptions; |
194 | |
195 | #ifdef __cplusplus |
196 | } // {Extern:C} |
197 | #endif |
198 | |
199 | // ============================================================================ |
200 | // [BLStrokeOptions - Core] |
201 | // ============================================================================ |
202 | |
203 | //! Stroke options [C Interface - Core]. |
204 | //! |
205 | //! This structure may use dynamically allocated memory so it's required to use |
206 | //! proper initializers to initialize it and reset it. |
207 | struct BLStrokeOptionsCore { |
208 | union { |
209 | struct { |
210 | uint8_t startCap; |
211 | uint8_t endCap; |
212 | uint8_t join; |
213 | uint8_t transformOrder; |
214 | uint8_t reserved[4]; |
215 | }; |
216 | uint8_t caps[BL_STROKE_CAP_POSITION_COUNT]; |
217 | uint64_t hints; |
218 | }; |
219 | |
220 | double width; |
221 | double miterLimit; |
222 | double dashOffset; |
223 | BL_TYPED_MEMBER(BLArrayCore, BLArray<double>, dashArray); |
224 | |
225 | BL_HAS_TYPED_MEMBERS(BLStrokeOptionsCore) |
226 | }; |
227 | |
228 | // ============================================================================ |
229 | // [BLStrokeOptions - C++] |
230 | // ============================================================================ |
231 | |
232 | #ifdef __cplusplus |
233 | // Prevents the following: |
234 | // Base class XXX should be explicitly initialized in the copy constructor [-Wextra] |
235 | BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_EXTRA_WARNINGS) |
236 | |
237 | //! Stroke options [C++ API]. |
238 | //! |
239 | //! You should use this as a structure and use members of `BLStrokeOptionsCore` |
240 | //! directly. |
241 | class BLStrokeOptions : public BLStrokeOptionsCore { |
242 | public: |
243 | BL_INLINE BLStrokeOptions() noexcept { blStrokeOptionsInit(this); } |
244 | BL_INLINE BLStrokeOptions(BLStrokeOptions&& other) noexcept { blStrokeOptionsInitMove(this, &other); } |
245 | BL_INLINE BLStrokeOptions(const BLStrokeOptions& other) noexcept { blStrokeOptionsInitWeak(this, &other); } |
246 | BL_INLINE ~BLStrokeOptions() noexcept { blStrokeOptionsReset(this); } |
247 | |
248 | BL_INLINE BLStrokeOptions& operator=(BLStrokeOptions&& other) noexcept { blStrokeOptionsAssignMove(this, &other); return *this; } |
249 | BL_INLINE BLStrokeOptions& operator=(const BLStrokeOptions& other) noexcept { blStrokeOptionsAssignWeak(this, &other); return *this; } |
250 | |
251 | BL_INLINE void setCaps(uint32_t strokeCap) noexcept { |
252 | startCap = uint8_t(strokeCap); |
253 | endCap = uint8_t(strokeCap); |
254 | } |
255 | }; |
256 | |
257 | BL_DIAGNOSTIC_POP |
258 | #endif |
259 | |
260 | // ============================================================================ |
261 | // [BLPath - View] |
262 | // ============================================================================ |
263 | |
264 | //! 2D path view provides pointers to vertex and command data along with their |
265 | //! size. |
266 | struct BLPathView { |
267 | const uint8_t* commandData; |
268 | const BLPoint* vertexData; |
269 | size_t size; |
270 | |
271 | // -------------------------------------------------------------------------- |
272 | #ifdef __cplusplus |
273 | BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_SHADOW) |
274 | |
275 | BL_INLINE void reset() noexcept { |
276 | this->commandData = nullptr; |
277 | this->vertexData = nullptr; |
278 | this->size = 0; |
279 | } |
280 | |
281 | BL_INLINE void reset(const uint8_t* commandData, const BLPoint* vertexData, size_t size) noexcept { |
282 | this->commandData = commandData; |
283 | this->vertexData = vertexData; |
284 | this->size = size; |
285 | } |
286 | |
287 | BL_DIAGNOSTIC_POP |
288 | #endif |
289 | // -------------------------------------------------------------------------- |
290 | }; |
291 | |
292 | // ============================================================================ |
293 | // [BLPath - Core] |
294 | // ============================================================================ |
295 | |
296 | //! 2D vector path [C Interface - Impl]. |
297 | struct BLPathImpl { |
298 | //! Union of either raw path-data or their `view`. |
299 | union { |
300 | struct { |
301 | //! Command data |
302 | uint8_t* commandData; |
303 | //! Vertex data. |
304 | BLPoint* vertexData; |
305 | //! Vertex/command count. |
306 | size_t size; |
307 | }; |
308 | //! Path data as view. |
309 | BLPathView view; |
310 | }; |
311 | |
312 | //! Reference count. |
313 | volatile size_t refCount; |
314 | //! Impl type. |
315 | uint8_t implType; |
316 | //! Impl traits. |
317 | uint8_t implTraits; |
318 | //! Memory pool data. |
319 | uint16_t memPoolData; |
320 | |
321 | //! Path flags related to caching. |
322 | volatile uint32_t flags; |
323 | //! Path vertex/command capacity. |
324 | size_t capacity; |
325 | }; |
326 | |
327 | //! 2D vector path [C Interface - Core]. |
328 | struct BLPathCore { |
329 | BLPathImpl* impl; |
330 | }; |
331 | |
332 | // ============================================================================ |
333 | // [BLPath - C++] |
334 | // ============================================================================ |
335 | |
336 | #ifdef __cplusplus |
337 | //! 2D vector path [C++ API]. |
338 | class BLPath : public BLPathCore { |
339 | public: |
340 | //! \cond INTERNAL |
341 | static constexpr const uint32_t kImplType = BL_IMPL_TYPE_PATH; |
342 | //! \endcond |
343 | |
344 | //! \name Construction & Destruction |
345 | //! \{ |
346 | |
347 | BL_INLINE BLPath() noexcept { this->impl = none().impl; } |
348 | BL_INLINE BLPath(BLPath&& other) noexcept { blVariantInitMove(this, &other); } |
349 | BL_INLINE BLPath(const BLPath& other) noexcept { blVariantInitWeak(this, &other); } |
350 | BL_INLINE explicit BLPath(BLPathImpl* impl) noexcept { this->impl = impl; } |
351 | |
352 | BL_INLINE ~BLPath() noexcept { blPathReset(this); } |
353 | |
354 | //! \} |
355 | |
356 | //! \name Overloaded Operators |
357 | //! \{ |
358 | |
359 | BL_INLINE explicit operator bool() const noexcept { return impl->size != 0; } |
360 | |
361 | BL_INLINE BLPath& operator=(BLPath&& other) noexcept { blPathAssignMove(this, &other); return *this; } |
362 | BL_INLINE BLPath& operator=(const BLPath& other) noexcept { blPathAssignWeak(this, &other); return *this; } |
363 | |
364 | BL_INLINE bool operator==(const BLPath& other) const noexcept { return equals(other); } |
365 | BL_INLINE bool operator!=(const BLPath& other) const noexcept { return !equals(other); } |
366 | |
367 | //! \} |
368 | |
369 | //! \name Common Functionality |
370 | //! \{ |
371 | |
372 | BL_INLINE BLResult reset() noexcept { return blPathReset(this); } |
373 | BL_INLINE void swap(BLPath& other) noexcept { std::swap(this->impl, other.impl); } |
374 | |
375 | BL_INLINE BLResult assign(BLPath&& other) noexcept { return blPathAssignMove(this, &other); } |
376 | BL_INLINE BLResult assign(const BLPath& other) noexcept { return blPathAssignWeak(this, &other); } |
377 | BL_INLINE BLResult assignDeep(const BLPath& other) noexcept { return blPathAssignDeep(this, &other); } |
378 | |
379 | //! Tests whether the 2D path is a built-in null instance. |
380 | BL_INLINE bool isNone() const noexcept { return (impl->implTraits & BL_IMPL_TRAIT_NULL) != 0; } |
381 | //! Tests whether the path is empty (its size equals zero). |
382 | BL_INLINE bool empty() const noexcept { return impl->size == 0; } |
383 | |
384 | //! Tests whether this path and the `other` path are equal. |
385 | //! |
386 | //! The equality check is deep. The data of both paths is examined and binary |
387 | //! compared (thus a slight difference like -0 and +0 would make the equality |
388 | //! check to fail). |
389 | BL_INLINE bool equals(const BLPath& other) const noexcept { return blPathEquals(this, &other); } |
390 | |
391 | //! \} |
392 | |
393 | //! \name Path Content |
394 | //! \{ |
395 | |
396 | //! Returns path size (count of vertices used). |
397 | BL_INLINE size_t size() const noexcept { return impl->size; } |
398 | //! Returns path capacity (count of allocated vertices). |
399 | BL_INLINE size_t capacity() const noexcept { return impl->capacity; } |
400 | |
401 | //! Returns path's vertex data (read-only). |
402 | BL_INLINE const BLPoint* vertexData() const noexcept { return impl->vertexData; } |
403 | //! Returns the end of path's vertex data (read-only). |
404 | BL_INLINE const BLPoint* vertexDataEnd() const noexcept { return impl->vertexData + impl->size; } |
405 | |
406 | //! Returns path's command data (read-only). |
407 | BL_INLINE const uint8_t* commandData() const noexcept { return impl->commandData; } |
408 | //! Returns the end of path's command data (read-only). |
409 | BL_INLINE const uint8_t* commandDataEnd() const noexcept { return impl->commandData + impl->size; } |
410 | |
411 | //! Returns the path data as a read-only `BLPathView`. |
412 | BL_INLINE const BLPathView& view() const noexcept { return impl->view; } |
413 | |
414 | //! \} |
415 | |
416 | //! \name Path Construction |
417 | //! \{ |
418 | |
419 | //! Clears the content of the path. |
420 | BL_INLINE BLResult clear() noexcept { |
421 | return blPathClear(this); |
422 | } |
423 | |
424 | //! Shrinks the capacity of the path to fit the current usage. |
425 | BL_INLINE BLResult shrink() noexcept { |
426 | return blPathShrink(this); |
427 | } |
428 | |
429 | //! Reserves the capacity of the path for at least `n` vertices and commands. |
430 | BL_INLINE BLResult reserve(size_t n) noexcept { |
431 | return blPathReserve(this, n); |
432 | } |
433 | |
434 | BL_INLINE BLResult modifyOp(uint32_t op, size_t n, uint8_t** cmdDataOut, BLPoint** vtxDataOut) noexcept { |
435 | return blPathModifyOp(this, op, n, cmdDataOut, vtxDataOut); |
436 | } |
437 | |
438 | //! Sets vertex at `index` to `cmd` and `pt`. |
439 | //! |
440 | //! Pass `BL_PATH_CMD_PRESERVE` in `cmd` to preserve the current command. |
441 | BL_INLINE BLResult setVertexAt(size_t index, uint32_t cmd, const BLPoint& pt) noexcept { |
442 | return blPathSetVertexAt(this, index, cmd, pt.x, pt.y); |
443 | } |
444 | |
445 | //! Sets vertex at `index` to `cmd` and `[x, y]`. |
446 | //! |
447 | //! Pass `BL_PATH_CMD_PRESERVE` in `cmd` to preserve the current command. |
448 | BL_INLINE BLResult setVertexAt(size_t index, uint32_t cmd, double x, double y) noexcept { |
449 | return blPathSetVertexAt(this, index, cmd, x, y); |
450 | } |
451 | |
452 | //! Moves to `p0`. |
453 | //! |
454 | //! Appends `BL_PATH_CMD_MOVE[p0]` command to the path. |
455 | BL_INLINE BLResult moveTo(const BLPoint& p0) noexcept { |
456 | return blPathMoveTo(this, p0.x, p0.y); |
457 | } |
458 | |
459 | //! Moves to `[x0, y0]`. |
460 | //! |
461 | //! Appends `BL_PATH_CMD_MOVE[x0, y0]` command to the path. |
462 | BL_INLINE BLResult moveTo(double x0, double y0) noexcept { |
463 | return blPathMoveTo(this, x0, y0); |
464 | } |
465 | |
466 | //! Adds line to `p1`. |
467 | //! |
468 | //! Appends `BL_PATH_CMD_ON[p1]` command to the path. |
469 | BL_INLINE BLResult lineTo(const BLPoint& p1) noexcept { |
470 | return blPathLineTo(this, p1.x, p1.y); |
471 | } |
472 | |
473 | //! Adds line to `[x1, y1]`. |
474 | //! |
475 | //! Appends `BL_PATH_CMD_ON[x1, y1]` command to the path. |
476 | BL_INLINE BLResult lineTo(double x1, double y1) noexcept { |
477 | return blPathLineTo(this, x1, y1); |
478 | } |
479 | |
480 | //! Adds a polyline (LineTo) of the given `poly` array of size `count`. |
481 | //! |
482 | //! Appends multiple `BL_PATH_CMD_ON[x[i], y[i]]` commands to the path depending on `count` parameter. |
483 | BL_INLINE BLResult polyTo(const BLPoint* poly, size_t count) noexcept { |
484 | return blPathPolyTo(this, poly, count); |
485 | } |
486 | |
487 | //! Adds a quadratic curve to `p1` and `p2`. |
488 | //! |
489 | //! Appends the following commands to the path: |
490 | //! - `BL_PATH_CMD_QUAD[p1]` |
491 | //! - `BL_PATH_CMD_ON[p2]` |
492 | //! |
493 | //! Matches SVG 'Q' path command: |
494 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
495 | BL_INLINE BLResult quadTo(const BLPoint& p1, const BLPoint& p2) noexcept { |
496 | return blPathQuadTo(this, p1.x, p1.y, p2.x, p2.y); |
497 | } |
498 | |
499 | //! Adds a quadratic curve to `[x1, y1]` and `[x2, y2]`. |
500 | //! |
501 | //! Appends the following commands to the path: |
502 | //! - `BL_PATH_CMD_QUAD[x1, y1]` |
503 | //! - `BL_PATH_CMD_ON[x2, y2]` |
504 | //! |
505 | //! Matches SVG 'Q' path command: |
506 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
507 | BL_INLINE BLResult quadTo(double x1, double y1, double x2, double y2) noexcept { |
508 | return blPathQuadTo(this, x1, y1, x2, y2); |
509 | } |
510 | |
511 | //! Adds a cubic curve to `p1`, `p2`, `p3`. |
512 | //! |
513 | //! Appends the following commands to the path: |
514 | //! - `BL_PATH_CMD_CUBIC[p1]` |
515 | //! - `BL_PATH_CMD_CUBIC[p2]` |
516 | //! - `BL_PATH_CMD_ON[p3]` |
517 | //! |
518 | //! Matches SVG 'C' path command: |
519 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands |
520 | BL_INLINE BLResult cubicTo(const BLPoint& p1, const BLPoint& p2, const BLPoint& p3) noexcept { |
521 | return blPathCubicTo(this, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); |
522 | } |
523 | |
524 | //! Adds a cubic curve to `[x1, y1]`, `[x2, y2]`, and `[x3, y3]`. |
525 | //! |
526 | //! Appends the following commands to the path: |
527 | //! - `BL_PATH_CMD_CUBIC[x1, y1]` |
528 | //! - `BL_PATH_CMD_CUBIC[x2, y2]` |
529 | //! - `BL_PATH_CMD_ON[x3, y3]` |
530 | //! |
531 | //! Matches SVG 'C' path command: |
532 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands |
533 | BL_INLINE BLResult cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) noexcept { |
534 | return blPathCubicTo(this, x1, y1, x2, y2, x3, y3); |
535 | } |
536 | |
537 | //! Adds a smooth quadratic curve to `p2`, calculating `p1` from last points. |
538 | //! |
539 | //! Appends the following commands to the path: |
540 | //! - `BL_PATH_CMD_QUAD[calculated]` |
541 | //! - `BL_PATH_CMD_ON[p2]` |
542 | //! |
543 | //! Matches SVG 'T' path command: |
544 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
545 | BL_INLINE BLResult smoothQuadTo(const BLPoint& p2) noexcept { |
546 | return blPathSmoothQuadTo(this, p2.x, p2.y); |
547 | } |
548 | |
549 | //! Adds a smooth quadratic curve to `[x2, y2]`, calculating `[x1, y1]` from last points. |
550 | //! |
551 | //! Appends the following commands to the path: |
552 | //! - `BL_PATH_CMD_QUAD[calculated]` |
553 | //! - `BL_PATH_CMD_ON[x2, y2]` |
554 | //! |
555 | //! Matches SVG 'T' path command: |
556 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands |
557 | BL_INLINE BLResult smoothQuadTo(double x2, double y2) noexcept { |
558 | return blPathSmoothQuadTo(this, x2, y2); |
559 | } |
560 | |
561 | //! Adds a smooth cubic curve to `p2` and `p3`, calculating `p1` from last points. |
562 | //! |
563 | //! Appends the following commands to the path: |
564 | //! - `BL_PATH_CMD_CUBIC[calculated]` |
565 | //! - `BL_PATH_CMD_CUBIC[p2]` |
566 | //! - `BL_PATH_CMD_ON[p3]` |
567 | //! |
568 | //! Matches SVG 'S' path command: |
569 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands |
570 | BL_INLINE BLResult smoothCubicTo(const BLPoint& p2, const BLPoint& p3) noexcept { |
571 | return blPathSmoothCubicTo(this, p2.x, p2.y, p3.x, p3.y); |
572 | } |
573 | |
574 | //! Adds a smooth cubic curve to `[x2, y2]` and `[x3, y3]`, calculating `[x1, y1]` from last points. |
575 | //! |
576 | //! Appends the following commands to the path: |
577 | //! - `BL_PATH_CMD_CUBIC[calculated]` |
578 | //! - `BL_PATH_CMD_CUBIC[x2, y2]` |
579 | //! - `BL_PATH_CMD_ON[x3, y3]` |
580 | //! |
581 | //! Matches SVG 'S' path command: |
582 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands |
583 | BL_INLINE BLResult smoothCubicTo(double x2, double y2, double x3, double y3) noexcept { |
584 | return blPathSmoothCubicTo(this, x2, y2, x3, y3); |
585 | } |
586 | |
587 | //! Adds an arc to the path. |
588 | //! |
589 | //! The center of the arc is specified by `c` and radius by `r`. Both `start` |
590 | //! and `sweep` angles are in radians. If the last vertex doesn't match the |
591 | //! start of the arc then a `lineTo()` would be emitted before adding the arc. |
592 | //! Pass `true` in `forceMoveTo` to always emit `moveTo()` at the beginning of |
593 | //! the arc, which starts a new figure. |
594 | BL_INLINE BLResult arcTo(const BLPoint& c, const BLPoint& r, double start, double sweep, bool forceMoveTo = false) noexcept { |
595 | return blPathArcTo(this, c.x, c.y, r.x, r.y, start, sweep, forceMoveTo); |
596 | } |
597 | |
598 | //! \overload |
599 | BL_INLINE BLResult arcTo(double cx, double cy, double rx, double ry, double start, double sweep, bool forceMoveTo = false) noexcept { |
600 | return blPathArcTo(this, cx, cy, rx, ry, start, sweep, forceMoveTo); |
601 | } |
602 | |
603 | //! Adds an arc quadrant (90deg) to the path. The first point `p1` specifies |
604 | //! the quadrant corner and the last point `p2` specifies the end point. |
605 | BL_INLINE BLResult arcQuadrantTo(const BLPoint& p1, const BLPoint& p2) noexcept { |
606 | return blPathArcQuadrantTo(this, p1.x, p1.y, p2.x, p2.y); |
607 | } |
608 | |
609 | //! \overload |
610 | BL_INLINE BLResult arcQuadrantTo(double x1, double y1, double x2, double y2) noexcept { |
611 | return blPathArcQuadrantTo(this, x1, y1, x2, y2); |
612 | } |
613 | |
614 | //! Adds an elliptic arc to the path that follows the SVG specification. |
615 | //! |
616 | //! Matches SVG 'A' path command: |
617 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands |
618 | BL_INLINE BLResult ellipticArcTo(const BLPoint& rp, double xAxisRotation, bool largeArcFlag, bool sweepFlag, const BLPoint& p1) noexcept { |
619 | return blPathEllipticArcTo(this, rp.x, rp.y, xAxisRotation, largeArcFlag, sweepFlag, p1.x, p1.y); |
620 | } |
621 | |
622 | //! \overload |
623 | BL_INLINE BLResult ellipticArcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, bool sweepFlag, double x1, double y1) noexcept { |
624 | return blPathEllipticArcTo(this, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x1, y1); |
625 | } |
626 | |
627 | //! Closes the current figure. |
628 | //! |
629 | //! Appends `BL_PATH_CMD_CLOSE` to the path. |
630 | //! |
631 | //! Matches SVG 'Z' path command: |
632 | //! - https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand |
633 | BL_INLINE BLResult close() noexcept { return blPathClose(this); } |
634 | |
635 | //! \} |
636 | |
637 | //! \name Adding Figures |
638 | //! \{ |
639 | |
640 | //! Adds a closed rectangle to the path specified by `box`. |
641 | BL_INLINE BLResult addBox(const BLBoxI& box, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
642 | return blPathAddBoxI(this, &box, dir); |
643 | } |
644 | |
645 | //! Adds a closed rectangle to the path specified by `box`. |
646 | BL_INLINE BLResult addBox(const BLBox& box, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
647 | return blPathAddBoxD(this, &box, dir); |
648 | } |
649 | |
650 | //! Adds a closed rectangle to the path specified by `[x0, y0, x1, y1]`. |
651 | BL_INLINE BLResult addBox(double x0, double y0, double x1, double y1, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
652 | return addBox(BLBox(x0, y0, x1, y1), dir); |
653 | } |
654 | |
655 | //! Adds a closed rectangle to the path specified by `rect`. |
656 | BL_INLINE BLResult addRect(const BLRectI& rect, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
657 | return blPathAddRectI(this, &rect, dir); |
658 | } |
659 | |
660 | //! Adds a closed rectangle to the path specified by `rect`. |
661 | BL_INLINE BLResult addRect(const BLRect& rect, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
662 | return blPathAddRectD(this, &rect, dir); |
663 | } |
664 | |
665 | //! Adds a closed rectangle to the path specified by `[x, y, w, h]`. |
666 | BL_INLINE BLResult addRect(double x, double y, double w, double h, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
667 | return addRect(BLRect(x, y, w, h), dir); |
668 | } |
669 | |
670 | //! Adds a geometry to the path. |
671 | BL_INLINE BLResult addGeometry(uint32_t geometryType, const void* geometryData, const BLMatrix2D* m = nullptr, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
672 | return blPathAddGeometry(this, geometryType, geometryData, m, dir); |
673 | } |
674 | |
675 | //! Adds a closed circle to the path. |
676 | BL_INLINE BLResult addCircle(const BLCircle& circle, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
677 | return addGeometry(BL_GEOMETRY_TYPE_CIRCLE, &circle, nullptr, dir); |
678 | } |
679 | |
680 | //! \overload |
681 | BL_INLINE BLResult addCircle(const BLCircle& circle, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
682 | return addGeometry(BL_GEOMETRY_TYPE_CIRCLE, &circle, &m, dir); |
683 | } |
684 | |
685 | //! Adds a closed ellipse to the path. |
686 | BL_INLINE BLResult addEllipse(const BLEllipse& ellipse, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
687 | return addGeometry(BL_GEOMETRY_TYPE_ELLIPSE, &ellipse, nullptr, dir); |
688 | } |
689 | |
690 | //! \overload |
691 | BL_INLINE BLResult addEllipse(const BLEllipse& ellipse, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
692 | return addGeometry(BL_GEOMETRY_TYPE_ELLIPSE, &ellipse, &m, dir); |
693 | } |
694 | |
695 | //! Adds a closed rounded ractangle to the path. |
696 | BL_INLINE BLResult addRoundRect(const BLRoundRect& rr, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
697 | return addGeometry(BL_GEOMETRY_TYPE_ROUND_RECT, &rr, nullptr, dir); |
698 | } |
699 | |
700 | //! \overload |
701 | BL_INLINE BLResult addRoundRect(const BLRoundRect& rr, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
702 | return addGeometry(BL_GEOMETRY_TYPE_ROUND_RECT, &rr, &m, dir); |
703 | } |
704 | |
705 | //! Adds an unclosed arc to the path. |
706 | BL_INLINE BLResult addArc(const BLArc& arc, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
707 | return addGeometry(BL_GEOMETRY_TYPE_ARC, &arc, nullptr, dir); |
708 | } |
709 | |
710 | //! \overload |
711 | BL_INLINE BLResult addArc(const BLArc& arc, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
712 | return addGeometry(BL_GEOMETRY_TYPE_ARC, &arc, &m, dir); |
713 | } |
714 | |
715 | //! Adds a closed chord to the path. |
716 | BL_INLINE BLResult addChord(const BLArc& chord, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
717 | return addGeometry(BL_GEOMETRY_TYPE_CHORD, &chord, nullptr, dir); |
718 | } |
719 | |
720 | //! \overload |
721 | BL_INLINE BLResult addChord(const BLArc& chord, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
722 | return addGeometry(BL_GEOMETRY_TYPE_CHORD, &chord, &m, dir); |
723 | } |
724 | |
725 | //! Adds a closed pie to the path. |
726 | BL_INLINE BLResult addPie(const BLArc& pie, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
727 | return addGeometry(BL_GEOMETRY_TYPE_PIE, &pie, nullptr, dir); |
728 | } |
729 | |
730 | //! \overload |
731 | BL_INLINE BLResult addPie(const BLArc& pie, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
732 | return addGeometry(BL_GEOMETRY_TYPE_PIE, &pie, &m, dir); |
733 | } |
734 | |
735 | //! Adds an unclosed line to the path. |
736 | BL_INLINE BLResult addLine(const BLLine& line, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
737 | return addGeometry(BL_GEOMETRY_TYPE_LINE, &line, nullptr, dir); |
738 | } |
739 | |
740 | //! \overload |
741 | BL_INLINE BLResult addLine(const BLLine& line, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
742 | return addGeometry(BL_GEOMETRY_TYPE_LINE, &line, &m, dir); |
743 | } |
744 | |
745 | //! Adds a closed triangle. |
746 | BL_INLINE BLResult addTriangle(const BLTriangle& triangle, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
747 | return addGeometry(BL_GEOMETRY_TYPE_TRIANGLE, &triangle, nullptr, dir); |
748 | } |
749 | |
750 | //! \overload |
751 | BL_INLINE BLResult addTriangle(const BLTriangle& triangle, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
752 | return addGeometry(BL_GEOMETRY_TYPE_TRIANGLE, &triangle, &m, dir); |
753 | } |
754 | |
755 | //! Adds a polyline. |
756 | BL_INLINE BLResult addPolyline(const BLArrayView<BLPointI>& poly, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
757 | return addGeometry(BL_GEOMETRY_TYPE_POLYLINEI, &poly, nullptr, dir); |
758 | } |
759 | |
760 | //! \overload |
761 | BL_INLINE BLResult addPolyline(const BLArrayView<BLPointI>& poly, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
762 | return addGeometry(BL_GEOMETRY_TYPE_POLYLINEI, &poly, &m, dir); |
763 | } |
764 | |
765 | //! \overload |
766 | BL_INLINE BLResult addPolyline(const BLPointI* poly, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
767 | return addPolyline(BLArrayView<BLPointI>{poly, n}, dir); |
768 | } |
769 | |
770 | //! \overload |
771 | BL_INLINE BLResult addPolyline(const BLPointI* poly, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
772 | return addPolyline(BLArrayView<BLPointI>{poly, n}, m, dir); |
773 | } |
774 | |
775 | //! Adds a polyline. |
776 | BL_INLINE BLResult addPolyline(const BLArrayView<BLPoint>& poly, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
777 | return addGeometry(BL_GEOMETRY_TYPE_POLYLINED, &poly, nullptr, dir); |
778 | } |
779 | |
780 | //! \overload |
781 | BL_INLINE BLResult addPolyline(const BLArrayView<BLPoint>& poly, const BLMatrix2D& m, uint32_t dir) { |
782 | return addGeometry(BL_GEOMETRY_TYPE_POLYLINED, &poly, &m, dir); |
783 | } |
784 | |
785 | //! \overload |
786 | BL_INLINE BLResult addPolyline(const BLPoint* poly, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
787 | return addPolyline(BLArrayView<BLPoint>{poly, n}, dir); |
788 | } |
789 | |
790 | //! \overload |
791 | BL_INLINE BLResult addPolyline(const BLPoint* poly, size_t n, const BLMatrix2D& m, uint32_t dir) { |
792 | return addPolyline(BLArrayView<BLPoint>{poly, n}, m, dir); |
793 | } |
794 | |
795 | //! Adds a polygon. |
796 | BL_INLINE BLResult addPolygon(const BLArrayView<BLPointI>& poly, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
797 | return addGeometry(BL_GEOMETRY_TYPE_POLYGONI, &poly, nullptr, dir); |
798 | } |
799 | |
800 | //! \overload |
801 | BL_INLINE BLResult addPolygon(const BLArrayView<BLPointI>& poly, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
802 | return addGeometry(BL_GEOMETRY_TYPE_POLYGONI, &poly, &m, dir); |
803 | } |
804 | |
805 | //! \overload |
806 | BL_INLINE BLResult addPolygon(const BLPointI* poly, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
807 | return addPolygon(BLArrayView<BLPointI>{poly, n}, dir); |
808 | } |
809 | |
810 | //! \overload |
811 | BL_INLINE BLResult addPolygon(const BLPointI* poly, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
812 | return addPolygon(BLArrayView<BLPointI>{poly, n}, m, dir); |
813 | } |
814 | |
815 | //! Adds a polygon. |
816 | BL_INLINE BLResult addPolygon(const BLArrayView<BLPoint>& poly, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
817 | return addGeometry(BL_GEOMETRY_TYPE_POLYGOND, &poly, nullptr, dir); |
818 | } |
819 | |
820 | //! \overload |
821 | BL_INLINE BLResult addPolygon(const BLArrayView<BLPoint>& poly, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
822 | return addGeometry(BL_GEOMETRY_TYPE_POLYGOND, &poly, &m, dir); |
823 | } |
824 | |
825 | //! \overload |
826 | BL_INLINE BLResult addPolygon(const BLPoint* poly, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
827 | return addPolygon(BLArrayView<BLPoint>{poly, n}, dir); |
828 | } |
829 | |
830 | //! \overload |
831 | BL_INLINE BLResult addPolygon(const BLPoint* poly, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
832 | return addPolygon(BLArrayView<BLPoint>{poly, n}, m, dir); |
833 | } |
834 | |
835 | //! Adds an array of closed boxes. |
836 | BL_INLINE BLResult addBoxArray(const BLArrayView<BLBoxI>& array, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
837 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, &array, nullptr, dir); |
838 | } |
839 | |
840 | //! \overload |
841 | BL_INLINE BLResult addBoxArray(const BLArrayView<BLBoxI>& array, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
842 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, &array, &m, dir); |
843 | } |
844 | |
845 | //! \overload |
846 | BL_INLINE BLResult addBoxArray(const BLBoxI* data, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
847 | return addBoxArray(BLArrayView<BLBoxI>{data, n}, dir); |
848 | } |
849 | |
850 | //! \overload |
851 | BL_INLINE BLResult addBoxArray(const BLBoxI* data, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
852 | return addBoxArray(BLArrayView<BLBoxI>{data, n}, m, dir); |
853 | } |
854 | |
855 | //! Adds an array of closed boxes. |
856 | BL_INLINE BLResult addBoxArray(const BLArrayView<BLBox>& array, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
857 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, &array, nullptr, dir); |
858 | } |
859 | |
860 | //! \overload |
861 | BL_INLINE BLResult addBoxArray(const BLArrayView<BLBox>& array, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
862 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, &array, &m, dir); |
863 | } |
864 | |
865 | //! \overload |
866 | BL_INLINE BLResult addBoxArray(const BLBox* data, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
867 | return addBoxArray(BLArrayView<BLBox>{data, n}, dir); |
868 | } |
869 | |
870 | //! \overload |
871 | BL_INLINE BLResult addBoxArray(const BLBox* data, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
872 | return addBoxArray(BLArrayView<BLBox>{data, n}, m, dir); |
873 | } |
874 | |
875 | //! Adds an array of closed rectangles. |
876 | BL_INLINE BLResult addRectArray(const BLArrayView<BLRectI>& array, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
877 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, &array, nullptr, dir); |
878 | } |
879 | |
880 | //! \overload |
881 | BL_INLINE BLResult addRectArray(const BLArrayView<BLRectI>& array, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
882 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, &array, &m, dir); |
883 | } |
884 | |
885 | //! \overload |
886 | BL_INLINE BLResult addRectArray(const BLRectI* data, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
887 | return addRectArray(BLArrayView<BLRectI>{data, n}, dir); |
888 | } |
889 | |
890 | //! \overload |
891 | BL_INLINE BLResult addRectArray(const BLRectI* data, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
892 | return addRectArray(BLArrayView<BLRectI>{data, n}, m, dir); |
893 | } |
894 | |
895 | //! Adds an array of closed rectangles. |
896 | BL_INLINE BLResult addRectArray(const BLArrayView<BLRect>& array, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
897 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, &array, nullptr, dir); |
898 | } |
899 | |
900 | //! \overload |
901 | BL_INLINE BLResult addRectArray(const BLArrayView<BLRect>& array, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
902 | return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, &array, &m, dir); |
903 | } |
904 | |
905 | //! \overload |
906 | BL_INLINE BLResult addRectArray(const BLRect* data, size_t n, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
907 | return addRectArray(BLArrayView<BLRect>{data, n}, dir); |
908 | } |
909 | |
910 | //! \overload |
911 | BL_INLINE BLResult addRectArray(const BLRect* data, size_t n, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
912 | return addRectArray(BLArrayView<BLRect>{data, n}, m, dir); |
913 | } |
914 | |
915 | //! Adds a closed region (converted to set of rectangles). |
916 | BL_INLINE BLResult addRegion(const BLRegion& region, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
917 | return addGeometry(BL_GEOMETRY_TYPE_REGION, ®ion, nullptr, dir); |
918 | } |
919 | |
920 | //! Adds a closed region (converted to set of rectangles). |
921 | BL_INLINE BLResult addRegion(const BLRegion& region, const BLMatrix2D& m, uint32_t dir = BL_GEOMETRY_DIRECTION_CW) noexcept { |
922 | return addGeometry(BL_GEOMETRY_TYPE_REGION, ®ion, &m, dir); |
923 | } |
924 | |
925 | //! \} |
926 | |
927 | //! \name Adding Paths |
928 | //! \{ |
929 | |
930 | //! Adds other `path` to this path. |
931 | BL_INLINE BLResult addPath(const BLPath& path) noexcept { |
932 | return blPathAddPath(this, &path, nullptr); |
933 | } |
934 | |
935 | //! Adds other `path` sliced by the given `range` to this path. |
936 | BL_INLINE BLResult addPath(const BLPath& path, const BLRange& range) noexcept { |
937 | return blPathAddPath(this, &path, &range); |
938 | } |
939 | |
940 | //! Adds other `path` translated by `p` to this path. |
941 | BL_INLINE BLResult addPath(const BLPath& path, const BLPoint& p) noexcept { |
942 | return blPathAddTranslatedPath(this, &path, nullptr, &p); |
943 | } |
944 | |
945 | //! Adds other `path` translated by `p` and sliced by the given `range` to this path. |
946 | BL_INLINE BLResult addPath(const BLPath& path, const BLRange& range, const BLPoint& p) noexcept { |
947 | return blPathAddTranslatedPath(this, &path, &range, &p); |
948 | } |
949 | |
950 | //! Adds other `path` transformed by `m` to this path. |
951 | BL_INLINE BLResult addPath(const BLPath& path, const BLMatrix2D& m) noexcept { |
952 | return blPathAddTransformedPath(this, &path, nullptr, &m); |
953 | } |
954 | |
955 | //! Adds other `path` transformed by `m` and sliced by the given `range` to this path. |
956 | BL_INLINE BLResult addPath(const BLPath& path, const BLRange& range, const BLMatrix2D& m) noexcept { |
957 | return blPathAddTransformedPath(this, &path, &range, &m); |
958 | } |
959 | |
960 | //! Adds other `path`, but reversed. |
961 | BL_INLINE BLResult addReversedPath(const BLPath& path, uint32_t reverseMode) noexcept { |
962 | return blPathAddReversedPath(this, &path, nullptr, reverseMode); |
963 | } |
964 | |
965 | //! Adds other `path`, but reversed. |
966 | BL_INLINE BLResult addReversedPath(const BLPath& path, const BLRange& range, uint32_t reverseMode) noexcept { |
967 | return blPathAddReversedPath(this, &path, &range, reverseMode); |
968 | } |
969 | |
970 | //! Adds a stroke of `path` to this path. |
971 | BL_INLINE BLResult addStrokedPath(const BLPath& path, const BLRange& range, const BLStrokeOptions& strokeOptions, const BLApproximationOptions& approximationOptions) noexcept { |
972 | return blPathAddStrokedPath(this, &path, &range, &strokeOptions, &approximationOptions); |
973 | } |
974 | //! \overload |
975 | BL_INLINE BLResult addStrokedPath(const BLPath& path, const BLStrokeOptions& strokeOptions, const BLApproximationOptions& approximationOptions) noexcept { |
976 | return blPathAddStrokedPath(this, &path, nullptr, &strokeOptions, &approximationOptions); |
977 | } |
978 | |
979 | //! \} |
980 | |
981 | //! \name Transformations |
982 | //! \{ |
983 | |
984 | //! Translates the whole path by `p`. |
985 | BL_INLINE BLResult translate(const BLPoint& p) noexcept { |
986 | return blPathTranslate(this, nullptr, &p); |
987 | } |
988 | |
989 | //! Translates a part of the path specified by the given `range` by `p`. |
990 | BL_INLINE BLResult translate(const BLRange& range, const BLPoint& p) noexcept { |
991 | return blPathTranslate(this, &range, &p); |
992 | } |
993 | |
994 | //! Transforms the whole path by matrix `m`. |
995 | BL_INLINE BLResult transform(const BLMatrix2D& m) noexcept { |
996 | return blPathTransform(this, nullptr, &m); |
997 | } |
998 | |
999 | //! Transforms a part of the path specified by the given `range` by matrix `m`. |
1000 | BL_INLINE BLResult transform(const BLRange& range, const BLMatrix2D& m) noexcept { |
1001 | return blPathTransform(this, &range, &m); |
1002 | } |
1003 | |
1004 | //! Fits the whole path into the given `rect` by taking into account fit flags passed by `fitFlags`. |
1005 | BL_INLINE BLResult fitTo(const BLRect& rect, uint32_t fitFlags) noexcept { |
1006 | return blPathFitTo(this, nullptr, &rect, fitFlags); |
1007 | } |
1008 | |
1009 | //! Fits a parh of the path specified by the given `range` into the given `rect` by taking into account fit flags passed by `fitFlags`. |
1010 | BL_INLINE BLResult fitTo(const BLRange& range, const BLRect& rect, uint32_t fitFlags) noexcept { |
1011 | return blPathFitTo(this, &range, &rect, fitFlags); |
1012 | } |
1013 | |
1014 | //! \} |
1015 | |
1016 | //! \name Path Information |
1017 | //! \{ |
1018 | |
1019 | //! Update a path information if necessary. |
1020 | BL_INLINE BLResult getInfoFlags(uint32_t* flagsOut) const noexcept { |
1021 | return blPathGetInfoFlags(this, flagsOut); |
1022 | } |
1023 | |
1024 | //! Stores a bounding box of all vertices and control points to `boxOut`. |
1025 | //! |
1026 | //! Control box is simply bounds of all vertices the path has without further |
1027 | //! processing. It contains both on-path and off-path points. Consider using |
1028 | //! `getBoundingBox()` if you need a visual bounding box. |
1029 | BL_INLINE BLResult getControlBox(BLBox* boxOut) const noexcept { |
1030 | return blPathGetControlBox(this, boxOut); |
1031 | } |
1032 | |
1033 | //! Stores a bounding box of all on-path vertices and curve extremas to `boxOut`. |
1034 | //! |
1035 | //! The bounding box stored to `boxOut` could be smaller than a bounding box |
1036 | //! obtained by `getControlBox()` as it's calculated by merging only start/end |
1037 | //! points and curves at their extremas (not control points). The resulting |
1038 | //! bounding box represents a visual bounds of the path. |
1039 | BL_INLINE BLResult getBoundingBox(BLBox* boxOut) const noexcept { |
1040 | return blPathGetBoundingBox(this, boxOut); |
1041 | } |
1042 | |
1043 | //! Returns the range describing a figure at the given `index`. |
1044 | BL_INLINE BLResult getFigureRange(size_t index, BLRange* rangeOut) const noexcept { |
1045 | return blPathGetFigureRange(this, index, rangeOut); |
1046 | } |
1047 | |
1048 | //! Returns the last vertex of the path and stores it to `vtxOut`. If the very |
1049 | //! last command of the path is `BL_PATH_CMD_CLOSE` then the path will be |
1050 | //! iterated in reverse order to match the initial vertex of the last figure. |
1051 | BL_INLINE BLResult getLastVertex(BLPoint* vtxOut) noexcept { |
1052 | return blPathGetLastVertex(this, vtxOut); |
1053 | } |
1054 | |
1055 | BL_INLINE BLResult getClosestVertex(const BLPoint& p, double maxDistance, size_t* indexOut) const noexcept { |
1056 | double distanceOut; |
1057 | return blPathGetClosestVertex(this, &p, maxDistance, indexOut, &distanceOut); |
1058 | } |
1059 | |
1060 | BL_INLINE BLResult getClosestVertex(const BLPoint& p, double maxDistance, size_t* indexOut, double* distanceOut) const noexcept { |
1061 | return blPathGetClosestVertex(this, &p, maxDistance, indexOut, distanceOut); |
1062 | } |
1063 | |
1064 | //! \} |
1065 | |
1066 | //! \name Hit Testing |
1067 | //! \{ |
1068 | |
1069 | //! Hit tests the given point `p` by respecting the given `fillRule`. |
1070 | BL_INLINE uint32_t hitTest(const BLPoint& p, uint32_t fillRule) const noexcept { |
1071 | return blPathHitTest(this, &p, fillRule); |
1072 | } |
1073 | |
1074 | //! \} |
1075 | |
1076 | static BL_INLINE const BLPath& none() noexcept { return reinterpret_cast<const BLPath*>(blNone)[kImplType]; } |
1077 | }; |
1078 | #endif |
1079 | |
1080 | //! \} |
1081 | |
1082 | #endif // BLEND2D_BLPATH_H |
1083 | |