5#include <glm/common.hpp>
6#include <glm/geometric.hpp>
14void validatePoint(glm::vec2
point) {
19float pointLineDistance(glm::vec2
point, glm::vec2
a, glm::vec2
b) {
20 const glm::vec2
line =
b -
a;
22 if (lengthSquared <= 1e-20f)
return glm::length(
point -
a);
23 const float t = glm::clamp(glm::dot(
point -
a,
line) / lengthSquared, 0.f, 1.f);
27void flattenQuad(glm::vec2
a, glm::vec2 control, glm::vec2
b,
float tolerance, std::uint32_t
depth,
28 std::uint32_t maxDepth, std::vector<glm::vec2>&
output) {
29 if (
depth >= maxDepth || pointLineDistance(control,
a,
b) <= tolerance) {
33 const glm::vec2
ac = (
a + control) * 0.5f;
34 const glm::vec2 cb = (control +
b) * 0.5f;
35 const glm::vec2 middle = (
ac + cb) * 0.5f;
36 flattenQuad(
a,
ac, middle, tolerance,
depth + 1, maxDepth,
output);
37 flattenQuad(middle, cb,
b, tolerance,
depth + 1, maxDepth,
output);
40void flattenCubic(glm::vec2
a, glm::vec2 c1, glm::vec2 c2, glm::vec2
b,
float tolerance, std::uint32_t
depth,
41 std::uint32_t maxDepth, std::vector<glm::vec2>&
output) {
42 const float deviation = std::max(pointLineDistance(c1,
a,
b), pointLineDistance(c2,
a,
b));
43 if (
depth >= maxDepth || deviation <= tolerance) {
47 const glm::vec2 a1 = (
a + c1) * 0.5f;
48 const glm::vec2 c12 = (c1 + c2) * 0.5f;
49 const glm::vec2 c2b = (c2 +
b) * 0.5f;
50 const glm::vec2 leftControl = (a1 + c12) * 0.5f;
51 const glm::vec2 rightControl = (c12 + c2b) * 0.5f;
52 const glm::vec2 middle = (leftControl + rightControl) * 0.5f;
53 flattenCubic(
a, a1, leftControl, middle, tolerance,
depth + 1, maxDepth,
output);
54 flattenCubic(middle, rightControl, c2b,
b, tolerance,
depth + 1, maxDepth,
output);
61 verbs_.push_back(Verb::Move);
62 points_.push_back(
point);
68 EV_PARAM_CHECK(contourOpen_,
"lineTo requires a preceding moveTo");
70 verbs_.push_back(Verb::Line);
71 points_.push_back(
point);
76 EV_PARAM_CHECK(contourOpen_,
"quadTo requires a preceding moveTo");
77 validatePoint(control);
79 verbs_.push_back(Verb::Quad);
80 points_.push_back(control);
81 points_.push_back(
point);
86 EV_PARAM_CHECK(contourOpen_,
"cubicTo requires a preceding moveTo");
87 validatePoint(control1);
88 validatePoint(control2);
90 verbs_.push_back(Verb::Cubic);
91 points_.push_back(control1);
92 points_.push_back(control2);
93 points_.push_back(
point);
99 verbs_.push_back(Verb::Close);
100 contourOpen_ =
false;
107 contourOpen_ =
false;
110std::vector<FlattenedContour2D>
Path2D::flatten(
float tolerance, std::uint32_t maxDepth)
const {
111 const bool validTolerance = std::isfinite(tolerance) && tolerance > 0.f;
112 EV_PARAM_CHECK(validTolerance,
"path flatten tolerance must be finite and positive");
113 const bool validMaxDepth = maxDepth > 0 && maxDepth <= 24;
114 EV_PARAM_CHECK(validMaxDepth,
"path flatten maxDepth must be in [1, 24]");
116 std::vector<FlattenedContour2D> result;
117 std::size_t pointIndex = 0;
119 for (Verb verb : verbs_) {
122 result.push_back({});
123 current = points_[pointIndex++];
124 result.back().points.push_back(
current);
127 current = points_[pointIndex++];
128 result.back().points.push_back(
current);
131 const glm::vec2 control = points_[pointIndex++];
132 const glm::vec2
end = points_[pointIndex++];
133 flattenQuad(
current, control,
end, tolerance, 0, maxDepth, result.back().points);
138 const glm::vec2 control1 = points_[pointIndex++];
139 const glm::vec2 control2 = points_[pointIndex++];
140 const glm::vec2
end = points_[pointIndex++];
141 flattenCubic(
current, control1, control2,
end, tolerance, 0, maxDepth, result.back().points);
145 case Verb::Close: result.back().closed =
true;
break;
EVEngine assertion entry point, backed by zeroerr.
#define EV_PARAM_CHECK(cond,...)
Validate a function parameter / public API precondition.
Owning backend-neutral 2D vector path.
Path2D & lineTo(glm::vec2 point)
Adds a straight segment to point.
Path2D & moveTo(glm::vec2 point)
Starts a new contour at point.
Path2D & quadTo(glm::vec2 control, glm::vec2 point)
Adds a quadratic Bezier segment.
Path2D & cubicTo(glm::vec2 control1, glm::vec2 control2, glm::vec2 point)
Adds a cubic Bezier segment.
Path2D & close()
Closes the current contour.
std::vector< FlattenedContour2D > flatten(float tolerance=0.25f, std::uint32_t maxDepth=12) const
Flattens curves into owning line contours.
void clear() noexcept
Removes all verbs and points while retaining capacity.
float lengthSquared(Vec3 value)
Length squared.
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...