载入中...
搜索中...
未找到
PrimitivePath.cpp
浏览该文件的文档.
2
3#include "common/Assert.h"
4
5#include <glm/common.hpp>
6#include <glm/geometric.hpp>
7
8#include <algorithm>
9#include <cmath>
10
11namespace eve::graphics {
12namespace {
13
14void validatePoint(glm::vec2 point) {
15 const bool finite = std::isfinite(point.x) && std::isfinite(point.y);
16 EV_PARAM_CHECK(finite, "path points must be finite");
17}
18
19float pointLineDistance(glm::vec2 point, glm::vec2 a, glm::vec2 b) {
20 const glm::vec2 line = b - a;
21 const float lengthSquared = glm::dot(line, line);
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);
24 return glm::length(point - (a + line * t));
25}
26
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) {
30 output.push_back(b);
31 return;
32 }
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);
38}
39
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) {
44 output.push_back(b);
45 return;
46 }
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);
55}
56
57} // namespace
58
60 validatePoint(point);
61 verbs_.push_back(Verb::Move);
62 points_.push_back(point);
63 contourOpen_ = true;
64 return *this;
65}
66
68 EV_PARAM_CHECK(contourOpen_, "lineTo requires a preceding moveTo");
69 validatePoint(point);
70 verbs_.push_back(Verb::Line);
71 points_.push_back(point);
72 return *this;
73}
74
75Path2D& Path2D::quadTo(glm::vec2 control, glm::vec2 point) {
76 EV_PARAM_CHECK(contourOpen_, "quadTo requires a preceding moveTo");
77 validatePoint(control);
78 validatePoint(point);
79 verbs_.push_back(Verb::Quad);
80 points_.push_back(control);
81 points_.push_back(point);
82 return *this;
83}
84
85Path2D& Path2D::cubicTo(glm::vec2 control1, glm::vec2 control2, glm::vec2 point) {
86 EV_PARAM_CHECK(contourOpen_, "cubicTo requires a preceding moveTo");
87 validatePoint(control1);
88 validatePoint(control2);
89 validatePoint(point);
90 verbs_.push_back(Verb::Cubic);
91 points_.push_back(control1);
92 points_.push_back(control2);
93 points_.push_back(point);
94 return *this;
95}
96
98 EV_PARAM_CHECK(contourOpen_, "close requires an open contour");
99 verbs_.push_back(Verb::Close);
100 contourOpen_ = false;
101 return *this;
102}
103
104void Path2D::clear() noexcept {
105 verbs_.clear();
106 points_.clear();
107 contourOpen_ = false;
108}
109
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]");
115
116 std::vector<FlattenedContour2D> result;
117 std::size_t pointIndex = 0;
118 glm::vec2 current{0.f};
119 for (Verb verb : verbs_) {
120 switch (verb) {
121 case Verb::Move:
122 result.push_back({});
123 current = points_[pointIndex++];
124 result.back().points.push_back(current);
125 break;
126 case Verb::Line:
127 current = points_[pointIndex++];
128 result.back().points.push_back(current);
129 break;
130 case Verb::Quad: {
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);
134 current = end;
135 break;
136 }
137 case Verb::Cubic: {
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);
142 current = end;
143 break;
144 }
145 case Verb::Close: result.back().closed = true; break;
146 }
147 }
148 return result;
149}
150
151} // namespace eve::graphics
EVEngine assertion entry point, backed by zeroerr.
#define EV_PARAM_CHECK(cond,...)
Validate a function parameter / public API precondition.
Definition Assert.h:30
std::string output
std::uint32_t ac
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
bool finite
float t
double current
std::uint32_t depth
glm::vec3 point
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:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25