-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCurveData.h
More file actions
131 lines (119 loc) · 4.31 KB
/
Copy pathCurveData.h
File metadata and controls
131 lines (119 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// =============================================================================
// CurveData.h ── 曲线数据结构
// · AnchorPoint 锚点(位置 + 两个手柄,手柄为绝对坐标)
// · CurveStroke 一条曲线(多段三次贝塞尔)
// · HandleMode 手柄约束模式
// =============================================================================
#pragma once
#include "BezierMath.h"
#include <vector>
#include <string>
#include <windows.h>
// ---------- 手柄模式 ----------
enum class HandleMode {
Symmetric, // |handleOut - pos| == |handleIn - pos|,方向相反
Smooth, // 方向共线,长度独立
Free, // 完全独立(平滑点下的自由手柄)
Corner // 尖点(手柄收回至锚点)
};
// ---------- 锚点 ----------
struct AnchorPoint
{
Vec2 pos;
Vec2 handleIn; // 入手柄(绝对坐标)
Vec2 handleOut; // 出手柄(绝对坐标)
HandleMode mode = HandleMode::Symmetric;
explicit AnchorPoint(Vec2 p = {})
: pos(p), handleIn(p), handleOut(p) {}
// 手柄是否偏离锚点
bool HasIn() const { return (handleIn - pos).lengthSq() > 0.01; }
bool HasOut() const { return (handleOut - pos).lengthSq() > 0.01; }
// 根据模式同步另一个手柄
// changed: 0=out改变 → 同步in, 1=in改变 → 同步out
void SyncHandle(int changed)
{
if (mode == HandleMode::Symmetric) {
if (changed == 0) handleIn = pos * 2.0 - handleOut;
else handleOut = pos * 2.0 - handleIn;
}
else if (mode == HandleMode::Smooth) {
if (changed == 0) {
double lenIn = (handleIn - pos).length();
Vec2 dir = (pos - handleOut).normalized();
handleIn = pos + dir * lenIn;
} else {
double lenOut = (handleOut - pos).length();
Vec2 dir = (pos - handleIn).normalized();
handleOut = pos + dir * lenOut;
}
}
// Free / Corner: 不同步
}
// 是否为平滑点(非尖点)
bool IsSmooth() const { return mode != HandleMode::Corner; }
};
// ---------- 曲线描边 ----------
struct CurveStroke
{
std::vector<AnchorPoint> points;
bool closed = false;
COLORREF color = RGB(0, 0, 0);
double width = 1.0;
bool visible = true; // 图层可见性
bool locked = false; // 图层锁定(禁止编辑)
std::wstring name; // 图层名称
// 段数
int SegCount() const {
int n = (int)points.size();
if (n < 2) return 0;
return closed ? n : n - 1;
}
// 取第 seg 段的四个贝塞尔控制点
void GetSeg(int seg, Vec2& p0, Vec2& p1, Vec2& p2, Vec2& p3) const {
int n = (int)points.size();
const AnchorPoint& a = points[seg % n];
const AnchorPoint& b = points[(seg + 1) % n];
p0 = a.pos;
p1 = a.handleOut;
p2 = b.handleIn;
p3 = b.pos;
}
};
// ---------- NURBS 曲线 ----------
struct NURBSStroke
{
std::vector<Vec2> controlPoints;
std::vector<double> weights;
std::vector<double> knots;
int degree = 3;
bool closed = false;
COLORREF color = RGB(0, 0, 0);
double width = 1.0;
bool visible = true;
bool locked = false;
std::wstring name;
// 生成夹紧节点向量(随控制点数量自动更新)
void EnsureKnots() {
int n = (int)controlPoints.size();
if (n < 1) return;
int expected = n + degree + 1;
if ((int)knots.size() == expected) return;
knots.assign(expected, 0.0);
if (n <= degree) {
// 控制点不足 degree+1 时生成均匀节点,避免越界
for (int i = 0; i < expected; ++i)
knots[i] = (double)i / (double)(expected - 1);
} else {
for (int i = degree + 1; i < n; ++i)
knots[i] = (double)(i - degree) / (double)(n - degree);
for (int i = n; i <= n + degree; ++i)
knots[i] = 1.0;
}
}
// 初始化 weights(保持与 controlPoints 数量一致)
void EnsureWeights() {
if ((int)weights.size() != (int)controlPoints.size()) {
weights.assign(controlPoints.size(), 1.0);
}
}
};