blob: 6f402682b33a078998e570f3a5f2bb1be6e68226 [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#include "rive/math/math_types.hpp"
#include "rive/math/raw_path_utils.hpp"
#include <cmath>
// just putting a sane limit, the particular value not important.
constexpr int MAX_LINE_SEGMENTS = 100;
// (a+c)/2 - (a+2b+c)/4)
// a/4 - b/2 + c/4
// d = |a - 2b + c|/4
// count = sqrt(d / tol)
//
int rive::computeApproximatingQuadLineSegments(const rive::Vec2D pts[3], float invTolerance) {
auto diff = pts[0] - rive::two(pts[1]) + pts[2];
float d = diff.length();
float count = sqrtf(d * invTolerance * 0.25f);
return std::max(1, std::min((int)std::ceil(count), MAX_LINE_SEGMENTS));
}
int rive::computeApproximatingCubicLineSegments(const rive::Vec2D pts[4], float invTolerance) {
auto abc = pts[0] - pts[1] - pts[1] + pts[2];
auto bcd = pts[1] - pts[2] - pts[2] + pts[3];
float dx = std::max(std::abs(abc.x), std::abs(bcd.x));
float dy = std::max(std::abs(abc.y), std::abs(bcd.y));
float d = Vec2D{dx, dy}.length();
// count = sqrt(3*d / 4*tol)
float count = sqrtf(d * invTolerance * 0.75f);
return std::max(1, std::min((int)std::ceil(count), MAX_LINE_SEGMENTS));
}
// Extract subsets
void rive::quad_subdivide(const rive::Vec2D src[3], float t, rive::Vec2D dst[5]) {
assert(t >= 0 && t <= 1);
auto ab = lerp(src[0], src[1], t);
auto bc = lerp(src[1], src[2], t);
dst[0] = src[0];
dst[1] = ab;
dst[2] = lerp(ab, bc, t);
dst[3] = bc;
dst[4] = src[2];
}
void rive::cubic_subdivide(const rive::Vec2D src[4], float t, rive::Vec2D dst[7]) {
assert(t >= 0 && t <= 1);
auto ab = lerp(src[0], src[1], t);
auto bc = lerp(src[1], src[2], t);
auto cd = lerp(src[2], src[3], t);
auto abc = lerp(ab, bc, t);
auto bcd = lerp(bc, cd, t);
dst[0] = src[0];
dst[1] = ab;
dst[2] = abc;
dst[3] = lerp(abc, bcd, t);
dst[4] = bcd;
dst[5] = cd;
dst[6] = src[3];
}
void rive::line_extract(const rive::Vec2D src[2], float startT, float endT, rive::Vec2D dst[2]) {
assert(startT <= endT);
assert(startT >= 0 && endT <= 1);
dst[0] = lerp(src[0], src[1], startT);
dst[1] = lerp(src[0], src[1], endT);
}
void rive::quad_extract(const rive::Vec2D src[3], float startT, float endT, rive::Vec2D dst[3]) {
assert(startT <= endT);
assert(startT >= 0 && endT <= 1);
rive::Vec2D tmp[5];
if (startT == 0 && endT == 1) {
std::copy(src, src + 3, dst);
} else if (startT == 0) {
rive::quad_subdivide(src, endT, tmp);
std::copy(tmp, tmp + 3, dst);
} else if (endT == 1) {
rive::quad_subdivide(src, startT, tmp);
std::copy(tmp + 2, tmp + 5, dst);
} else {
assert(endT > 0);
rive::quad_subdivide(src, endT, tmp);
rive::Vec2D tmp2[5];
rive::quad_subdivide(tmp, startT / endT, tmp2);
std::copy(tmp2 + 2, tmp2 + 5, dst);
}
}
void rive::cubic_extract(const rive::Vec2D src[4], float startT, float endT, rive::Vec2D dst[4]) {
assert(startT <= endT);
assert(startT >= 0 && endT <= 1);
rive::Vec2D tmp[7];
if (startT == 0 && endT == 1) {
std::copy(src, src + 4, dst);
} else if (startT == 0) {
rive::cubic_subdivide(src, endT, tmp);
std::copy(tmp, tmp + 4, dst);
} else if (endT == 1) {
rive::cubic_subdivide(src, startT, tmp);
std::copy(tmp + 3, tmp + 7, dst);
} else {
assert(endT > 0);
rive::cubic_subdivide(src, endT, tmp);
rive::Vec2D tmp2[7];
rive::cubic_subdivide(tmp, startT / endT, tmp2);
std::copy(tmp2 + 3, tmp2 + 7, dst);
}
}