mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
* chore: fix clang-17 compiler * chore: adding missing file * fix: rive_native builds * chore: remove no runtime linking on linux * chore: more fixes * chore: removing rive_common * chore: use build_rive.sh for ios * chore: use rive_build.sh for recorder * chore: fix fill missing version * chore: add rive_build.sh to path * chore: add rive_build.sh to pr_ios_tests.yaml * chore: add rive_build to the recorder tests * chore: drop rive_flutter tests * chore: fixing ios tests * fix misspelled * chore: cleanup * chore: use latest zlib * chore: premake5.lua redirects to premake5_v2 * fix: tvos and ios builds * fix: unreal build path for miniaudio Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
160 lines
4.4 KiB
C++
160 lines
4.4 KiB
C++
/*
|
|
* Copyright 2022 Rive
|
|
*/
|
|
|
|
#ifndef _RIVE_CONTOUR_MEASURE_HPP_
|
|
#define _RIVE_CONTOUR_MEASURE_HPP_
|
|
|
|
#include "rive/math/raw_path.hpp"
|
|
#include "rive/math/vec2d.hpp"
|
|
#include "rive/refcnt.hpp"
|
|
#include <utility>
|
|
|
|
namespace rive
|
|
{
|
|
|
|
class ContourMeasure : public RefCnt<ContourMeasure>
|
|
{
|
|
public:
|
|
static constexpr unsigned kMaxDot30 = (1 << 30) - 1;
|
|
static constexpr float kInvScaleD30 = 1.0f / (float)kMaxDot30;
|
|
|
|
// Deliberately making this pack well (12 bytes)
|
|
struct Segment
|
|
{
|
|
float m_distance; // total distance up to this point
|
|
uint32_t m_ptIndex; // index of the first point for this line/quad/cubic
|
|
unsigned m_tValue : 30; // Dot30 t value for the end of this segment
|
|
unsigned m_type : 2; // [private enum]
|
|
|
|
float getT() const { return (float)m_tValue * kInvScaleD30; }
|
|
|
|
bool operator<(const Segment& other) const
|
|
{
|
|
return m_distance < other.m_distance;
|
|
}
|
|
|
|
void extract(RawPath* dst,
|
|
float fromT,
|
|
float toT,
|
|
const Vec2D pts[],
|
|
bool moveTo) const;
|
|
void extract(RawPath* dst, const Vec2D pts[]) const;
|
|
};
|
|
|
|
private:
|
|
size_t findSegment(float distance) const;
|
|
|
|
std::vector<Segment> m_segments;
|
|
std::vector<Vec2D> m_points;
|
|
const float m_length;
|
|
const bool m_isClosed;
|
|
|
|
ContourMeasure(std::vector<Segment>&&,
|
|
std::vector<Vec2D>&&,
|
|
float length,
|
|
bool isClosed);
|
|
|
|
friend class ContourMeasureIter;
|
|
|
|
public:
|
|
float length() const { return m_length; }
|
|
bool isClosed() const { return m_isClosed; }
|
|
|
|
struct PosTan
|
|
{
|
|
Vec2D pos, tan;
|
|
};
|
|
struct PosTanDistance
|
|
{
|
|
Vec2D pos, tan;
|
|
/// Distance along the curve.
|
|
float distance;
|
|
|
|
/// Squared distance to point projected to curve.
|
|
float sqDistanceToPoint;
|
|
|
|
PosTanDistance() : distance(0.0f), sqDistanceToPoint(0.0f) {}
|
|
PosTanDistance(PosTan posTan, float dist) :
|
|
pos(posTan.pos),
|
|
tan(posTan.tan),
|
|
distance(dist),
|
|
sqDistanceToPoint(0.0f)
|
|
{}
|
|
};
|
|
PosTan getPosTan(float distance) const;
|
|
|
|
void getSegment(float startDistance,
|
|
float endDistance,
|
|
RawPath* dst,
|
|
bool startWithMove) const;
|
|
|
|
Vec2D warp(Vec2D src) const
|
|
{
|
|
const auto result = this->getPosTan(src.x);
|
|
return {
|
|
result.pos.x - result.tan.y * src.y,
|
|
result.pos.y + result.tan.x * src.y,
|
|
};
|
|
}
|
|
|
|
void dump() const;
|
|
};
|
|
|
|
class ContourMeasureIter
|
|
{
|
|
RawPath m_optionalCopy;
|
|
RawPath::Iter m_iter;
|
|
RawPath::Iter m_end;
|
|
const Vec2D* m_srcPoints;
|
|
float m_invTolerance;
|
|
|
|
float addQuadSegs(ContourMeasure::Segment*,
|
|
const Vec2D[],
|
|
uint32_t segmentCount,
|
|
uint32_t ptIndex,
|
|
float distance) const;
|
|
float addCubicSegs(ContourMeasure::Segment*,
|
|
const Vec2D[],
|
|
uint32_t segmentCount,
|
|
uint32_t ptIndex,
|
|
float distance) const;
|
|
rcp<ContourMeasure> tryNext();
|
|
|
|
public:
|
|
// Tolerance is the max deviation of the curve from its approximating line
|
|
// segments. A smaller tolerance means more line segments, but a better
|
|
// approximation for the curves actual length.
|
|
static constexpr float kDefaultTolerance = 0.5f;
|
|
|
|
ContourMeasureIter(const RawPath* path, float tol = kDefaultTolerance)
|
|
{
|
|
this->rewind(path, tol);
|
|
}
|
|
|
|
void rewind(const RawPath*, float = kDefaultTolerance);
|
|
|
|
// Returns a measure object for each contour in the path
|
|
// (contours with zero-length are skipped over)
|
|
// and then returns nullptr when its finished.
|
|
//
|
|
// ContourMeasureIter iter(path);
|
|
// while ((auto meas = iter.next())) {
|
|
// ... meas can be used, and passed to other objects
|
|
// }
|
|
//
|
|
// Each measure object is stand-alone, and can outlive the
|
|
// ContourMeasureIter that created it. It contains no back pointers to the
|
|
// Iter or to the path.
|
|
//
|
|
rcp<ContourMeasure> next();
|
|
|
|
// Temporary storage used during tryNext(), for counting up how many
|
|
// segments a contour will be divided into.
|
|
std::vector<uint32_t> m_segmentCounts;
|
|
};
|
|
|
|
} // namespace rive
|
|
|
|
#endif
|