@ccpc/math 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/constants/geom_type.d.ts +13 -0
- package/dist/constants/geom_type.d.ts.map +1 -0
- package/dist/constants/geom_type.js +17 -0
- package/dist/constants/math_const.d.ts +9 -0
- package/dist/constants/math_const.d.ts.map +1 -0
- package/dist/constants/math_const.js +12 -0
- package/dist/core/box2.d.ts +71 -0
- package/dist/core/box2.d.ts.map +1 -0
- package/dist/core/box2.js +243 -0
- package/dist/core/coord2d.d.ts +62 -0
- package/dist/core/coord2d.d.ts.map +1 -0
- package/dist/core/coord2d.js +155 -0
- package/dist/core/geom_base.d.ts +19 -0
- package/dist/core/geom_base.d.ts.map +1 -0
- package/dist/core/geom_base.js +18 -0
- package/dist/core/mat3.d.ts +101 -0
- package/dist/core/mat3.d.ts.map +1 -0
- package/dist/core/mat3.js +290 -0
- package/dist/core/vec2.d.ts +138 -0
- package/dist/core/vec2.d.ts.map +1 -0
- package/dist/core/vec2.js +297 -0
- package/dist/curves/arc2.d.ts +49 -0
- package/dist/curves/arc2.d.ts.map +1 -0
- package/dist/curves/arc2.js +265 -0
- package/dist/curves/bspline2.d.ts +150 -0
- package/dist/curves/bspline2.d.ts.map +1 -0
- package/dist/curves/bspline2.js +793 -0
- package/dist/curves/circle2.d.ts +42 -0
- package/dist/curves/circle2.d.ts.map +1 -0
- package/dist/curves/circle2.js +135 -0
- package/dist/curves/circle_curve2.d.ts +38 -0
- package/dist/curves/circle_curve2.d.ts.map +1 -0
- package/dist/curves/circle_curve2.js +112 -0
- package/dist/curves/curve2.d.ts +214 -0
- package/dist/curves/curve2.d.ts.map +1 -0
- package/dist/curves/curve2.js +238 -0
- package/dist/curves/ellipse2.d.ts +42 -0
- package/dist/curves/ellipse2.d.ts.map +1 -0
- package/dist/curves/ellipse2.js +125 -0
- package/dist/curves/ellipse_arc2.d.ts +49 -0
- package/dist/curves/ellipse_arc2.d.ts.map +1 -0
- package/dist/curves/ellipse_arc2.js +184 -0
- package/dist/curves/ellipse_curve2.d.ts +56 -0
- package/dist/curves/ellipse_curve2.d.ts.map +1 -0
- package/dist/curves/ellipse_curve2.js +262 -0
- package/dist/curves/interval.d.ts +112 -0
- package/dist/curves/interval.d.ts.map +1 -0
- package/dist/curves/interval.js +200 -0
- package/dist/curves/line2.d.ts +64 -0
- package/dist/curves/line2.d.ts.map +1 -0
- package/dist/curves/line2.js +193 -0
- package/dist/curves/period_interval.d.ts +129 -0
- package/dist/curves/period_interval.d.ts.map +1 -0
- package/dist/curves/period_interval.js +240 -0
- package/dist/discretize/discretize_defaults.d.ts +12 -0
- package/dist/discretize/discretize_defaults.d.ts.map +1 -0
- package/dist/discretize/discretize_defaults.js +12 -0
- package/dist/discretize/discretize_engine.d.ts +33 -0
- package/dist/discretize/discretize_engine.d.ts.map +1 -0
- package/dist/discretize/discretize_engine.js +347 -0
- package/dist/discretize/discretize_errors.d.ts +15 -0
- package/dist/discretize/discretize_errors.d.ts.map +1 -0
- package/dist/discretize/discretize_errors.js +30 -0
- package/dist/discretize/discretize_options.d.ts +18 -0
- package/dist/discretize/discretize_options.d.ts.map +1 -0
- package/dist/discretize/discretize_options.js +19 -0
- package/dist/discretize/discretize_types.d.ts +36 -0
- package/dist/discretize/discretize_types.d.ts.map +1 -0
- package/dist/discretize/discretize_types.js +1 -0
- package/dist/discretize/internal/curve_guards.d.ts +35 -0
- package/dist/discretize/internal/curve_guards.d.ts.map +1 -0
- package/dist/discretize/internal/curve_guards.js +62 -0
- package/dist/discretize/internal/postprocess.d.ts +5 -0
- package/dist/discretize/internal/postprocess.d.ts.map +1 -0
- package/dist/discretize/internal/postprocess.js +109 -0
- package/dist/discretize/internal/sampling_utils.d.ts +8 -0
- package/dist/discretize/internal/sampling_utils.d.ts.map +1 -0
- package/dist/discretize/internal/sampling_utils.js +36 -0
- package/dist/discretize/register_builtin_strategies.d.ts +3 -0
- package/dist/discretize/register_builtin_strategies.d.ts.map +1 -0
- package/dist/discretize/register_builtin_strategies.js +10 -0
- package/dist/discretize/strategies/bspline_strategy.d.ts +4 -0
- package/dist/discretize/strategies/bspline_strategy.d.ts.map +1 -0
- package/dist/discretize/strategies/bspline_strategy.js +115 -0
- package/dist/discretize/strategies/circle_strategy.d.ts +7 -0
- package/dist/discretize/strategies/circle_strategy.d.ts.map +1 -0
- package/dist/discretize/strategies/circle_strategy.js +55 -0
- package/dist/discretize/strategies/ellipse_strategy.d.ts +7 -0
- package/dist/discretize/strategies/ellipse_strategy.d.ts.map +1 -0
- package/dist/discretize/strategies/ellipse_strategy.js +86 -0
- package/dist/discretize/strategies/line_strategy.d.ts +4 -0
- package/dist/discretize/strategies/line_strategy.d.ts.map +1 -0
- package/dist/discretize/strategies/line_strategy.js +40 -0
- package/dist/discretize/strategy_registry.d.ts +9 -0
- package/dist/discretize/strategy_registry.d.ts.map +1 -0
- package/dist/discretize/strategy_registry.js +34 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/intersections/analytic_x_algorithm.d.ts +10 -0
- package/dist/intersections/analytic_x_algorithm.d.ts.map +1 -0
- package/dist/intersections/analytic_x_algorithm.js +83 -0
- package/dist/intersections/curve_x_engine.d.ts +9 -0
- package/dist/intersections/curve_x_engine.d.ts.map +1 -0
- package/dist/intersections/curve_x_engine.js +27 -0
- package/dist/intersections/index.d.ts +5 -0
- package/dist/intersections/index.d.ts.map +1 -0
- package/dist/intersections/index.js +11 -0
- package/dist/intersections/internal/certification.d.ts +34 -0
- package/dist/intersections/internal/certification.d.ts.map +1 -0
- package/dist/intersections/internal/certification.js +238 -0
- package/dist/intersections/internal/interval_clipping.d.ts +29 -0
- package/dist/intersections/internal/interval_clipping.d.ts.map +1 -0
- package/dist/intersections/internal/interval_clipping.js +123 -0
- package/dist/intersections/internal/kind.d.ts +4 -0
- package/dist/intersections/internal/kind.d.ts.map +1 -0
- package/dist/intersections/internal/kind.js +16 -0
- package/dist/intersections/internal/pair.d.ts +9 -0
- package/dist/intersections/internal/pair.d.ts.map +1 -0
- package/dist/intersections/internal/pair.js +14 -0
- package/dist/intersections/internal/result.d.ts +20 -0
- package/dist/intersections/internal/result.d.ts.map +1 -0
- package/dist/intersections/internal/result.js +125 -0
- package/dist/intersections/internal/sampling.d.ts +15 -0
- package/dist/intersections/internal/sampling.d.ts.map +1 -0
- package/dist/intersections/internal/sampling.js +131 -0
- package/dist/intersections/internal/segment.d.ts +32 -0
- package/dist/intersections/internal/segment.d.ts.map +1 -0
- package/dist/intersections/internal/segment.js +137 -0
- package/dist/intersections/internal/tolerance.d.ts +10 -0
- package/dist/intersections/internal/tolerance.d.ts.map +1 -0
- package/dist/intersections/internal/tolerance.js +20 -0
- package/dist/intersections/intersector.d.ts +6 -0
- package/dist/intersections/intersector.d.ts.map +1 -0
- package/dist/intersections/intersector.js +1 -0
- package/dist/intersections/numeric_x_algorithm.d.ts +10 -0
- package/dist/intersections/numeric_x_algorithm.d.ts.map +1 -0
- package/dist/intersections/numeric_x_algorithm.js +73 -0
- package/dist/intersections/solvers/bspline_self_solver.d.ts +7 -0
- package/dist/intersections/solvers/bspline_self_solver.d.ts.map +1 -0
- package/dist/intersections/solvers/bspline_self_solver.js +308 -0
- package/dist/intersections/solvers/line_line_pair_solver.d.ts +7 -0
- package/dist/intersections/solvers/line_line_pair_solver.d.ts.map +1 -0
- package/dist/intersections/solvers/line_line_pair_solver.js +35 -0
- package/dist/intersections/solvers/pair_solvers.d.ts +94 -0
- package/dist/intersections/solvers/pair_solvers.d.ts.map +1 -0
- package/dist/intersections/solvers/pair_solvers.js +1078 -0
- package/dist/intersections/solvers/polyline_pair_intersector.d.ts +51 -0
- package/dist/intersections/solvers/polyline_pair_intersector.d.ts.map +1 -0
- package/dist/intersections/solvers/polyline_pair_intersector.js +731 -0
- package/dist/intersections/types.d.ts +11 -0
- package/dist/intersections/types.d.ts.map +1 -0
- package/dist/intersections/types.js +1 -0
- package/dist/serialize/dump_types.d.ts +101 -0
- package/dist/serialize/dump_types.d.ts.map +1 -0
- package/dist/serialize/dump_types.js +5 -0
- package/dist/serialize/geom_mgr.d.ts +24 -0
- package/dist/serialize/geom_mgr.d.ts.map +1 -0
- package/dist/serialize/geom_mgr.js +30 -0
- package/dist/types/type_define.d.ts +29 -0
- package/dist/types/type_define.d.ts.map +1 -0
- package/dist/types/type_define.js +10 -0
- package/dist/types/type_guard.d.ts +46 -0
- package/dist/types/type_guard.d.ts.map +1 -0
- package/dist/types/type_guard.js +5 -0
- package/dist/utils/math_error.d.ts +16 -0
- package/dist/utils/math_error.d.ts.map +1 -0
- package/dist/utils/math_error.js +35 -0
- package/dist/utils/math_utils.d.ts +9 -0
- package/dist/utils/math_utils.d.ts.map +1 -0
- package/dist/utils/math_utils.js +25 -0
- package/dist/utils/precision.d.ts +29 -0
- package/dist/utils/precision.d.ts.map +1 -0
- package/dist/utils/precision.js +44 -0
- package/package.json +38 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Linea Math - Curves
|
|
3
|
+
* Curve2: 二维曲线抽象基类
|
|
4
|
+
*/
|
|
5
|
+
import { GeomBase } from '../core/geom_base';
|
|
6
|
+
import { MathError } from '../utils/math_error';
|
|
7
|
+
import { Precision } from '../utils/precision';
|
|
8
|
+
import { DiscretizeEngine } from '../discretize/discretize_engine';
|
|
9
|
+
import { Interval } from './interval';
|
|
10
|
+
export class Curve2 extends GeomBase {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
/**
|
|
14
|
+
* 参数域
|
|
15
|
+
* - 默认使用无界区间,具体曲线应在子类中覆盖
|
|
16
|
+
* - 子类可直接赋值 this._range,或调用 setRange()
|
|
17
|
+
*/
|
|
18
|
+
this._range = Interval.infinite();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 获取参数域。
|
|
22
|
+
* @returns 参数域副本,调用方修改不会影响内部状态。
|
|
23
|
+
*/
|
|
24
|
+
getRange() {
|
|
25
|
+
return this._range.clone();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 判断参数是否落在当前曲线参数域内。
|
|
29
|
+
* @param u 待判断参数。
|
|
30
|
+
* @param eps 区间边界比较容差。
|
|
31
|
+
* @returns 落在参数域内返回 `true`。
|
|
32
|
+
*/
|
|
33
|
+
containsParam(u, eps = Precision.CURVE_PARAM_EPS) {
|
|
34
|
+
return this._range.contains(u, eps);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 是否为退化曲线。
|
|
38
|
+
* 默认规则:参数域过小或曲线长度过小。
|
|
39
|
+
*/
|
|
40
|
+
isDegenerate() {
|
|
41
|
+
return this._range.length() <= Precision.CURVE_PARAM_EPS || this.length() <= Precision.CURVE_LENGTH_EPS;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 是否为闭合曲线。
|
|
45
|
+
* 默认返回 `false`,由闭合曲线子类覆盖。
|
|
46
|
+
*/
|
|
47
|
+
isClosed() {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
/** 是否为线段曲线。 */
|
|
51
|
+
isLine() {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/** 是否为整圆曲线。 */
|
|
55
|
+
isCircle() {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/** 是否为圆弧曲线。 */
|
|
59
|
+
isArc() {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/** 是否为整椭圆曲线。 */
|
|
63
|
+
isEllipse() {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
/** 是否为椭圆弧曲线。 */
|
|
67
|
+
isEllipseArc() {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/** 是否为 B 样条曲线。 */
|
|
71
|
+
isBSpline() {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 获取第 `n` 阶导数(默认由 `derivatives` 派生)。
|
|
76
|
+
* @param u 曲线参数。
|
|
77
|
+
* @param n 导数阶数,要求为非负整数。
|
|
78
|
+
* @returns 第 `n` 阶导数向量。
|
|
79
|
+
*/
|
|
80
|
+
derivativeAt(u, n) {
|
|
81
|
+
MathError.assert(Number.isInteger(n) && n >= 0, 'Curve2.derivativeAt: n must be a non-negative integer');
|
|
82
|
+
const ds = this.derivatives(u, n);
|
|
83
|
+
MathError.assert(ds.length > n, 'Curve2.derivativeAt: derivative order is not available');
|
|
84
|
+
return ds[n];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 最近参数(默认由 `closestPoint` 派生)。
|
|
88
|
+
* @param p 查询点。
|
|
89
|
+
* @param tol 计算容差。
|
|
90
|
+
* @returns 最近点对应参数。
|
|
91
|
+
*/
|
|
92
|
+
closestParam(p, tol = Precision.LEN_EPS) {
|
|
93
|
+
return this.closestPoint(p, tol).param;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 点到曲线距离(默认由 `closestPoint` 派生)。
|
|
97
|
+
* @param p 查询点。
|
|
98
|
+
* @param tol 计算容差。
|
|
99
|
+
* @returns 点到曲线的最短距离。
|
|
100
|
+
*/
|
|
101
|
+
distanceToPoint(p, tol = Precision.LEN_EPS) {
|
|
102
|
+
return this.closestPoint(p, tol).distance;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 曲线离散化便捷入口(薄封装)。
|
|
106
|
+
* @param options 离散参数。
|
|
107
|
+
* @returns 折线采样结果。
|
|
108
|
+
*/
|
|
109
|
+
discretize(options) {
|
|
110
|
+
return DiscretizeEngine.discretize(this, options);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 设置参数域(供子类构造期使用)。
|
|
114
|
+
* @param range 参数区间。
|
|
115
|
+
* @returns 当前实例。
|
|
116
|
+
*/
|
|
117
|
+
setRange(range) {
|
|
118
|
+
this._range = range.clone();
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Newton + 二分混合求解参数(常用于弧长反参)。
|
|
123
|
+
* @param target 目标值(如目标弧长)。
|
|
124
|
+
* @param start 参数下界。
|
|
125
|
+
* @param end 参数上界。
|
|
126
|
+
* @param tol 收敛容差。
|
|
127
|
+
* @param evalValue 参数到目标量的映射函数(要求在 [start, end] 上单调)。
|
|
128
|
+
* @param evalSlope 参数处导数量(如速度),用于 Newton 步。
|
|
129
|
+
* @param failMessage 未收敛时抛错信息。
|
|
130
|
+
* @param initialGuess 可选初值;不传时取区间中点。
|
|
131
|
+
* @returns 收敛后的参数。
|
|
132
|
+
*/
|
|
133
|
+
solveParamByHybridNewton(target, start, end, tol, evalValue, evalSlope, failMessage, initialGuess) {
|
|
134
|
+
MathError.assert(Number.isFinite(start) && Number.isFinite(end) && end > start, 'Curve2.solveParamByHybridNewton: invalid range');
|
|
135
|
+
MathError.assert(Number.isFinite(tol) && tol > 0, 'Curve2.solveParamByHybridNewton: tol must be > 0');
|
|
136
|
+
// lo/hi 始终包住当前根,Newton 出界时回退到二分保证收敛性。
|
|
137
|
+
let lo = start;
|
|
138
|
+
let hi = end;
|
|
139
|
+
let u = initialGuess ?? ((lo + hi) * 0.5);
|
|
140
|
+
if (!Number.isFinite(u) || u <= lo || u >= hi) {
|
|
141
|
+
u = (lo + hi) * 0.5;
|
|
142
|
+
}
|
|
143
|
+
for (let i = 0; i < Precision.CURVE_MAX_ITER; i++) {
|
|
144
|
+
const value = evalValue(u);
|
|
145
|
+
const f = value - target;
|
|
146
|
+
if (Math.abs(f) <= tol)
|
|
147
|
+
return u;
|
|
148
|
+
const slope = evalSlope(u);
|
|
149
|
+
let next = Number.NaN;
|
|
150
|
+
if (Math.abs(slope) > Precision.CURVE_NEWTON_EPS) {
|
|
151
|
+
next = u - f / slope;
|
|
152
|
+
}
|
|
153
|
+
// Newton 步越界或数值异常时,退回二分步,避免振荡/发散。
|
|
154
|
+
if (!Number.isFinite(next) || next <= lo || next >= hi) {
|
|
155
|
+
next = (lo + hi) * 0.5;
|
|
156
|
+
}
|
|
157
|
+
if (f > 0) {
|
|
158
|
+
hi = u;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
lo = u;
|
|
162
|
+
}
|
|
163
|
+
u = next;
|
|
164
|
+
}
|
|
165
|
+
MathError.throw(failMessage);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* “采样粗定位 + Newton 细化”最近点求解通用流程。
|
|
169
|
+
* @param p 查询点。
|
|
170
|
+
* @param tol 收敛容差。
|
|
171
|
+
* @param sampleCount 初始采样数(含两端点)。
|
|
172
|
+
* @param evalPoint 参数求点函数。
|
|
173
|
+
* @param evalD1 一阶导函数。
|
|
174
|
+
* @param evalD2 二阶导函数。
|
|
175
|
+
* @param failMessage 未收敛时抛错信息。
|
|
176
|
+
* @param compareParam 参数平局比较器(返回 <0 表示 a 更优)。
|
|
177
|
+
* @returns 最近点结果。
|
|
178
|
+
*/
|
|
179
|
+
solveClosestPointBySampleNewton(p, tol, sampleCount, evalPoint, evalD1, evalD2, failMessage, compareParam = (a, b) => a - b) {
|
|
180
|
+
MathError.assert(Number.isFinite(tol) && tol > 0, 'Curve2.solveClosestPointBySampleNewton: tol must be > 0');
|
|
181
|
+
MathError.assert(Number.isInteger(sampleCount) && sampleCount > 0, 'Curve2.solveClosestPointBySampleNewton: sampleCount must be a positive integer');
|
|
182
|
+
const start = this._range.start;
|
|
183
|
+
const span = this._range.length();
|
|
184
|
+
// 零跨度参数域直接退化为单点评估。
|
|
185
|
+
if (span <= Precision.CURVE_PARAM_EPS) {
|
|
186
|
+
const point = evalPoint(start);
|
|
187
|
+
return { point, param: start, distance: point.distanceTo(p) };
|
|
188
|
+
}
|
|
189
|
+
// 第 1 阶段:均匀采样找一个稳定的初始参数。
|
|
190
|
+
let bestU = start;
|
|
191
|
+
let bestDistSq = Number.POSITIVE_INFINITY;
|
|
192
|
+
for (let i = 0; i <= sampleCount; i++) {
|
|
193
|
+
const u = start + (span * i) / sampleCount;
|
|
194
|
+
const q = evalPoint(u);
|
|
195
|
+
const d2 = q.distanceToSq(p);
|
|
196
|
+
if (d2 < bestDistSq - tol * tol) {
|
|
197
|
+
bestDistSq = d2;
|
|
198
|
+
bestU = u;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (Math.abs(d2 - bestDistSq) <= tol * tol && compareParam(u, bestU) < 0) {
|
|
202
|
+
bestU = u;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// 第 2 阶段:在采样命中的局部窗口做 Newton 迭代。
|
|
206
|
+
const step = span / sampleCount;
|
|
207
|
+
let lo = Math.max(start, bestU - step);
|
|
208
|
+
let hi = Math.min(start + span, bestU + step);
|
|
209
|
+
let u = bestU;
|
|
210
|
+
for (let i = 0; i < Precision.CURVE_MAX_ITER; i++) {
|
|
211
|
+
const c = evalPoint(u);
|
|
212
|
+
const d1 = evalD1(u);
|
|
213
|
+
const d2 = evalD2(u);
|
|
214
|
+
const cp = c.subtracted(p);
|
|
215
|
+
const f = cp.dot(d1);
|
|
216
|
+
if (Math.abs(f) <= tol) {
|
|
217
|
+
return { point: c, param: u, distance: c.distanceTo(p) };
|
|
218
|
+
}
|
|
219
|
+
const fp = d1.dot(d1) + cp.dot(d2);
|
|
220
|
+
let next = Number.NaN;
|
|
221
|
+
if (Math.abs(fp) > Precision.CURVE_NEWTON_EPS) {
|
|
222
|
+
next = u - f / fp;
|
|
223
|
+
}
|
|
224
|
+
// Newton 失效时回退二分,保持区间收缩。
|
|
225
|
+
if (!Number.isFinite(next) || next <= lo || next >= hi) {
|
|
226
|
+
next = (lo + hi) * 0.5;
|
|
227
|
+
}
|
|
228
|
+
if (f > 0) {
|
|
229
|
+
hi = u;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
lo = u;
|
|
233
|
+
}
|
|
234
|
+
u = next;
|
|
235
|
+
}
|
|
236
|
+
MathError.throw(failMessage);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EN_GEO_TYPE } from '../constants/geom_type';
|
|
2
|
+
import { Box2 } from '../core/box2';
|
|
3
|
+
import { Mat3 } from '../core/mat3';
|
|
4
|
+
import { Vec2 } from '../core/vec2';
|
|
5
|
+
import type { IDBEllipse2 } from '../serialize/dump_types';
|
|
6
|
+
import { EllipseArc2 } from './ellipse_arc2';
|
|
7
|
+
import { EllipseCurve2 } from './ellipse_curve2';
|
|
8
|
+
import { Interval } from './interval';
|
|
9
|
+
export declare class Ellipse2 extends EllipseCurve2 {
|
|
10
|
+
static readonly type = EN_GEO_TYPE.Ellipse2;
|
|
11
|
+
/**
|
|
12
|
+
* 构造整椭圆。
|
|
13
|
+
* @param center 中心点。
|
|
14
|
+
* @param rx 长半轴。
|
|
15
|
+
* @param ry 短半轴。
|
|
16
|
+
* @param rotation 椭圆局部 x 轴相对全局 x 轴旋转角(弧度)。
|
|
17
|
+
*/
|
|
18
|
+
constructor(center: Vec2, rx: number, ry: number, rotation?: number);
|
|
19
|
+
split(u: number): EllipseArc2[];
|
|
20
|
+
trim(range: Interval): EllipseArc2[];
|
|
21
|
+
reverse(): this;
|
|
22
|
+
transform(m: Mat3): this;
|
|
23
|
+
transformed(m: Mat3): this;
|
|
24
|
+
boundingBox(): Box2;
|
|
25
|
+
isValid(eps?: number): boolean;
|
|
26
|
+
isClosed(): boolean;
|
|
27
|
+
isEllipse(): this is Ellipse2;
|
|
28
|
+
/**
|
|
29
|
+
* 结构等价判断(字段级)。
|
|
30
|
+
* @param other 对比椭圆。
|
|
31
|
+
* @param eps 数值容差。
|
|
32
|
+
* @returns 中心、长短半轴和旋转角近似相等时返回 `true`。
|
|
33
|
+
*/
|
|
34
|
+
equals(other: Ellipse2, eps?: number): boolean;
|
|
35
|
+
clone(): this;
|
|
36
|
+
dump(): IDBEllipse2;
|
|
37
|
+
static load(data: IDBEllipse2): Ellipse2;
|
|
38
|
+
protected paramToAngle(u: number): number;
|
|
39
|
+
protected angleToParam(theta: number): number;
|
|
40
|
+
protected angleDerivativeSign(): 1 | -1;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=ellipse2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ellipse2.d.ts","sourceRoot":"","sources":["../../src/curves/ellipse2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEpD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAI1D,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,qBAKa,QAAS,SAAQ,aAAa;IACvC,gBAAuB,IAAI,wBAAuB;IAElD;;;;;;OAMG;gBACS,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAI;IAK9C,KAAK,CAAC,CAAC,EAAE,MAAM;IAYf,IAAI,CAAC,KAAK,EAAE,QAAQ;IAOpB,OAAO;IAKP,SAAS,CAAC,CAAC,EAAE,IAAI;IAWjB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI;IAI1B,WAAW;IAaX,OAAO,CAAC,GAAG,SAA6B;IAIxC,QAAQ,IAAI,OAAO;IAInB,SAAS,IAAI,IAAI,IAAI,QAAQ;IAI7C;;;;;OAKG;IACI,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,SAAgB;IAOlC,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,WAAW;WAUrB,IAAI,CAAC,IAAI,EAAE,WAAW;cASjB,YAAY,CAAC,CAAC,EAAE,MAAM;cAKtB,YAAY,CAAC,KAAK,EAAE,MAAM;cAK1B,mBAAmB,IAAI,CAAC,GAAG,CAAC,CAAC;CAGnD"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var Ellipse2_1;
|
|
8
|
+
import { EN_GEO_TYPE } from '../constants/geom_type';
|
|
9
|
+
import { MathConst } from '../constants/math_const';
|
|
10
|
+
import { Box2 } from '../core/box2';
|
|
11
|
+
import { Vec2 } from '../core/vec2';
|
|
12
|
+
import { RegisterGeom } from '../serialize/geom_mgr';
|
|
13
|
+
import { MathError } from '../utils/math_error';
|
|
14
|
+
import { Precision } from '../utils/precision';
|
|
15
|
+
import { EllipseArc2 } from './ellipse_arc2';
|
|
16
|
+
import { EllipseCurve2 } from './ellipse_curve2';
|
|
17
|
+
import { PeriodInterval } from './period_interval';
|
|
18
|
+
let Ellipse2 = Ellipse2_1 = class Ellipse2 extends EllipseCurve2 {
|
|
19
|
+
/**
|
|
20
|
+
* 构造整椭圆。
|
|
21
|
+
* @param center 中心点。
|
|
22
|
+
* @param rx 长半轴。
|
|
23
|
+
* @param ry 短半轴。
|
|
24
|
+
* @param rotation 椭圆局部 x 轴相对全局 x 轴旋转角(弧度)。
|
|
25
|
+
*/
|
|
26
|
+
constructor(center, rx, ry, rotation = 0) {
|
|
27
|
+
super(center, rx, ry, rotation);
|
|
28
|
+
this.setRange(new PeriodInterval(0, MathConst.PI2, MathConst.PI2));
|
|
29
|
+
}
|
|
30
|
+
split(u) {
|
|
31
|
+
const range = this._range;
|
|
32
|
+
const uu = range.normalizeInPeriod(u, range.start);
|
|
33
|
+
if (Math.abs(uu - range.start) <= Precision.CURVE_PARAM_EPS || Math.abs(uu - range.end) <= Precision.CURVE_PARAM_EPS) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const left = new EllipseArc2(this._center, this._rx, this._ry, this._rotation, range.start, uu, false);
|
|
37
|
+
const right = new EllipseArc2(this._center, this._rx, this._ry, this._rotation, uu, range.start + range.period, false);
|
|
38
|
+
return [left, right].filter((arc) => arc.length() > Precision.CURVE_LENGTH_EPS);
|
|
39
|
+
}
|
|
40
|
+
trim(range) {
|
|
41
|
+
this._range.assertContainsRange(range, Precision.CURVE_PARAM_EPS);
|
|
42
|
+
if (range.length() <= Precision.CURVE_PARAM_EPS)
|
|
43
|
+
return [];
|
|
44
|
+
return [new EllipseArc2(this._center, this._rx, this._ry, this._rotation, range.start, range.end, false)];
|
|
45
|
+
}
|
|
46
|
+
reverse() {
|
|
47
|
+
// 整椭圆反转后几何与参数域等价,保持不变即可。
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
transform(m) {
|
|
51
|
+
const next = this.transformedEllipseParams(m);
|
|
52
|
+
MathError.assert(next.rx > Precision.CURVE_LENGTH_EPS && next.ry > Precision.CURVE_LENGTH_EPS, 'Ellipse2.transform: degenerate ellipse after transform');
|
|
53
|
+
this._center = next.center;
|
|
54
|
+
this._rx = next.rx;
|
|
55
|
+
this._ry = next.ry;
|
|
56
|
+
this._rotation = next.rotation;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
transformed(m) {
|
|
60
|
+
return this.clone().transform(m);
|
|
61
|
+
}
|
|
62
|
+
boundingBox() {
|
|
63
|
+
const c = Math.cos(this._rotation);
|
|
64
|
+
const s = Math.sin(this._rotation);
|
|
65
|
+
const ex = Math.hypot(this._rx * c, this._ry * s);
|
|
66
|
+
const ey = Math.hypot(this._rx * s, this._ry * c);
|
|
67
|
+
return new Box2(this._center.x - ex, this._center.y - ey, this._center.x + ex, this._center.y + ey);
|
|
68
|
+
}
|
|
69
|
+
isValid(eps = Precision.CURVE_LENGTH_EPS) {
|
|
70
|
+
return this.isEllipseStructValid(eps);
|
|
71
|
+
}
|
|
72
|
+
isClosed() {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
isEllipse() {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 结构等价判断(字段级)。
|
|
80
|
+
* @param other 对比椭圆。
|
|
81
|
+
* @param eps 数值容差。
|
|
82
|
+
* @returns 中心、长短半轴和旋转角近似相等时返回 `true`。
|
|
83
|
+
*/
|
|
84
|
+
equals(other, eps = Precision.EPS) {
|
|
85
|
+
return this._center.equals(other._center, eps) &&
|
|
86
|
+
Precision.equal(this._rx, other._rx, eps) &&
|
|
87
|
+
Precision.equal(this._ry, other._ry, eps) &&
|
|
88
|
+
Precision.equal(this._rotation, other._rotation, eps);
|
|
89
|
+
}
|
|
90
|
+
clone() {
|
|
91
|
+
return new Ellipse2_1(this._center, this._rx, this._ry, this._rotation);
|
|
92
|
+
}
|
|
93
|
+
dump() {
|
|
94
|
+
return {
|
|
95
|
+
type: Ellipse2_1.type,
|
|
96
|
+
center: { x: this._center.x, y: this._center.y },
|
|
97
|
+
rx: this._rx,
|
|
98
|
+
ry: this._ry,
|
|
99
|
+
rotation: this._rotation,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
static load(data) {
|
|
103
|
+
return new Ellipse2_1(new Vec2(data.center.x, data.center.y), data.rx, data.ry, data.rotation);
|
|
104
|
+
}
|
|
105
|
+
paramToAngle(u) {
|
|
106
|
+
const range = this._range;
|
|
107
|
+
return range.normalizeInPeriod(u, range.start);
|
|
108
|
+
}
|
|
109
|
+
angleToParam(theta) {
|
|
110
|
+
const range = this._range;
|
|
111
|
+
return range.normalizeInPeriod(theta, range.start);
|
|
112
|
+
}
|
|
113
|
+
angleDerivativeSign() {
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
Ellipse2.type = EN_GEO_TYPE.Ellipse2;
|
|
118
|
+
Ellipse2 = Ellipse2_1 = __decorate([
|
|
119
|
+
RegisterGeom
|
|
120
|
+
/**
|
|
121
|
+
* 二维整椭圆曲线。
|
|
122
|
+
* 参数域固定为 `PeriodInterval(0, 2π, 2π)`。
|
|
123
|
+
*/
|
|
124
|
+
], Ellipse2);
|
|
125
|
+
export { Ellipse2 };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EN_GEO_TYPE } from '../constants/geom_type';
|
|
2
|
+
import { Mat3 } from '../core/mat3';
|
|
3
|
+
import { Vec2 } from '../core/vec2';
|
|
4
|
+
import type { IDBEllipseArc2 } from '../serialize/dump_types';
|
|
5
|
+
import { EllipseCurve2 } from './ellipse_curve2';
|
|
6
|
+
import { Interval } from './interval';
|
|
7
|
+
export declare class EllipseArc2 extends EllipseCurve2 {
|
|
8
|
+
static readonly type = EN_GEO_TYPE.EllipseArc2;
|
|
9
|
+
private _clockwise;
|
|
10
|
+
/**
|
|
11
|
+
* 构造椭圆弧。
|
|
12
|
+
* @param center 中心点。
|
|
13
|
+
* @param rx 长半轴。
|
|
14
|
+
* @param ry 短半轴。
|
|
15
|
+
* @param rotation 椭圆局部 x 轴相对全局 x 轴旋转角(弧度)。
|
|
16
|
+
* @param startAngle 起始角(几何语义)。
|
|
17
|
+
* @param endAngle 终止角(几何语义)。
|
|
18
|
+
* @param clockwise 是否顺时针。
|
|
19
|
+
*/
|
|
20
|
+
constructor(center: Vec2, rx: number, ry: number, rotation: number, startAngle: number, endAngle: number, clockwise?: boolean);
|
|
21
|
+
get clockwise(): boolean;
|
|
22
|
+
get startAngle(): number;
|
|
23
|
+
get endAngle(): number;
|
|
24
|
+
split(u: number): EllipseArc2[];
|
|
25
|
+
trim(range: Interval): EllipseArc2[];
|
|
26
|
+
reverse(): this;
|
|
27
|
+
transform(m: Mat3): this;
|
|
28
|
+
transformed(m: Mat3): this;
|
|
29
|
+
isValid(eps?: number): boolean;
|
|
30
|
+
isClosed(): boolean;
|
|
31
|
+
isEllipseArc(): this is EllipseArc2;
|
|
32
|
+
/**
|
|
33
|
+
* 结构等价判断(字段级)。
|
|
34
|
+
* @param other 对比椭圆弧。
|
|
35
|
+
* @param eps 数值容差。
|
|
36
|
+
* @returns 中心、轴长、旋转、方向与起终角参数近似相等时返回 `true`。
|
|
37
|
+
*/
|
|
38
|
+
equals(other: EllipseArc2, eps?: number): boolean;
|
|
39
|
+
clone(): this;
|
|
40
|
+
dump(): IDBEllipseArc2;
|
|
41
|
+
static load(data: IDBEllipseArc2): EllipseArc2;
|
|
42
|
+
protected paramToAngle(u: number): number;
|
|
43
|
+
protected angleToParam(theta: number): number;
|
|
44
|
+
protected angleDerivativeSign(): 1 | -1;
|
|
45
|
+
private resetAngles;
|
|
46
|
+
private normalizeAngle;
|
|
47
|
+
private positiveMod;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=ellipse_arc2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ellipse_arc2.d.ts","sourceRoot":"","sources":["../../src/curves/ellipse_arc2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEpD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAI7D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,qBAKa,WAAY,SAAQ,aAAa;IAC1C,gBAAuB,IAAI,2BAA0B;IAErD,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;;;;OASG;gBACS,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,UAAQ;IAO3H,IAAW,SAAS,YAEnB;IAED,IAAW,UAAU,WAEpB;IAED,IAAW,QAAQ,WAMlB;IAEe,KAAK,CAAC,CAAC,EAAE,MAAM;IAUf,IAAI,CAAC,KAAK,EAAE,QAAQ;IAUpB,OAAO;IAOP,SAAS,CAAC,CAAC,EAAE,IAAI;IA4BjB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI;IAI1B,OAAO,CAAC,GAAG,SAA6B;IAIxC,QAAQ,IAAI,OAAO;IAInB,YAAY,IAAI,IAAI,IAAI,WAAW;IAInD;;;;;OAKG;IACI,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,SAAgB;IAUrC,KAAK,IAAI,IAAI;IAYb,IAAI,IAAI,cAAc;WAaxB,IAAI,CAAC,IAAI,EAAE,cAAc;cAYpB,YAAY,CAAC,CAAC,EAAE,MAAM;cAMtB,YAAY,CAAC,KAAK,EAAE,MAAM;cAS1B,mBAAmB,IAAI,CAAC,GAAG,CAAC,CAAC;IAIhD,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;CAItB"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var EllipseArc2_1;
|
|
8
|
+
import { EN_GEO_TYPE } from '../constants/geom_type';
|
|
9
|
+
import { MathConst } from '../constants/math_const';
|
|
10
|
+
import { Vec2 } from '../core/vec2';
|
|
11
|
+
import { RegisterGeom } from '../serialize/geom_mgr';
|
|
12
|
+
import { MathError } from '../utils/math_error';
|
|
13
|
+
import { Precision } from '../utils/precision';
|
|
14
|
+
import { EllipseCurve2 } from './ellipse_curve2';
|
|
15
|
+
import { PeriodInterval } from './period_interval';
|
|
16
|
+
let EllipseArc2 = EllipseArc2_1 = class EllipseArc2 extends EllipseCurve2 {
|
|
17
|
+
/**
|
|
18
|
+
* 构造椭圆弧。
|
|
19
|
+
* @param center 中心点。
|
|
20
|
+
* @param rx 长半轴。
|
|
21
|
+
* @param ry 短半轴。
|
|
22
|
+
* @param rotation 椭圆局部 x 轴相对全局 x 轴旋转角(弧度)。
|
|
23
|
+
* @param startAngle 起始角(几何语义)。
|
|
24
|
+
* @param endAngle 终止角(几何语义)。
|
|
25
|
+
* @param clockwise 是否顺时针。
|
|
26
|
+
*/
|
|
27
|
+
constructor(center, rx, ry, rotation, startAngle, endAngle, clockwise = false) {
|
|
28
|
+
super(center, rx, ry, rotation);
|
|
29
|
+
MathError.assert(Number.isFinite(startAngle) && Number.isFinite(endAngle), 'EllipseArc2: startAngle/endAngle must be finite');
|
|
30
|
+
this._clockwise = clockwise;
|
|
31
|
+
this.resetAngles(startAngle, endAngle, clockwise);
|
|
32
|
+
}
|
|
33
|
+
get clockwise() {
|
|
34
|
+
return this._clockwise;
|
|
35
|
+
}
|
|
36
|
+
get startAngle() {
|
|
37
|
+
return this.normalizeAngle(this._range.start);
|
|
38
|
+
}
|
|
39
|
+
get endAngle() {
|
|
40
|
+
const sweep = this._range.length();
|
|
41
|
+
const end = this._clockwise
|
|
42
|
+
? this._range.start - sweep
|
|
43
|
+
: this._range.start + sweep;
|
|
44
|
+
return this.normalizeAngle(end);
|
|
45
|
+
}
|
|
46
|
+
split(u) {
|
|
47
|
+
const parts = this._range.split(u, Precision.CURVE_PARAM_EPS);
|
|
48
|
+
if (parts.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
const theta = this.paramToAngle(u);
|
|
51
|
+
const left = new EllipseArc2_1(this._center, this._rx, this._ry, this._rotation, this.startAngle, theta, this._clockwise);
|
|
52
|
+
const right = new EllipseArc2_1(this._center, this._rx, this._ry, this._rotation, theta, this.endAngle, this._clockwise);
|
|
53
|
+
return [left, right].filter((arc) => arc.length() > Precision.CURVE_LENGTH_EPS);
|
|
54
|
+
}
|
|
55
|
+
trim(range) {
|
|
56
|
+
this._range.assertContainsRange(range, Precision.CURVE_PARAM_EPS);
|
|
57
|
+
if (range.length() <= Precision.CURVE_PARAM_EPS)
|
|
58
|
+
return [];
|
|
59
|
+
const start = this.paramToAngle(range.start);
|
|
60
|
+
const end = this.paramToAngle(range.end);
|
|
61
|
+
const arc = new EllipseArc2_1(this._center, this._rx, this._ry, this._rotation, start, end, this._clockwise);
|
|
62
|
+
return arc.length() <= Precision.CURVE_LENGTH_EPS ? [] : [arc];
|
|
63
|
+
}
|
|
64
|
+
reverse() {
|
|
65
|
+
const s = this.startAngle;
|
|
66
|
+
const e = this.endAngle;
|
|
67
|
+
this.resetAngles(e, s, !this._clockwise);
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
transform(m) {
|
|
71
|
+
const oldSweep = this._range.length();
|
|
72
|
+
const startPoint = this.pointAt(this._range.start);
|
|
73
|
+
const endPoint = this.pointAt(this._range.end);
|
|
74
|
+
const next = this.transformedEllipseParams(m);
|
|
75
|
+
MathError.assert(next.rx > Precision.CURVE_LENGTH_EPS && next.ry > Precision.CURVE_LENGTH_EPS, 'EllipseArc2.transform: degenerate ellipse after transform');
|
|
76
|
+
const nextStartPoint = m.transformedPoint(startPoint);
|
|
77
|
+
const nextEndPoint = m.transformedPoint(endPoint);
|
|
78
|
+
const startAngle = this.angleFromPointOnEllipse(nextStartPoint, next.center, next.rx, next.ry, next.rotation);
|
|
79
|
+
let endAngle = this.angleFromPointOnEllipse(nextEndPoint, next.center, next.rx, next.ry, next.rotation);
|
|
80
|
+
const nextClockwise = next.mirrored ? !this._clockwise : this._clockwise;
|
|
81
|
+
if (Math.abs(oldSweep - MathConst.PI2) <= Precision.CURVE_PARAM_EPS) {
|
|
82
|
+
endAngle = startAngle + (nextClockwise ? -MathConst.PI2 : MathConst.PI2);
|
|
83
|
+
}
|
|
84
|
+
this._center = next.center;
|
|
85
|
+
this._rx = next.rx;
|
|
86
|
+
this._ry = next.ry;
|
|
87
|
+
this._rotation = next.rotation;
|
|
88
|
+
this.resetAngles(startAngle, endAngle, nextClockwise);
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
transformed(m) {
|
|
92
|
+
return this.clone().transform(m);
|
|
93
|
+
}
|
|
94
|
+
isValid(eps = Precision.CURVE_LENGTH_EPS) {
|
|
95
|
+
return this.isEllipseStructValid(eps) && this._range.length() >= 0 && this._range.length() <= MathConst.PI2 + Precision.CURVE_PARAM_EPS;
|
|
96
|
+
}
|
|
97
|
+
isClosed() {
|
|
98
|
+
return Precision.equal(this._range.length(), MathConst.PI2, Precision.CURVE_PARAM_EPS);
|
|
99
|
+
}
|
|
100
|
+
isEllipseArc() {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 结构等价判断(字段级)。
|
|
105
|
+
* @param other 对比椭圆弧。
|
|
106
|
+
* @param eps 数值容差。
|
|
107
|
+
* @returns 中心、轴长、旋转、方向与起终角参数近似相等时返回 `true`。
|
|
108
|
+
*/
|
|
109
|
+
equals(other, eps = Precision.EPS) {
|
|
110
|
+
return this._clockwise === other._clockwise &&
|
|
111
|
+
this._center.equals(other._center, eps) &&
|
|
112
|
+
Precision.equal(this._rx, other._rx, eps) &&
|
|
113
|
+
Precision.equal(this._ry, other._ry, eps) &&
|
|
114
|
+
Precision.equal(this._rotation, other._rotation, eps) &&
|
|
115
|
+
Precision.equal(this.startAngle, other.startAngle, eps) &&
|
|
116
|
+
Precision.equal(this.endAngle, other.endAngle, eps);
|
|
117
|
+
}
|
|
118
|
+
clone() {
|
|
119
|
+
return new EllipseArc2_1(this._center, this._rx, this._ry, this._rotation, this.startAngle, this.endAngle, this._clockwise);
|
|
120
|
+
}
|
|
121
|
+
dump() {
|
|
122
|
+
return {
|
|
123
|
+
type: EllipseArc2_1.type,
|
|
124
|
+
center: { x: this._center.x, y: this._center.y },
|
|
125
|
+
rx: this._rx,
|
|
126
|
+
ry: this._ry,
|
|
127
|
+
rotation: this._rotation,
|
|
128
|
+
startAngle: this.startAngle,
|
|
129
|
+
endAngle: this.endAngle,
|
|
130
|
+
clockwise: this._clockwise,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
static load(data) {
|
|
134
|
+
return new EllipseArc2_1(new Vec2(data.center.x, data.center.y), data.rx, data.ry, data.rotation, data.startAngle, data.endAngle, data.clockwise);
|
|
135
|
+
}
|
|
136
|
+
paramToAngle(u) {
|
|
137
|
+
const uu = this.normalizeParamForEval(u);
|
|
138
|
+
if (!this._clockwise)
|
|
139
|
+
return uu;
|
|
140
|
+
return this._range.start - (uu - this._range.start);
|
|
141
|
+
}
|
|
142
|
+
angleToParam(theta) {
|
|
143
|
+
const range = this._range;
|
|
144
|
+
if (!this._clockwise) {
|
|
145
|
+
return range.normalizeInPeriod(theta, range.start);
|
|
146
|
+
}
|
|
147
|
+
const reflected = 2 * range.start - theta;
|
|
148
|
+
return range.normalizeInPeriod(reflected, range.start);
|
|
149
|
+
}
|
|
150
|
+
angleDerivativeSign() {
|
|
151
|
+
return this._clockwise ? -1 : 1;
|
|
152
|
+
}
|
|
153
|
+
resetAngles(startAngle, endAngle, clockwise) {
|
|
154
|
+
const s = this.normalizeAngle(startAngle);
|
|
155
|
+
const startEqEnd = Precision.equal(startAngle, endAngle, Precision.CURVE_PARAM_EPS);
|
|
156
|
+
let sweep = 0;
|
|
157
|
+
if (!startEqEnd) {
|
|
158
|
+
const raw = clockwise ? (startAngle - endAngle) : (endAngle - startAngle);
|
|
159
|
+
sweep = this.positiveMod(raw);
|
|
160
|
+
if (Precision.equal(sweep, 0, Precision.CURVE_PARAM_EPS)) {
|
|
161
|
+
sweep = MathConst.PI2;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
this._clockwise = clockwise;
|
|
165
|
+
this.setRange(new PeriodInterval(s, s + sweep, MathConst.PI2));
|
|
166
|
+
}
|
|
167
|
+
normalizeAngle(a) {
|
|
168
|
+
const r = a % MathConst.PI2;
|
|
169
|
+
return r < 0 ? r + MathConst.PI2 : r;
|
|
170
|
+
}
|
|
171
|
+
positiveMod(x) {
|
|
172
|
+
const r = x % MathConst.PI2;
|
|
173
|
+
return r < 0 ? r + MathConst.PI2 : r;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
EllipseArc2.type = EN_GEO_TYPE.EllipseArc2;
|
|
177
|
+
EllipseArc2 = EllipseArc2_1 = __decorate([
|
|
178
|
+
RegisterGeom
|
|
179
|
+
/**
|
|
180
|
+
* 二维椭圆弧曲线。
|
|
181
|
+
* 内部参数域统一为递增区间 `[s, s + sweep]`,方向由 `clockwise` 表示。
|
|
182
|
+
*/
|
|
183
|
+
], EllipseArc2);
|
|
184
|
+
export { EllipseArc2 };
|