DYT/Tool/OpenSceneGraph-3.6.5/include/blend2d/path.h
2024-12-25 07:49:36 +08:00

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