1358 lines
54 KiB
C
1358 lines
54 KiB
C
|
// This file is part of Blend2D project <https://blend2d.com>
|
||
|
//
|
||
|
// See blend2d.h or LICENSE.md for license and copyright information
|
||
|
// SPDX-License-Identifier: Zlib
|
||
|
|
||
|
#ifndef BLEND2D_PATH_H_INCLUDED
|
||
|
#define BLEND2D_PATH_H_INCLUDED
|
||
|
|
||
|
#include "array.h"
|
||
|
#include "geometry.h"
|
||
|
#include "object.h"
|
||
|
|
||
|
//! \addtogroup blend2d_api_geometry
|
||
|
//! \{
|
||
|
|
||
|
//! \name BLPath - Constants
|
||
|
//! \{
|
||
|
|
||
|
//! Path command.
|
||
|
BL_DEFINE_ENUM(BLPathCmd) {
|
||
|
//! Move-to command (starts a new figure).
|
||
|
BL_PATH_CMD_MOVE = 0,
|
||
|
//! On-path command (interpreted as line-to or the end of a curve).
|
||
|
BL_PATH_CMD_ON = 1,
|
||
|
//! Quad-to control point.
|
||
|
BL_PATH_CMD_QUAD = 2,
|
||
|
//! Conic-to control point
|
||
|
BL_PATH_CMD_CONIC = 3,
|
||
|
//! Cubic-to control point (always used as a pair of commands).
|
||
|
BL_PATH_CMD_CUBIC = 4,
|
||
|
//! Close path.
|
||
|
BL_PATH_CMD_CLOSE = 5,
|
||
|
|
||
|
//! Conic weight.
|
||
|
//!
|
||
|
//! \note This is not a point. This is a pair of values from which only the first (x) is used to represent weight
|
||
|
//! as used by conic curve. The other value (y) is always set to NaN by Blend2D, but can be arbitrary as it has
|
||
|
//! no meaning.
|
||
|
BL_PATH_CMD_WEIGHT = 6,
|
||
|
|
||
|
//! Maximum value of `BLPathCmd`.
|
||
|
BL_PATH_CMD_MAX_VALUE = 6
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_PATH_CMD)
|
||
|
};
|
||
|
|
||
|
//! Path command (never stored in path).
|
||
|
BL_DEFINE_ENUM(BLPathCmdExtra) {
|
||
|
//! Used by `BLPath::setVertexAt` to preserve the current command value.
|
||
|
BL_PATH_CMD_PRESERVE = 0xFFFFFFFFu
|
||
|
};
|
||
|
|
||
|
//! Path flags.
|
||
|
BL_DEFINE_ENUM(BLPathFlags) {
|
||
|
//! No flags.
|
||
|
BL_PATH_NO_FLAGS = 0u,
|
||
|
//! Path is empty (no commands or close commands only).
|
||
|
BL_PATH_FLAG_EMPTY = 0x00000001u,
|
||
|
//! Path contains multiple figures.
|
||
|
BL_PATH_FLAG_MULTIPLE = 0x00000002u,
|
||
|
//! Path contains one or more quad curves.
|
||
|
BL_PATH_FLAG_QUADS = 0x00000004u,
|
||
|
//! Path contains one or more conic curves.
|
||
|
BL_PATH_FLAG_CONICS = 0x00000008u,
|
||
|
//! Path contains one or more cubic curves.
|
||
|
BL_PATH_FLAG_CUBICS = 0x00000010u,
|
||
|
//! Path is invalid.
|
||
|
BL_PATH_FLAG_INVALID = 0x40000000u,
|
||
|
//! Flags are dirty (not reflecting the current status).
|
||
|
BL_PATH_FLAG_DIRTY = 0x80000000u
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_PATH_FLAG)
|
||
|
};
|
||
|
|
||
|
//! Path reversal mode.
|
||
|
BL_DEFINE_ENUM(BLPathReverseMode) {
|
||
|
//! Reverse each figure and their order as well (default).
|
||
|
BL_PATH_REVERSE_MODE_COMPLETE = 0,
|
||
|
//! Reverse each figure separately (keeps their order).
|
||
|
BL_PATH_REVERSE_MODE_SEPARATE = 1,
|
||
|
|
||
|
//! Maximum value of `BLPathReverseMode`.
|
||
|
BL_PATH_REVERSE_MODE_MAX_VALUE = 1
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_PATH_REVERSE_MODE)
|
||
|
};
|
||
|
|
||
|
//! Stroke join type.
|
||
|
BL_DEFINE_ENUM(BLStrokeJoin) {
|
||
|
//! Miter-join possibly clipped at `miterLimit` [default].
|
||
|
BL_STROKE_JOIN_MITER_CLIP = 0,
|
||
|
//! Miter-join or bevel-join depending on miterLimit condition.
|
||
|
BL_STROKE_JOIN_MITER_BEVEL = 1,
|
||
|
//! Miter-join or round-join depending on miterLimit condition.
|
||
|
BL_STROKE_JOIN_MITER_ROUND = 2,
|
||
|
//! Bevel-join.
|
||
|
BL_STROKE_JOIN_BEVEL = 3,
|
||
|
//! Round-join.
|
||
|
BL_STROKE_JOIN_ROUND = 4,
|
||
|
|
||
|
//! Maximum value of `BLStrokeJoin`.
|
||
|
BL_STROKE_JOIN_MAX_VALUE = 4
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_STROKE_JOIN)
|
||
|
};
|
||
|
|
||
|
//! Position of a stroke-cap.
|
||
|
BL_DEFINE_ENUM(BLStrokeCapPosition) {
|
||
|
//! Start of the path.
|
||
|
BL_STROKE_CAP_POSITION_START = 0,
|
||
|
//! End of the path.
|
||
|
BL_STROKE_CAP_POSITION_END = 1,
|
||
|
|
||
|
//! Maximum value of `BLStrokeCapPosition`.
|
||
|
BL_STROKE_CAP_POSITION_MAX_VALUE = 1
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_STROKE_CAP_POSITION)
|
||
|
};
|
||
|
|
||
|
//! A presentation attribute defining the shape to be used at the end of open sub-paths.
|
||
|
BL_DEFINE_ENUM(BLStrokeCap) {
|
||
|
//! Butt cap [default].
|
||
|
BL_STROKE_CAP_BUTT = 0,
|
||
|
//! Square cap.
|
||
|
BL_STROKE_CAP_SQUARE = 1,
|
||
|
//! Round cap.
|
||
|
BL_STROKE_CAP_ROUND = 2,
|
||
|
//! Round cap reversed.
|
||
|
BL_STROKE_CAP_ROUND_REV = 3,
|
||
|
//! Triangle cap.
|
||
|
BL_STROKE_CAP_TRIANGLE = 4,
|
||
|
//! Triangle cap reversed.
|
||
|
BL_STROKE_CAP_TRIANGLE_REV = 5,
|
||
|
|
||
|
//! Maximum value of `BLStrokeCap`.
|
||
|
BL_STROKE_CAP_MAX_VALUE = 5
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_STROKE_CAP)
|
||
|
};
|
||
|
|
||
|
//! Stroke transform order.
|
||
|
BL_DEFINE_ENUM(BLStrokeTransformOrder) {
|
||
|
//! Transform after stroke => `Transform(Stroke(Input))` [default].
|
||
|
BL_STROKE_TRANSFORM_ORDER_AFTER = 0,
|
||
|
//! Transform before stroke => `Stroke(Transform(Input))`.
|
||
|
BL_STROKE_TRANSFORM_ORDER_BEFORE = 1,
|
||
|
|
||
|
//! Maximum value of `BLStrokeTransformOrder`.
|
||
|
BL_STROKE_TRANSFORM_ORDER_MAX_VALUE = 1
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_STROKE_TRANSFORM_ORDER)
|
||
|
};
|
||
|
|
||
|
//! Mode that specifies how curves are approximated to line segments.
|
||
|
BL_DEFINE_ENUM(BLFlattenMode) {
|
||
|
//! Use default mode (decided by Blend2D).
|
||
|
BL_FLATTEN_MODE_DEFAULT = 0,
|
||
|
//! Recursive subdivision flattening.
|
||
|
BL_FLATTEN_MODE_RECURSIVE = 1,
|
||
|
|
||
|
//! Maximum value of `BLFlattenMode`.
|
||
|
BL_FLATTEN_MODE_MAX_VALUE = 1
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_FLATTEN_MODE)
|
||
|
};
|
||
|
|
||
|
//! Mode that specifies how to construct offset curves.
|
||
|
BL_DEFINE_ENUM(BLOffsetMode) {
|
||
|
//! Use default mode (decided by Blend2D).
|
||
|
BL_OFFSET_MODE_DEFAULT = 0,
|
||
|
//! Iterative offset construction.
|
||
|
BL_OFFSET_MODE_ITERATIVE = 1,
|
||
|
|
||
|
//! Maximum value of `BLOffsetMode`.
|
||
|
BL_OFFSET_MODE_MAX_VALUE = 1
|
||
|
|
||
|
BL_FORCE_ENUM_UINT32(BL_OFFSET_MODE)
|
||
|
};
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name BLPath - Structs
|
||
|
//! \{
|
||
|
|
||
|
//! Options used to describe how geometry is approximated.
|
||
|
//!
|
||
|
//! This struct cannot be simply zeroed and then passed to functions that accept approximation options.
|
||
|
//! Use `blDefaultApproximationOptions` to setup defaults and then alter values you want to change.
|
||
|
//!
|
||
|
//! Example of using `BLApproximationOptions`:
|
||
|
//!
|
||
|
//! ```
|
||
|
//! // Initialize with defaults first.
|
||
|
//! BLApproximationOptions approx = blDefaultApproximationOptions;
|
||
|
//!
|
||
|
//! // Override values you want to change.
|
||
|
//! approx.simplifyTolerance = 0.02;
|
||
|
//!
|
||
|
//! // ... now safely use approximation options in your code ...
|
||
|
//! ```
|
||
|
struct BLApproximationOptions {
|
||
|
//! Specifies how curves are flattened, see `FlattenMode`.
|
||
|
uint8_t flattenMode;
|
||
|
//! Specifies how curves are offsetted (used by stroking), see `BLOffsetMode`.
|
||
|
uint8_t offsetMode;
|
||
|
//! Reserved for future use, must be zero.
|
||
|
uint8_t reservedFlags[6];
|
||
|
|
||
|
//! Tolerance used to flatten curves.
|
||
|
double flattenTolerance;
|
||
|
//! Tolerance used to approximate cubic curves with quadratic curves.
|
||
|
double simplifyTolerance;
|
||
|
//! Curve offsetting parameter, exact meaning depends on `offsetMode`.
|
||
|
double offsetParameter;
|
||
|
};
|
||
|
|
||
|
//! 2D vector path view provides pointers to vertex and command data along with their size.
|
||
|
struct BLPathView {
|
||
|
const uint8_t* commandData;
|
||
|
const BLPoint* vertexData;
|
||
|
size_t size;
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
BL_INLINE_NODEBUG void reset() noexcept { *this = BLPathView{}; }
|
||
|
|
||
|
BL_INLINE_NODEBUG void reset(const uint8_t* commandDataIn, const BLPoint* vertexDataIn, size_t sizeIn) noexcept {
|
||
|
commandData = commandDataIn;
|
||
|
vertexData = vertexDataIn;
|
||
|
size = sizeIn;
|
||
|
}
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name BLPath - Globals
|
||
|
//!
|
||
|
//! 2D path functionality is provided by \ref BLPathCore in C API and wrapped by \ref BLPath in C++ API.
|
||
|
//!
|
||
|
//! \{
|
||
|
BL_BEGIN_C_DECLS
|
||
|
|
||
|
//! Default approximation options used by Blend2D.
|
||
|
extern BL_API const BLApproximationOptions blDefaultApproximationOptions;
|
||
|
|
||
|
BL_END_C_DECLS
|
||
|
//! \}
|
||
|
|
||
|
//! \name BLPath - C API
|
||
|
//! \{
|
||
|
|
||
|
//! Optional callback that can be used to consume a path data.
|
||
|
typedef BLResult (BL_CDECL* BLPathSinkFunc)(BLPathCore* path, const void* info, void* userData) BL_NOEXCEPT;
|
||
|
|
||
|
//! This is a sink that is used by path offsetting. This sink consumes both `a` and `b` offsets of the path. The sink
|
||
|
//! will be called for each figure and is responsible for joining these paths. If the paths are not closed then the
|
||
|
//! sink must insert start cap, then join `b`, and then insert end cap.
|
||
|
//!
|
||
|
//! The sink must also clean up the paths as this is not done by the offsetter. The reason is that in case the `a` path
|
||
|
//! is the output path you can just keep it and insert `b` path into it (clearing only `b` path after each call).
|
||
|
typedef BLResult (BL_CDECL* BLPathStrokeSinkFunc)(BLPathCore* a, BLPathCore* b, BLPathCore* c, size_t inputStart, size_t inputEnd, void* userData) BL_NOEXCEPT;
|
||
|
|
||
|
BL_BEGIN_C_DECLS
|
||
|
|
||
|
BL_API BLResult BL_CDECL blPathInit(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathInitMove(BLPathCore* self, BLPathCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathInitWeak(BLPathCore* self, const BLPathCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathDestroy(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathReset(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API size_t BL_CDECL blPathGetSize(const BLPathCore* self) BL_NOEXCEPT_C BL_PURE;
|
||
|
BL_API size_t BL_CDECL blPathGetCapacity(const BLPathCore* self) BL_NOEXCEPT_C BL_PURE;
|
||
|
BL_API const uint8_t* BL_CDECL blPathGetCommandData(const BLPathCore* self) BL_NOEXCEPT_C BL_PURE;
|
||
|
BL_API const BLPoint* BL_CDECL blPathGetVertexData(const BLPathCore* self) BL_NOEXCEPT_C BL_PURE;
|
||
|
BL_API BLResult BL_CDECL blPathClear(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathShrink(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathReserve(BLPathCore* self, size_t n) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathModifyOp(BLPathCore* self, BLModifyOp op, size_t n, uint8_t** cmdDataOut, BLPoint** vtxDataOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAssignMove(BLPathCore* self, BLPathCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAssignWeak(BLPathCore* self, const BLPathCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAssignDeep(BLPathCore* self, const BLPathCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathSetVertexAt(BLPathCore* self, size_t index, uint32_t cmd, double x, double y) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathMoveTo(BLPathCore* self, double x0, double y0) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathLineTo(BLPathCore* self, double x1, double y1) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathPolyTo(BLPathCore* self, const BLPoint* poly, size_t count) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathQuadTo(BLPathCore* self, double x1, double y1, double x2, double y2) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathConicTo(BLPathCore* self, double x1, double y1, double x2, double y2, double w) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathCubicTo(BLPathCore* self, double x1, double y1, double x2, double y2, double x3, double y3) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathSmoothQuadTo(BLPathCore* self, double x2, double y2) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathSmoothCubicTo(BLPathCore* self, double x2, double y2, double x3, double y3) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathArcTo(BLPathCore* self, double x, double y, double rx, double ry, double start, double sweep, bool forceMoveTo) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathArcQuadrantTo(BLPathCore* self, double x1, double y1, double x2, double y2) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathEllipticArcTo(BLPathCore* self, double rx, double ry, double xAxisRotation, bool largeArcFlag, bool sweepFlag, double x1, double y1) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathClose(BLPathCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddGeometry(BLPathCore* self, BLGeometryType geometryType, const void* geometryData, const BLMatrix2D* m, BLGeometryDirection dir) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddBoxI(BLPathCore* self, const BLBoxI* box, BLGeometryDirection dir) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddBoxD(BLPathCore* self, const BLBox* box, BLGeometryDirection dir) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddRectI(BLPathCore* self, const BLRectI* rect, BLGeometryDirection dir) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddRectD(BLPathCore* self, const BLRect* rect, BLGeometryDirection dir) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddPath(BLPathCore* self, const BLPathCore* other, const BLRange* range) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddTranslatedPath(BLPathCore* self, const BLPathCore* other, const BLRange* range, const BLPoint* p) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddTransformedPath(BLPathCore* self, const BLPathCore* other, const BLRange* range, const BLMatrix2D* m) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddReversedPath(BLPathCore* self, const BLPathCore* other, const BLRange* range, BLPathReverseMode reverseMode) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathAddStrokedPath(BLPathCore* self, const BLPathCore* other, const BLRange* range, const BLStrokeOptionsCore* options, const BLApproximationOptions* approx) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathRemoveRange(BLPathCore* self, const BLRange* range) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathTranslate(BLPathCore* self, const BLRange* range, const BLPoint* p) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathTransform(BLPathCore* self, const BLRange* range, const BLMatrix2D* m) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathFitTo(BLPathCore* self, const BLRange* range, const BLRect* rect, uint32_t fitFlags) BL_NOEXCEPT_C;
|
||
|
BL_API bool BL_CDECL blPathEquals(const BLPathCore* a, const BLPathCore* b) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetInfoFlags(const BLPathCore* self, uint32_t* flagsOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetControlBox(const BLPathCore* self, BLBox* boxOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetBoundingBox(const BLPathCore* self, BLBox* boxOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetFigureRange(const BLPathCore* self, size_t index, BLRange* rangeOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetLastVertex(const BLPathCore* self, BLPoint* vtxOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blPathGetClosestVertex(const BLPathCore* self, const BLPoint* p, double maxDistance, size_t* indexOut, double* distanceOut) BL_NOEXCEPT_C;
|
||
|
BL_API BLHitTest BL_CDECL blPathHitTest(const BLPathCore* self, const BLPoint* p, BLFillRule fillRule) BL_NOEXCEPT_C;
|
||
|
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsInit(BLStrokeOptionsCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsInitMove(BLStrokeOptionsCore* self, BLStrokeOptionsCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsInitWeak(BLStrokeOptionsCore* self, const BLStrokeOptionsCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsDestroy(BLStrokeOptionsCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsReset(BLStrokeOptionsCore* self) BL_NOEXCEPT_C;
|
||
|
BL_API bool BL_CDECL blStrokeOptionsEquals(const BLStrokeOptionsCore* a, const BLStrokeOptionsCore* b) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsAssignMove(BLStrokeOptionsCore* self, BLStrokeOptionsCore* other) BL_NOEXCEPT_C;
|
||
|
BL_API BLResult BL_CDECL blStrokeOptionsAssignWeak(BLStrokeOptionsCore* self, const BLStrokeOptionsCore* other) BL_NOEXCEPT_C;
|
||
|
|
||
|
BL_API BLResult BL_CDECL blPathStrokeToSink(
|
||
|
const BLPathCore* self,
|
||
|
const BLRange* range,
|
||
|
const BLStrokeOptionsCore* strokeOptions,
|
||
|
const BLApproximationOptions* approximationOptions,
|
||
|
BLPathCore *a,
|
||
|
BLPathCore *b,
|
||
|
BLPathCore *c,
|
||
|
BLPathStrokeSinkFunc sink, void* userData) BL_NOEXCEPT_C;
|
||
|
|
||
|
BL_END_C_DECLS
|
||
|
|
||
|
//! 2D vector path [C API].
|
||
|
struct BLPathCore BL_CLASS_INHERITS(BLObjectCore) {
|
||
|
BL_DEFINE_OBJECT_DETAIL
|
||
|
BL_DEFINE_OBJECT_DCAST(BLPath)
|
||
|
};
|
||
|
|
||
|
//! Stroke options [C API].
|
||
|
struct BLStrokeOptionsCore {
|
||
|
union {
|
||
|
struct {
|
||
|
uint8_t startCap;
|
||
|
uint8_t endCap;
|
||
|
uint8_t join;
|
||
|
uint8_t transformOrder;
|
||
|
uint8_t reserved[4];
|
||
|
};
|
||
|
uint8_t caps[BL_STROKE_CAP_POSITION_MAX_VALUE + 1];
|
||
|
uint64_t hints;
|
||
|
};
|
||
|
|
||
|
double width;
|
||
|
double miterLimit;
|
||
|
double dashOffset;
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
union { BLArray<double> dashArray; };
|
||
|
#else
|
||
|
BLArrayCore dashArray;
|
||
|
#endif
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
BL_INLINE_NODEBUG BLStrokeOptionsCore() noexcept {}
|
||
|
BL_INLINE_NODEBUG BLStrokeOptionsCore(const BLStrokeOptionsCore& other) noexcept { _copyFrom(other); }
|
||
|
BL_INLINE_NODEBUG ~BLStrokeOptionsCore() noexcept {}
|
||
|
BL_INLINE_NODEBUG BLStrokeOptionsCore& operator=(const BLStrokeOptionsCore& other) noexcept { _copyFrom(other); return *this; }
|
||
|
|
||
|
BL_INLINE void _copyFrom(const BLStrokeOptionsCore& other) noexcept {
|
||
|
hints = other.hints;
|
||
|
width = other.width;
|
||
|
miterLimit = other.miterLimit;
|
||
|
dashOffset = other.dashOffset;
|
||
|
dashArray._d = other.dashArray._d;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
BL_DEFINE_OBJECT_DCAST(BLStrokeOptions)
|
||
|
};
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \cond INTERNAL
|
||
|
//! \name BLPath - Internals
|
||
|
//! \{
|
||
|
|
||
|
//! 2D vector path [Impl].
|
||
|
struct BLPathImpl BL_CLASS_INHERITS(BLObjectImpl) {
|
||
|
//! Union of either raw path-data or their `view`.
|
||
|
union {
|
||
|
struct {
|
||
|
//! Command data
|
||
|
uint8_t* commandData;
|
||
|
//! Vertex data.
|
||
|
BLPoint* vertexData;
|
||
|
//! Vertex/command count.
|
||
|
size_t size;
|
||
|
};
|
||
|
//! Path data as view.
|
||
|
BLPathView view;
|
||
|
};
|
||
|
|
||
|
//! Path vertex/command capacity.
|
||
|
size_t capacity;
|
||
|
|
||
|
//! Path flags related to caching.
|
||
|
uint32_t flags;
|
||
|
};
|
||
|
|
||
|
//! \}
|
||
|
//! \endcond
|
||
|
|
||
|
//! \name BLPath - C++ API
|
||
|
//! \{
|
||
|
#ifdef __cplusplus
|
||
|
|
||
|
// Prevents the following:
|
||
|
// Base class XXX should be explicitly initialized in the copy constructor [-Wextra]
|
||
|
BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_EXTRA_WARNINGS)
|
||
|
|
||
|
//! Stroke options [C++ API].
|
||
|
//!
|
||
|
//! You should use this as a structure and use members of `BLStrokeOptionsCore` directly.
|
||
|
class BLStrokeOptions final : public BLStrokeOptionsCore {
|
||
|
public:
|
||
|
BL_INLINE BLStrokeOptions() noexcept { blStrokeOptionsInit(this); }
|
||
|
BL_INLINE BLStrokeOptions(BLStrokeOptions&& other) noexcept { blStrokeOptionsInitMove(this, &other); }
|
||
|
BL_INLINE BLStrokeOptions(const BLStrokeOptions& other) noexcept { blStrokeOptionsInitWeak(this, &other); }
|
||
|
BL_INLINE ~BLStrokeOptions() noexcept { blStrokeOptionsDestroy(this); }
|
||
|
|
||
|
BL_INLINE BLStrokeOptions& operator=(BLStrokeOptions&& other) noexcept { blStrokeOptionsAssignMove(this, &other); return *this; }
|
||
|
BL_INLINE BLStrokeOptions& operator=(const BLStrokeOptions& other) noexcept { blStrokeOptionsAssignWeak(this, &other); return *this; }
|
||
|
|
||
|
BL_INLINE bool operator==(const BLStrokeOptions& other) const noexcept { return equals(other); }
|
||
|
BL_INLINE bool operator!=(const BLStrokeOptions& other) const noexcept { return !equals(other); }
|
||
|
|
||
|
BL_INLINE BLResult reset() noexcept { return blStrokeOptionsReset(this); }
|
||
|
BL_INLINE bool equals(const BLStrokeOptions& other) const noexcept { return blStrokeOptionsEquals(this, &other); }
|
||
|
|
||
|
BL_INLINE BLResult assign(BLStrokeOptions&& other) noexcept { return blStrokeOptionsAssignMove(this, &other); }
|
||
|
BL_INLINE BLResult assign(const BLStrokeOptions& other) noexcept { return blStrokeOptionsAssignWeak(this, &other); }
|
||
|
|
||
|
BL_INLINE void setCaps(BLStrokeCap strokeCap) noexcept {
|
||
|
startCap = uint8_t(strokeCap);
|
||
|
endCap = uint8_t(strokeCap);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
BL_DIAGNOSTIC_POP
|
||
|
|
||
|
namespace BLInternal {
|
||
|
|
||
|
template<typename T>
|
||
|
static BL_INLINE size_t pathSegmentCount(const T&) noexcept { return T::kVertexCount; }
|
||
|
template<typename T, typename... Args>
|
||
|
static BL_INLINE size_t pathSegmentCount(const T&, Args&&... args) noexcept { return T::kVertexCount + pathSegmentCount(BLInternal::forward<Args>(args)...); }
|
||
|
|
||
|
template<typename T> void storePathSegmentCmd(uint8_t* cmd, const T& segment) noexcept = delete;
|
||
|
template<typename T> void storePathSegmentVtx(BLPoint* vtx, const T& segment) noexcept = delete;
|
||
|
|
||
|
template<typename T>
|
||
|
static BL_INLINE void storePathSegmentsCmd(uint8_t* cmd, const T& segment) noexcept { storePathSegmentCmd<T>(cmd, segment); }
|
||
|
|
||
|
template<typename T, typename... Args>
|
||
|
static BL_INLINE void storePathSegmentsCmd(uint8_t* cmd, const T& segment, Args&&... args) noexcept {
|
||
|
storePathSegmentCmd<T>(cmd, segment);
|
||
|
storePathSegmentsCmd(cmd + T::kVertexCount, BLInternal::forward<Args>(args)...);
|
||
|
}
|
||
|
|
||
|
template<typename T>
|
||
|
static BL_INLINE void storePathSegmentsVtx(BLPoint* vtx, const T& segment) noexcept { storePathSegmentVtx<T>(vtx, segment); }
|
||
|
|
||
|
template<typename T, typename... Args>
|
||
|
static BL_INLINE void storePathSegmentsVtx(BLPoint* vtx, const T& segment, Args&&... args) noexcept {
|
||
|
storePathSegmentVtx<T>(vtx, segment);
|
||
|
storePathSegmentsVtx(vtx + T::kVertexCount, BLInternal::forward<Args>(args)...);
|
||
|
}
|
||
|
|
||
|
} // {BLInternal}
|
||
|
|
||
|
//! 2D vector path [C++ API].
|
||
|
class BLPath /* final */ : public BLPathCore {
|
||
|
public:
|
||
|
//! \cond INTERNAL
|
||
|
BL_INLINE_NODEBUG BLPathImpl* _impl() const noexcept { return static_cast<BLPathImpl*>(_d.impl); }
|
||
|
//! \endcond
|
||
|
|
||
|
//! \name Construction & Destruction
|
||
|
//! \{
|
||
|
|
||
|
BL_INLINE_NODEBUG BLPath() noexcept { blPathInit(this); }
|
||
|
BL_INLINE_NODEBUG BLPath(BLPath&& other) noexcept { blPathInitMove(this, &other); }
|
||
|
BL_INLINE_NODEBUG BLPath(const BLPath& other) noexcept { blPathInitWeak(this, &other); }
|
||
|
BL_INLINE_NODEBUG ~BLPath() noexcept { blPathDestroy(this); }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Overloaded Operators
|
||
|
//! \{
|
||
|
|
||
|
BL_INLINE_NODEBUG explicit operator bool() const noexcept { return !empty(); }
|
||
|
|
||
|
BL_INLINE_NODEBUG BLPath& operator=(BLPath&& other) noexcept { blPathAssignMove(this, &other); return *this; }
|
||
|
BL_INLINE_NODEBUG BLPath& operator=(const BLPath& other) noexcept { blPathAssignWeak(this, &other); return *this; }
|
||
|
|
||
|
BL_NODISCARD BL_INLINE_NODEBUG bool operator==(const BLPath& other) const noexcept { return equals(other); }
|
||
|
BL_NODISCARD BL_INLINE_NODEBUG bool operator!=(const BLPath& other) const noexcept { return !equals(other); }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Common Functionality
|
||
|
//! \{
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult reset() noexcept { return blPathReset(this); }
|
||
|
BL_INLINE_NODEBUG void swap(BLPathCore& other) noexcept { _d.swap(other._d); }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Accessors
|
||
|
//! \{
|
||
|
|
||
|
//! Tests whether the path is empty, which means its size equals to zero.
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG bool empty() const noexcept { return size() == 0; }
|
||
|
|
||
|
//! Returns path size (count of vertices used).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG size_t size() const noexcept { return _impl()->size; }
|
||
|
|
||
|
//! Returns path capacity (count of allocated vertices).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG size_t capacity() const noexcept { return _impl()->capacity; }
|
||
|
|
||
|
//! Returns path's vertex data (read-only).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG const BLPoint* vertexData() const noexcept { return _impl()->vertexData; }
|
||
|
|
||
|
//! Returns the end of path's vertex data (read-only).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG const BLPoint* vertexDataEnd() const noexcept { return _impl()->vertexData + _impl()->size; }
|
||
|
|
||
|
//! Returns path's command data (read-only).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG const uint8_t* commandData() const noexcept { return _impl()->commandData; }
|
||
|
|
||
|
//! Returns the end of path's command data (read-only).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG const uint8_t* commandDataEnd() const noexcept { return _impl()->commandData + _impl()->size; }
|
||
|
|
||
|
//! Returns a read-only path data as `BLPathView`.
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG BLPathView view() const noexcept { return _impl()->view; }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Path Construction
|
||
|
//! \{
|
||
|
|
||
|
//! Clears the content of the path.
|
||
|
BL_INLINE_NODEBUG BLResult clear() noexcept {
|
||
|
return blPathClear(this);
|
||
|
}
|
||
|
|
||
|
//! Shrinks the capacity of the path to fit the current usage.
|
||
|
BL_INLINE_NODEBUG BLResult shrink() noexcept {
|
||
|
return blPathShrink(this);
|
||
|
}
|
||
|
|
||
|
//! Reserves the capacity of the path for at least `n` vertices and commands.
|
||
|
BL_INLINE_NODEBUG BLResult reserve(size_t n) noexcept {
|
||
|
return blPathReserve(this, n);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult modifyOp(BLModifyOp op, size_t n, uint8_t** cmdDataOut, BLPoint** vtxDataOut) noexcept {
|
||
|
return blPathModifyOp(this, op, n, cmdDataOut, vtxDataOut);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult assign(BLPathCore&& other) noexcept {
|
||
|
return blPathAssignMove(this, &other);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult assign(const BLPathCore& other) noexcept {
|
||
|
return blPathAssignWeak(this, &other);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult assignDeep(const BLPathCore& other) noexcept {
|
||
|
return blPathAssignDeep(this, &other);
|
||
|
}
|
||
|
|
||
|
//! Sets vertex at `index` to `cmd` and `pt`.
|
||
|
//!
|
||
|
//! Pass `BL_PATH_CMD_PRESERVE` in `cmd` to preserve the current command.
|
||
|
BL_INLINE_NODEBUG BLResult setVertexAt(size_t index, uint32_t cmd, const BLPoint& pt) noexcept {
|
||
|
return blPathSetVertexAt(this, index, cmd, pt.x, pt.y);
|
||
|
}
|
||
|
|
||
|
//! Sets vertex at `index` to `cmd` and `[x, y]`.
|
||
|
//!
|
||
|
//! Pass `BL_PATH_CMD_PRESERVE` in `cmd` to preserve the current command.
|
||
|
BL_INLINE_NODEBUG BLResult setVertexAt(size_t index, uint32_t cmd, double x, double y) noexcept {
|
||
|
return blPathSetVertexAt(this, index, cmd, x, y);
|
||
|
}
|
||
|
|
||
|
//! Moves to `p0`.
|
||
|
//!
|
||
|
//! Appends `BL_PATH_CMD_MOVE[p0]` command to the path.
|
||
|
BL_INLINE_NODEBUG BLResult moveTo(const BLPoint& p0) noexcept {
|
||
|
return blPathMoveTo(this, p0.x, p0.y);
|
||
|
}
|
||
|
|
||
|
//! Moves to `[x0, y0]`.
|
||
|
//!
|
||
|
//! Appends `BL_PATH_CMD_MOVE[x0, y0]` command to the path.
|
||
|
BL_INLINE_NODEBUG BLResult moveTo(double x0, double y0) noexcept {
|
||
|
return blPathMoveTo(this, x0, y0);
|
||
|
}
|
||
|
|
||
|
//! Adds line to `p1`.
|
||
|
//!
|
||
|
//! Appends `BL_PATH_CMD_ON[p1]` command to the path.
|
||
|
BL_INLINE_NODEBUG BLResult lineTo(const BLPoint& p1) noexcept {
|
||
|
return blPathLineTo(this, p1.x, p1.y);
|
||
|
}
|
||
|
|
||
|
//! Adds line to `[x1, y1]`.
|
||
|
//!
|
||
|
//! Appends `BL_PATH_CMD_ON[x1, y1]` command to the path.
|
||
|
BL_INLINE_NODEBUG BLResult lineTo(double x1, double y1) noexcept {
|
||
|
return blPathLineTo(this, x1, y1);
|
||
|
}
|
||
|
|
||
|
//! Adds a polyline (LineTo) of the given `poly` array of size `count`.
|
||
|
//!
|
||
|
//! Appends multiple `BL_PATH_CMD_ON[x[i], y[i]]` commands to the path depending on `count` parameter.
|
||
|
BL_INLINE_NODEBUG BLResult polyTo(const BLPoint* poly, size_t count) noexcept {
|
||
|
return blPathPolyTo(this, poly, count);
|
||
|
}
|
||
|
|
||
|
//! Adds a quadratic curve to `p1` and `p2`.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_QUAD[p1]`
|
||
|
//! - `BL_PATH_CMD_ON[p2]`
|
||
|
//!
|
||
|
//! Matches SVG 'Q' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult quadTo(const BLPoint& p1, const BLPoint& p2) noexcept {
|
||
|
return blPathQuadTo(this, p1.x, p1.y, p2.x, p2.y);
|
||
|
}
|
||
|
|
||
|
//! Adds a quadratic curve to `[x1, y1]` and `[x2, y2]`.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_QUAD[x1, y1]`
|
||
|
//! - `BL_PATH_CMD_ON[x2, y2]`
|
||
|
//!
|
||
|
//! Matches SVG 'Q' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult quadTo(double x1, double y1, double x2, double y2) noexcept {
|
||
|
return blPathQuadTo(this, x1, y1, x2, y2);
|
||
|
}
|
||
|
|
||
|
BL_INLINE BLResult conicTo(const BLPoint& p1, const BLPoint& p2, double w) noexcept {
|
||
|
return blPathConicTo(this, p1.x, p1.y, p2.x, p2.y, w);
|
||
|
}
|
||
|
|
||
|
BL_INLINE BLResult conicTo(double x1, double y1, double x2, double y2, double w) noexcept {
|
||
|
return blPathConicTo(this, x1, y1, x2, y2, w);
|
||
|
}
|
||
|
|
||
|
//! Adds a cubic curve to `p1`, `p2`, `p3`.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_CUBIC[p1]`
|
||
|
//! - `BL_PATH_CMD_CUBIC[p2]`
|
||
|
//! - `BL_PATH_CMD_ON[p3]`
|
||
|
//!
|
||
|
//! Matches SVG 'C' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult cubicTo(const BLPoint& p1, const BLPoint& p2, const BLPoint& p3) noexcept {
|
||
|
return blPathCubicTo(this, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
|
||
|
}
|
||
|
|
||
|
//! Adds a cubic curve to `[x1, y1]`, `[x2, y2]`, and `[x3, y3]`.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_CUBIC[x1, y1]`
|
||
|
//! - `BL_PATH_CMD_CUBIC[x2, y2]`
|
||
|
//! - `BL_PATH_CMD_ON[x3, y3]`
|
||
|
//!
|
||
|
//! Matches SVG 'C' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) noexcept {
|
||
|
return blPathCubicTo(this, x1, y1, x2, y2, x3, y3);
|
||
|
}
|
||
|
|
||
|
//! Adds a smooth quadratic curve to `p2`, calculating `p1` from last points.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_QUAD[calculated]`
|
||
|
//! - `BL_PATH_CMD_ON[p2]`
|
||
|
//!
|
||
|
//! Matches SVG 'T' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult smoothQuadTo(const BLPoint& p2) noexcept {
|
||
|
return blPathSmoothQuadTo(this, p2.x, p2.y);
|
||
|
}
|
||
|
|
||
|
//! Adds a smooth quadratic curve to `[x2, y2]`, calculating `[x1, y1]` from last points.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_QUAD[calculated]`
|
||
|
//! - `BL_PATH_CMD_ON[x2, y2]`
|
||
|
//!
|
||
|
//! Matches SVG 'T' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult smoothQuadTo(double x2, double y2) noexcept {
|
||
|
return blPathSmoothQuadTo(this, x2, y2);
|
||
|
}
|
||
|
|
||
|
//! Adds a smooth cubic curve to `p2` and `p3`, calculating `p1` from last points.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_CUBIC[calculated]`
|
||
|
//! - `BL_PATH_CMD_CUBIC[p2]`
|
||
|
//! - `BL_PATH_CMD_ON[p3]`
|
||
|
//!
|
||
|
//! Matches SVG 'S' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult smoothCubicTo(const BLPoint& p2, const BLPoint& p3) noexcept {
|
||
|
return blPathSmoothCubicTo(this, p2.x, p2.y, p3.x, p3.y);
|
||
|
}
|
||
|
|
||
|
//! Adds a smooth cubic curve to `[x2, y2]` and `[x3, y3]`, calculating `[x1, y1]` from last points.
|
||
|
//!
|
||
|
//! Appends the following commands to the path:
|
||
|
//! - `BL_PATH_CMD_CUBIC[calculated]`
|
||
|
//! - `BL_PATH_CMD_CUBIC[x2, y2]`
|
||
|
//! - `BL_PATH_CMD_ON[x3, y3]`
|
||
|
//!
|
||
|
//! Matches SVG 'S' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
|
||
|
BL_INLINE_NODEBUG BLResult smoothCubicTo(double x2, double y2, double x3, double y3) noexcept {
|
||
|
return blPathSmoothCubicTo(this, x2, y2, x3, y3);
|
||
|
}
|
||
|
|
||
|
//! Adds an arc to the path.
|
||
|
//!
|
||
|
//! The center of the arc is specified by `c` and radius by `r`. Both `start` and `sweep` angles are in radians.
|
||
|
//! If the last vertex doesn't match the start of the arc then a `lineTo()` would be emitted before adding the arc.
|
||
|
//! Pass `true` in `forceMoveTo` to always emit `moveTo()` at the beginning of the arc, which starts a new figure.
|
||
|
BL_INLINE_NODEBUG BLResult arcTo(const BLPoint& c, const BLPoint& r, double start, double sweep, bool forceMoveTo = false) noexcept {
|
||
|
return blPathArcTo(this, c.x, c.y, r.x, r.y, start, sweep, forceMoveTo);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult arcTo(double cx, double cy, double rx, double ry, double start, double sweep, bool forceMoveTo = false) noexcept {
|
||
|
return blPathArcTo(this, cx, cy, rx, ry, start, sweep, forceMoveTo);
|
||
|
}
|
||
|
|
||
|
//! Adds an arc quadrant (90deg) to the path. The first point `p1` specifies
|
||
|
//! the quadrant corner and the last point `p2` specifies the end point.
|
||
|
BL_INLINE_NODEBUG BLResult arcQuadrantTo(const BLPoint& p1, const BLPoint& p2) noexcept {
|
||
|
return blPathArcQuadrantTo(this, p1.x, p1.y, p2.x, p2.y);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult arcQuadrantTo(double x1, double y1, double x2, double y2) noexcept {
|
||
|
return blPathArcQuadrantTo(this, x1, y1, x2, y2);
|
||
|
}
|
||
|
|
||
|
//! Adds an elliptic arc to the path that follows the SVG specification.
|
||
|
//!
|
||
|
//! Matches SVG 'A' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||
|
BL_INLINE_NODEBUG BLResult ellipticArcTo(const BLPoint& rp, double xAxisRotation, bool largeArcFlag, bool sweepFlag, const BLPoint& p1) noexcept {
|
||
|
return blPathEllipticArcTo(this, rp.x, rp.y, xAxisRotation, largeArcFlag, sweepFlag, p1.x, p1.y);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult ellipticArcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, bool sweepFlag, double x1, double y1) noexcept {
|
||
|
return blPathEllipticArcTo(this, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x1, y1);
|
||
|
}
|
||
|
|
||
|
//! Closes the current figure.
|
||
|
//!
|
||
|
//! Appends `BL_PATH_CMD_CLOSE` to the path.
|
||
|
//!
|
||
|
//! Matches SVG 'Z' path command:
|
||
|
//! - https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
|
||
|
BL_INLINE_NODEBUG BLResult close() noexcept { return blPathClose(this); }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Adding Multiple Segments
|
||
|
//!
|
||
|
//! Adding multiple segments API was designed to provide high-performance path building in case that the user knows
|
||
|
//! the segments that will be added to the path in advance.
|
||
|
//!
|
||
|
//! \{
|
||
|
|
||
|
struct MoveTo {
|
||
|
double x, y;
|
||
|
|
||
|
static constexpr uint32_t kVertexCount = 1;
|
||
|
};
|
||
|
|
||
|
struct LineTo {
|
||
|
double x, y;
|
||
|
|
||
|
static constexpr uint32_t kVertexCount = 1;
|
||
|
};
|
||
|
|
||
|
struct QuadTo {
|
||
|
double x0, y0, x1, y1;
|
||
|
|
||
|
static constexpr uint32_t kVertexCount = 2;
|
||
|
};
|
||
|
|
||
|
struct CubicTo {
|
||
|
double x0, y0, x1, y1, x2, y2;
|
||
|
|
||
|
static constexpr uint32_t kVertexCount = 3;
|
||
|
};
|
||
|
|
||
|
template<typename... Args>
|
||
|
BL_INLINE BLResult addSegments(Args&&... args) noexcept {
|
||
|
uint8_t* cmdPtr;
|
||
|
BLPoint* vtxPtr;
|
||
|
|
||
|
size_t kVertexCount = BLInternal::pathSegmentCount(BLInternal::forward<Args>(args)...);
|
||
|
BL_PROPAGATE(modifyOp(BL_MODIFY_OP_APPEND_GROW, kVertexCount, &cmdPtr, &vtxPtr));
|
||
|
|
||
|
BLInternal::storePathSegmentsCmd(cmdPtr, BLInternal::forward<Args>(args)...);
|
||
|
BLInternal::storePathSegmentsVtx(vtxPtr, BLInternal::forward<Args>(args)...);
|
||
|
|
||
|
return BL_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Adding Figures
|
||
|
//!
|
||
|
//! Adding a figure means starting with a move-to segment. For example `addBox()` would start a new figure
|
||
|
//! by adding `BL_PATH_CMD_MOVE_TO` segment, and then by adding 3 lines, and finally a close command.
|
||
|
//!
|
||
|
//! \{
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `box`.
|
||
|
BL_INLINE_NODEBUG BLResult addBox(const BLBoxI& box, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return blPathAddBoxI(this, &box, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `box`.
|
||
|
BL_INLINE_NODEBUG BLResult addBox(const BLBox& box, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return blPathAddBoxD(this, &box, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `[x0, y0, x1, y1]`.
|
||
|
BL_INLINE_NODEBUG BLResult addBox(double x0, double y0, double x1, double y1, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addBox(BLBox(x0, y0, x1, y1), dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `rect`.
|
||
|
BL_INLINE_NODEBUG BLResult addRect(const BLRectI& rect, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return blPathAddRectI(this, &rect, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `rect`.
|
||
|
BL_INLINE_NODEBUG BLResult addRect(const BLRect& rect, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return blPathAddRectD(this, &rect, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rectangle to the path specified by `[x, y, w, h]`.
|
||
|
BL_INLINE_NODEBUG BLResult addRect(double x, double y, double w, double h, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addRect(BLRect(x, y, w, h), dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a geometry to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addGeometry(BLGeometryType geometryType, const void* geometryData, const BLMatrix2D* m = nullptr, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return blPathAddGeometry(this, geometryType, geometryData, m, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed circle to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addCircle(const BLCircle& circle, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_CIRCLE, &circle, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addCircle(const BLCircle& circle, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_CIRCLE, &circle, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed ellipse to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addEllipse(const BLEllipse& ellipse, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ELLIPSE, &ellipse, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addEllipse(const BLEllipse& ellipse, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ELLIPSE, &ellipse, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed rounded rectangle to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addRoundRect(const BLRoundRect& rr, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ROUND_RECT, &rr, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRoundRect(const BLRoundRect& rr, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ROUND_RECT, &rr, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an unclosed arc to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addArc(const BLArc& arc, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARC, &arc, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addArc(const BLArc& arc, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARC, &arc, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed chord to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addChord(const BLArc& chord, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_CHORD, &chord, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addChord(const BLArc& chord, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_CHORD, &chord, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed pie to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addPie(const BLArc& pie, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_PIE, &pie, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPie(const BLArc& pie, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_PIE, &pie, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an unclosed line to the path.
|
||
|
BL_INLINE_NODEBUG BLResult addLine(const BLLine& line, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_LINE, &line, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addLine(const BLLine& line, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_LINE, &line, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a closed triangle.
|
||
|
BL_INLINE_NODEBUG BLResult addTriangle(const BLTriangle& triangle, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_TRIANGLE, &triangle, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addTriangle(const BLTriangle& triangle, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_TRIANGLE, &triangle, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a polyline.
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLArrayView<BLPointI>& poly, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYLINEI, &poly, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLArrayView<BLPointI>& poly, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYLINEI, &poly, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLPointI* poly, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolyline(BLArrayView<BLPointI>{poly, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLPointI* poly, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolyline(BLArrayView<BLPointI>{poly, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a polyline.
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLArrayView<BLPoint>& poly, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYLINED, &poly, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLArrayView<BLPoint>& poly, const BLMatrix2D& transform, BLGeometryDirection dir) {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYLINED, &poly, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLPoint* poly, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolyline(BLArrayView<BLPoint>{poly, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolyline(const BLPoint* poly, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir) {
|
||
|
return addPolyline(BLArrayView<BLPoint>{poly, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a polygon.
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLArrayView<BLPointI>& poly, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYGONI, &poly, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLArrayView<BLPointI>& poly, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYGONI, &poly, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLPointI* poly, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolygon(BLArrayView<BLPointI>{poly, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLPointI* poly, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolygon(BLArrayView<BLPointI>{poly, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds a polygon.
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLArrayView<BLPoint>& poly, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYGOND, &poly, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLArrayView<BLPoint>& poly, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_POLYGOND, &poly, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLPoint* poly, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolygon(BLArrayView<BLPoint>{poly, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addPolygon(const BLPoint* poly, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addPolygon(BLArrayView<BLPoint>{poly, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an array of closed boxes.
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLArrayView<BLBoxI>& array, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, &array, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLArrayView<BLBoxI>& array, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXI, &array, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLBoxI* data, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addBoxArray(BLArrayView<BLBoxI>{data, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLBoxI* data, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addBoxArray(BLArrayView<BLBoxI>{data, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an array of closed boxes.
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLArrayView<BLBox>& array, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, &array, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLArrayView<BLBox>& array, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_BOXD, &array, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLBox* data, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addBoxArray(BLArrayView<BLBox>{data, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addBoxArray(const BLBox* data, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addBoxArray(BLArrayView<BLBox>{data, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an array of closed rectangles.
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLArrayView<BLRectI>& array, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, &array, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLArrayView<BLRectI>& array, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTI, &array, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLRectI* data, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addRectArray(BLArrayView<BLRectI>{data, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLRectI* data, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addRectArray(BLArrayView<BLRectI>{data, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! Adds an array of closed rectangles.
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLArrayView<BLRect>& array, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, &array, nullptr, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLArrayView<BLRect>& array, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addGeometry(BL_GEOMETRY_TYPE_ARRAY_VIEW_RECTD, &array, &transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLRect* data, size_t n, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addRectArray(BLArrayView<BLRect>{data, n}, dir);
|
||
|
}
|
||
|
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addRectArray(const BLRect* data, size_t n, const BLMatrix2D& transform, BLGeometryDirection dir = BL_GEOMETRY_DIRECTION_CW) noexcept {
|
||
|
return addRectArray(BLArrayView<BLRect>{data, n}, transform, dir);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Adding Paths
|
||
|
//! \{
|
||
|
|
||
|
//! Adds other `path` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path) noexcept {
|
||
|
return blPathAddPath(this, &path, nullptr);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path` sliced by the given `range` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path, const BLRange& range) noexcept {
|
||
|
return blPathAddPath(this, &path, &range);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path` translated by `p` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path, const BLPoint& p) noexcept {
|
||
|
return blPathAddTranslatedPath(this, &path, nullptr, &p);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path` translated by `p` and sliced by the given `range` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path, const BLRange& range, const BLPoint& p) noexcept {
|
||
|
return blPathAddTranslatedPath(this, &path, &range, &p);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path` transformed by `m` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path, const BLMatrix2D& transform) noexcept {
|
||
|
return blPathAddTransformedPath(this, &path, nullptr, &transform);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path` transformed by `m` and sliced by the given `range` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addPath(const BLPath& path, const BLRange& range, const BLMatrix2D& transform) noexcept {
|
||
|
return blPathAddTransformedPath(this, &path, &range, &transform);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path`, but reversed.
|
||
|
BL_INLINE_NODEBUG BLResult addReversedPath(const BLPath& path, BLPathReverseMode reverseMode) noexcept {
|
||
|
return blPathAddReversedPath(this, &path, nullptr, reverseMode);
|
||
|
}
|
||
|
|
||
|
//! Adds other `path`, but reversed.
|
||
|
BL_INLINE_NODEBUG BLResult addReversedPath(const BLPath& path, const BLRange& range, BLPathReverseMode reverseMode) noexcept {
|
||
|
return blPathAddReversedPath(this, &path, &range, reverseMode);
|
||
|
}
|
||
|
|
||
|
//! Adds a stroke of `path` to this path.
|
||
|
BL_INLINE_NODEBUG BLResult addStrokedPath(const BLPath& path, const BLStrokeOptionsCore& strokeOptions, const BLApproximationOptions& approximationOptions) noexcept {
|
||
|
return blPathAddStrokedPath(this, &path, nullptr, &strokeOptions, &approximationOptions);
|
||
|
}
|
||
|
//! \overload
|
||
|
BL_INLINE_NODEBUG BLResult addStrokedPath(const BLPath& path, const BLRange& range, const BLStrokeOptionsCore& strokeOptions, const BLApproximationOptions& approximationOptions) noexcept {
|
||
|
return blPathAddStrokedPath(this, &path, &range, &strokeOptions, &approximationOptions);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Manipulation
|
||
|
//! \{
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult removeRange(const BLRange& range) noexcept {
|
||
|
return blPathRemoveRange(this, &range);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Transformations
|
||
|
//! \{
|
||
|
|
||
|
//! Translates the whole path by `p`.
|
||
|
BL_INLINE_NODEBUG BLResult translate(const BLPoint& p) noexcept {
|
||
|
return blPathTranslate(this, nullptr, &p);
|
||
|
}
|
||
|
|
||
|
//! Translates a part of the path specified by the given `range` by `p`.
|
||
|
BL_INLINE_NODEBUG BLResult translate(const BLRange& range, const BLPoint& p) noexcept {
|
||
|
return blPathTranslate(this, &range, &p);
|
||
|
}
|
||
|
|
||
|
//! Transforms the whole path by matrix `m`.
|
||
|
BL_INLINE_NODEBUG BLResult transform(const BLMatrix2D& m) noexcept {
|
||
|
return blPathTransform(this, nullptr, &m);
|
||
|
}
|
||
|
|
||
|
//! Transforms a part of the path specified by the given `range` by matrix `m`.
|
||
|
BL_INLINE_NODEBUG BLResult transform(const BLRange& range, const BLMatrix2D& m) noexcept {
|
||
|
return blPathTransform(this, &range, &m);
|
||
|
}
|
||
|
|
||
|
//! Fits the whole path into the given `rect` by taking into account fit flags passed by `fitFlags`.
|
||
|
BL_INLINE_NODEBUG BLResult fitTo(const BLRect& rect, uint32_t fitFlags) noexcept {
|
||
|
return blPathFitTo(this, nullptr, &rect, fitFlags);
|
||
|
}
|
||
|
|
||
|
//! Fits a path of the path specified by the given `range` into the given `rect` by taking into account fit flags
|
||
|
//! passed by `fitFlags`.
|
||
|
BL_INLINE_NODEBUG BLResult fitTo(const BLRange& range, const BLRect& rect, uint32_t fitFlags) noexcept {
|
||
|
return blPathFitTo(this, &range, &rect, fitFlags);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Equality & Comparison
|
||
|
//! \{
|
||
|
|
||
|
//! Tests whether this path and the `other` path are equal.
|
||
|
//!
|
||
|
//! The equality check is deep. The data of both paths is examined and binary compared (thus a slight difference
|
||
|
//! like -0 and +0 would make the equality check to fail).
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG bool equals(const BLPath& other) const noexcept { return blPathEquals(this, &other); }
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Path Information
|
||
|
//! \{
|
||
|
|
||
|
//! Update a path information if necessary.
|
||
|
BL_INLINE_NODEBUG BLResult getInfoFlags(uint32_t* flagsOut) const noexcept {
|
||
|
return blPathGetInfoFlags(this, flagsOut);
|
||
|
}
|
||
|
|
||
|
//! Stores a bounding box of all vertices and control points to `boxOut`.
|
||
|
//!
|
||
|
//! Control box is simply bounds of all vertices the path has without further processing. It contains both on-path
|
||
|
//! and off-path points. Consider using `getBoundingBox()` if you need a visual bounding box.
|
||
|
BL_INLINE_NODEBUG BLResult getControlBox(BLBox* boxOut) const noexcept {
|
||
|
return blPathGetControlBox(this, boxOut);
|
||
|
}
|
||
|
|
||
|
//! Stores a bounding box of all on-path vertices and curve extrema to `boxOut`.
|
||
|
//!
|
||
|
//! The bounding box stored to `boxOut` could be smaller than a bounding box obtained by `getControlBox()` as it's
|
||
|
//! calculated by merging only start/end points and curves at their extrema (not control points). The resulting
|
||
|
//! bounding box represents a visual bounds of the path.
|
||
|
BL_INLINE_NODEBUG BLResult getBoundingBox(BLBox* boxOut) const noexcept {
|
||
|
return blPathGetBoundingBox(this, boxOut);
|
||
|
}
|
||
|
|
||
|
//! Returns the range describing a figure at the given `index`.
|
||
|
BL_INLINE_NODEBUG BLResult getFigureRange(size_t index, BLRange* rangeOut) const noexcept {
|
||
|
return blPathGetFigureRange(this, index, rangeOut);
|
||
|
}
|
||
|
|
||
|
//! Returns the last vertex of the path and stores it to `vtxOut`. If the very last command of the path is
|
||
|
//! `BL_PATH_CMD_CLOSE` then the path will be iterated in reverse order to match the initial vertex of the last
|
||
|
//! figure.
|
||
|
BL_INLINE_NODEBUG BLResult getLastVertex(BLPoint* vtxOut) const noexcept {
|
||
|
return blPathGetLastVertex(this, vtxOut);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult getClosestVertex(const BLPoint& p, double maxDistance, size_t* indexOut) const noexcept {
|
||
|
double distanceOut;
|
||
|
return blPathGetClosestVertex(this, &p, maxDistance, indexOut, &distanceOut);
|
||
|
}
|
||
|
|
||
|
BL_INLINE_NODEBUG BLResult getClosestVertex(const BLPoint& p, double maxDistance, size_t* indexOut, double* distanceOut) const noexcept {
|
||
|
return blPathGetClosestVertex(this, &p, maxDistance, indexOut, distanceOut);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
//! \name Hit Testing
|
||
|
//! \{
|
||
|
|
||
|
//! Hit tests the given point `p` by respecting the given `fillRule`.
|
||
|
BL_NODISCARD
|
||
|
BL_INLINE_NODEBUG BLHitTest hitTest(const BLPoint& p, BLFillRule fillRule) const noexcept {
|
||
|
return blPathHitTest(this, &p, fillRule);
|
||
|
}
|
||
|
|
||
|
//! \}
|
||
|
};
|
||
|
|
||
|
namespace BLInternal {
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentCmd(uint8_t* cmd, const BLPath::MoveTo&) noexcept {
|
||
|
cmd[0] = uint8_t(BL_PATH_CMD_MOVE);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentVtx(BLPoint* vtx, const BLPath::MoveTo& segment) noexcept {
|
||
|
vtx[0] = BLPoint(segment.x, segment.y);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentCmd(uint8_t* cmd, const BLPath::LineTo&) noexcept {
|
||
|
cmd[0] = uint8_t(BL_PATH_CMD_ON);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentVtx(BLPoint* vtx, const BLPath::LineTo& segment) noexcept {
|
||
|
vtx[0] = BLPoint(segment.x, segment.y);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentCmd(uint8_t* cmd, const BLPath::QuadTo&) noexcept {
|
||
|
cmd[0] = uint8_t(BL_PATH_CMD_QUAD);
|
||
|
cmd[1] = uint8_t(BL_PATH_CMD_ON);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentVtx(BLPoint* vtx, const BLPath::QuadTo& segment) noexcept {
|
||
|
vtx[0] = BLPoint(segment.x0, segment.y0);
|
||
|
vtx[1] = BLPoint(segment.x1, segment.y1);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentCmd(uint8_t* cmd, const BLPath::CubicTo&) noexcept {
|
||
|
cmd[0] = uint8_t(BL_PATH_CMD_CUBIC);
|
||
|
cmd[1] = uint8_t(BL_PATH_CMD_CUBIC);
|
||
|
cmd[2] = uint8_t(BL_PATH_CMD_ON);
|
||
|
}
|
||
|
|
||
|
template<>
|
||
|
BL_INLINE void storePathSegmentVtx(BLPoint* vtx, const BLPath::CubicTo& segment) noexcept {
|
||
|
vtx[0] = BLPoint(segment.x0, segment.y0);
|
||
|
vtx[1] = BLPoint(segment.x1, segment.y1);
|
||
|
vtx[2] = BLPoint(segment.x2, segment.y2);
|
||
|
}
|
||
|
|
||
|
} // {BLInternal}
|
||
|
|
||
|
#endif
|
||
|
//! \}
|
||
|
|
||
|
//! \}
|
||
|
|
||
|
#endif // BLEND2D_PATH_H_INCLUDED
|