@vesium/geometry 1.0.1-beta.54
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 +62 -0
- package/dist/index.cjs +1278 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +378 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +378 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +1281 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.iife.min.js +2 -0
- package/dist/index.iife.min.js.map +1 -0
- package/dist/index.min.cjs +2 -0
- package/dist/index.min.cjs.map +1 -0
- package/dist/index.min.mjs +2 -0
- package/dist/index.min.mjs.map +1 -0
- package/dist/index.mjs +1226 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1278 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/helper.ts
|
|
3
|
+
const FITTING_COUNT = 100;
|
|
4
|
+
const HALF_PI = Math.PI / 2;
|
|
5
|
+
const ZERO_TOLERANCE = 1e-4;
|
|
6
|
+
const TWO_PI = Math.PI * 2;
|
|
7
|
+
/**
|
|
8
|
+
* 计算两个坐标之间的距离
|
|
9
|
+
* @param coord1
|
|
10
|
+
* @param coord2
|
|
11
|
+
*/
|
|
12
|
+
function mathDistance(coord1, coord2) {
|
|
13
|
+
return Math.hypot(coord1[0] - coord2[0], coord1[1] - coord2[1]);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 计算点集合的总距离
|
|
17
|
+
* @param points
|
|
18
|
+
*/
|
|
19
|
+
function wholeDistance(points) {
|
|
20
|
+
let distance = 0;
|
|
21
|
+
if (points && Array.isArray(points) && points.length > 0) points.forEach((item, index) => {
|
|
22
|
+
if (index < points.length - 1) distance += mathDistance(item, points[index + 1]);
|
|
23
|
+
});
|
|
24
|
+
return distance;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 获取基础长度
|
|
28
|
+
* @param points
|
|
29
|
+
*/
|
|
30
|
+
const getBaseLength = (points) => wholeDistance(points) ** .99;
|
|
31
|
+
/**
|
|
32
|
+
* 求取两个坐标的中间坐标
|
|
33
|
+
* @param coord1
|
|
34
|
+
* @param coord2
|
|
35
|
+
*/
|
|
36
|
+
function mid(coord1, coord2) {
|
|
37
|
+
return [(coord1[0] + coord2[0]) / 2, (coord1[1] + coord2[1]) / 2];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 通过三个点确定一个圆的中心点
|
|
41
|
+
* @param coord1
|
|
42
|
+
* @param coord2
|
|
43
|
+
* @param coord3
|
|
44
|
+
*/
|
|
45
|
+
function getCircleCenterOfThreeCoords(coord1, coord2, coord3) {
|
|
46
|
+
const coordA = [(coord1[0] + coord2[0]) / 2, (coord1[1] + coord2[1]) / 2];
|
|
47
|
+
const coordB = [coordA[0] - coord1[1] + coord2[1], coordA[1] + coord1[0] - coord2[0]];
|
|
48
|
+
const coordC = [(coord1[0] + coord3[0]) / 2, (coord1[1] + coord3[1]) / 2];
|
|
49
|
+
return getIntersectCoord(coordA, coordB, coordC, [coordC[0] - coord1[1] + coord3[1], coordC[1] + coord1[0] - coord3[0]]);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 获取交集的点
|
|
53
|
+
* @param coordA
|
|
54
|
+
* @param coordB
|
|
55
|
+
* @param coordC
|
|
56
|
+
* @param coordD
|
|
57
|
+
*/
|
|
58
|
+
function getIntersectCoord(coordA, coordB, coordC, coordD) {
|
|
59
|
+
if (coordA[1] === coordB[1]) return [(coordD[0] - coordC[0]) / (coordD[1] - coordC[1]) * (coordA[1] - coordC[1]) + coordC[0], coordA[1]];
|
|
60
|
+
if (coordC[1] === coordD[1]) return [(coordB[0] - coordA[0]) / (coordB[1] - coordA[1]) * (coordC[1] - coordA[1]) + coordA[0], coordC[1]];
|
|
61
|
+
const e = (coordB[0] - coordA[0]) / (coordB[1] - coordA[1]);
|
|
62
|
+
const f = (coordD[0] - coordC[0]) / (coordD[1] - coordC[1]);
|
|
63
|
+
const y = (e * coordA[1] - coordA[0] - f * coordC[1] + coordC[0]) / (e - f);
|
|
64
|
+
return [e * y - e * coordA[1] + coordA[0], y];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 获取方位角(地平经度)
|
|
68
|
+
* @param startCoord
|
|
69
|
+
* @param endCoord
|
|
70
|
+
*/
|
|
71
|
+
function getAzimuth(startCoord, endCoord) {
|
|
72
|
+
let azimuth = 0;
|
|
73
|
+
const angle = Math.asin(Math.abs(endCoord[1] - startCoord[1]) / mathDistance(startCoord, endCoord));
|
|
74
|
+
if (endCoord[1] >= startCoord[1] && endCoord[0] >= startCoord[0]) azimuth = angle + Math.PI;
|
|
75
|
+
else if (endCoord[1] >= startCoord[1] && endCoord[0] < startCoord[0]) azimuth = Math.PI * 2 - angle;
|
|
76
|
+
else if (endCoord[1] < startCoord[1] && endCoord[0] < startCoord[0]) azimuth = angle;
|
|
77
|
+
else if (endCoord[1] < startCoord[1] && endCoord[0] >= startCoord[0]) azimuth = Math.PI - angle;
|
|
78
|
+
return azimuth;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 通过三个点获取方位角
|
|
82
|
+
* @param coordA
|
|
83
|
+
* @param coordB
|
|
84
|
+
* @param coordC
|
|
85
|
+
*/
|
|
86
|
+
function getAngleOfThreeCoords(coordA, coordB, coordC) {
|
|
87
|
+
const angle = getAzimuth(coordB, coordA) - getAzimuth(coordB, coordC);
|
|
88
|
+
return angle < 0 ? angle + Math.PI * 2 : angle;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 判断是否是顺时针
|
|
92
|
+
* @param coord1
|
|
93
|
+
* @param coord2
|
|
94
|
+
* @param coord3
|
|
95
|
+
*/
|
|
96
|
+
function isClockWise(coord1, coord2, coord3) {
|
|
97
|
+
return (coord3[1] - coord1[1]) * (coord2[0] - coord1[0]) > (coord2[1] - coord1[1]) * (coord3[0] - coord1[0]);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 获取线上的点
|
|
101
|
+
* @param t
|
|
102
|
+
* @param startCoord
|
|
103
|
+
* @param endCoord
|
|
104
|
+
*/
|
|
105
|
+
function getCoordOnLine(t, startCoord, endCoord) {
|
|
106
|
+
return [startCoord[0] + t * (endCoord[0] - startCoord[0]), startCoord[1] + t * (endCoord[1] - startCoord[1])];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 获取立方值
|
|
110
|
+
*/
|
|
111
|
+
function getCubicValue(t, startCoord, coord1, coord2, endCoord) {
|
|
112
|
+
t = Math.max(Math.min(t, 1), 0);
|
|
113
|
+
const [tp, t2] = [1 - t, t * t];
|
|
114
|
+
const t3 = t2 * t;
|
|
115
|
+
const tp2 = tp * tp;
|
|
116
|
+
const tp3 = tp2 * tp;
|
|
117
|
+
return [tp3 * startCoord[0] + 3 * tp2 * t * coord1[0] + 3 * tp * t2 * coord2[0] + t3 * endCoord[0], tp3 * startCoord[1] + 3 * tp2 * t * coord1[1] + 3 * tp * t2 * coord2[1] + t3 * endCoord[1]];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 根据起止点和旋转方向求取第三个点
|
|
121
|
+
* @param startCoord
|
|
122
|
+
* @param endCoord
|
|
123
|
+
* @param angle
|
|
124
|
+
* @param distance
|
|
125
|
+
* @param clockWise
|
|
126
|
+
*/
|
|
127
|
+
function getThirdCoord(startCoord, endCoord, angle, distance, clockWise) {
|
|
128
|
+
const azimuth = getAzimuth(startCoord, endCoord);
|
|
129
|
+
const alpha = clockWise ? azimuth + angle : azimuth - angle;
|
|
130
|
+
const dx = distance * Math.cos(alpha);
|
|
131
|
+
const dy = distance * Math.sin(alpha);
|
|
132
|
+
return [endCoord[0] + dx, endCoord[1] + dy];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 插值弓形线段点
|
|
136
|
+
* @param center
|
|
137
|
+
* @param radius
|
|
138
|
+
* @param startAngle
|
|
139
|
+
* @param endAngle
|
|
140
|
+
*/
|
|
141
|
+
function getArcCoords(center, radius, startAngle, endAngle) {
|
|
142
|
+
let [x, y, coords, angleDiff] = [
|
|
143
|
+
0,
|
|
144
|
+
0,
|
|
145
|
+
[],
|
|
146
|
+
endAngle - startAngle
|
|
147
|
+
];
|
|
148
|
+
angleDiff = angleDiff < 0 ? angleDiff + Math.PI * 2 : angleDiff;
|
|
149
|
+
for (let i = 0; i <= 100; i++) {
|
|
150
|
+
const angle = startAngle + angleDiff * i / 100;
|
|
151
|
+
x = center[0] + radius * Math.cos(angle);
|
|
152
|
+
y = center[1] + radius * Math.sin(angle);
|
|
153
|
+
coords.push([x, y]);
|
|
154
|
+
}
|
|
155
|
+
return coords;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* getBisectorNormals
|
|
159
|
+
* @param t
|
|
160
|
+
* @param coord1
|
|
161
|
+
* @param coord2
|
|
162
|
+
* @param coord3
|
|
163
|
+
*/
|
|
164
|
+
function getBisectorNormals(t, coord1, coord2, coord3) {
|
|
165
|
+
const normal = getNormal(coord1, coord2, coord3);
|
|
166
|
+
let [bisectorNormalRight, bisectorNormalLeft, dt, x, y] = [
|
|
167
|
+
[0, 0],
|
|
168
|
+
[0, 0],
|
|
169
|
+
0,
|
|
170
|
+
0,
|
|
171
|
+
0
|
|
172
|
+
];
|
|
173
|
+
const dist = Math.hypot(normal[0], normal[1]);
|
|
174
|
+
const uX = normal[0] / dist;
|
|
175
|
+
const uY = normal[1] / dist;
|
|
176
|
+
const d1 = mathDistance(coord1, coord2);
|
|
177
|
+
const d2 = mathDistance(coord2, coord3);
|
|
178
|
+
if (dist > ZERO_TOLERANCE) if (isClockWise(coord1, coord2, coord3)) {
|
|
179
|
+
dt = t * d1;
|
|
180
|
+
x = coord2[0] - dt * uY;
|
|
181
|
+
y = coord2[1] + dt * uX;
|
|
182
|
+
bisectorNormalRight = [x, y];
|
|
183
|
+
dt = t * d2;
|
|
184
|
+
x = coord2[0] + dt * uY;
|
|
185
|
+
y = coord2[1] - dt * uX;
|
|
186
|
+
bisectorNormalLeft = [x, y];
|
|
187
|
+
} else {
|
|
188
|
+
dt = t * d1;
|
|
189
|
+
x = coord2[0] + dt * uY;
|
|
190
|
+
y = coord2[1] - dt * uX;
|
|
191
|
+
bisectorNormalRight = [x, y];
|
|
192
|
+
dt = t * d2;
|
|
193
|
+
x = coord2[0] - dt * uY;
|
|
194
|
+
y = coord2[1] + dt * uX;
|
|
195
|
+
bisectorNormalLeft = [x, y];
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
x = coord2[0] + t * (coord1[0] - coord2[0]);
|
|
199
|
+
y = coord2[1] + t * (coord1[1] - coord2[1]);
|
|
200
|
+
bisectorNormalRight = [x, y];
|
|
201
|
+
x = coord2[0] + t * (coord3[0] - coord2[0]);
|
|
202
|
+
y = coord2[1] + t * (coord3[1] - coord2[1]);
|
|
203
|
+
bisectorNormalLeft = [x, y];
|
|
204
|
+
}
|
|
205
|
+
return [bisectorNormalRight, bisectorNormalLeft];
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* 获取默认三点的内切圆
|
|
209
|
+
* @param coord1
|
|
210
|
+
* @param coord2
|
|
211
|
+
* @param coord3
|
|
212
|
+
*/
|
|
213
|
+
function getNormal(coord1, coord2, coord3) {
|
|
214
|
+
let dX1 = coord1[0] - coord2[0];
|
|
215
|
+
let dY1 = coord1[1] - coord2[1];
|
|
216
|
+
const d1 = Math.hypot(dX1, dY1);
|
|
217
|
+
dX1 /= d1;
|
|
218
|
+
dY1 /= d1;
|
|
219
|
+
let dX2 = coord3[0] - coord2[0];
|
|
220
|
+
let dY2 = coord3[1] - coord2[1];
|
|
221
|
+
const d2 = Math.hypot(dX2, dY2);
|
|
222
|
+
dX2 /= d2;
|
|
223
|
+
dY2 /= d2;
|
|
224
|
+
return [dX1 + dX2, dY1 + dY2];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 获取左边控制点
|
|
228
|
+
* @param controlCoords
|
|
229
|
+
* @param t
|
|
230
|
+
*/
|
|
231
|
+
function getLeftMostControlCoord(controlCoords, t) {
|
|
232
|
+
let [coord1, coord2, coord3, controlX, controlY] = [
|
|
233
|
+
controlCoords[0],
|
|
234
|
+
controlCoords[1],
|
|
235
|
+
controlCoords[2],
|
|
236
|
+
0,
|
|
237
|
+
0
|
|
238
|
+
];
|
|
239
|
+
const normalRight = getBisectorNormals(0, coord1, coord2, coord3)[0];
|
|
240
|
+
const normal = getNormal(coord1, coord2, coord3);
|
|
241
|
+
if (Math.hypot(normal[0], normal[1]) > ZERO_TOLERANCE) {
|
|
242
|
+
const midCoord = mid(coord1, coord2);
|
|
243
|
+
const pX = coord1[0] - midCoord[0];
|
|
244
|
+
const pY = coord1[1] - midCoord[1];
|
|
245
|
+
const n = 2 / mathDistance(coord1, coord2);
|
|
246
|
+
const nX = -n * pY;
|
|
247
|
+
const nY = n * pX;
|
|
248
|
+
const a11 = nX * nX - nY * nY;
|
|
249
|
+
const a12 = 2 * nX * nY;
|
|
250
|
+
const a22 = nY * nY - nX * nX;
|
|
251
|
+
const dX = normalRight[0] - midCoord[0];
|
|
252
|
+
const dY = normalRight[1] - midCoord[1];
|
|
253
|
+
controlX = midCoord[0] + a11 * dX + a12 * dY;
|
|
254
|
+
controlY = midCoord[1] + a12 * dX + a22 * dY;
|
|
255
|
+
} else {
|
|
256
|
+
controlX = coord1[0] + t * (coord2[0] - coord1[0]);
|
|
257
|
+
controlY = coord1[1] + t * (coord2[1] - coord1[1]);
|
|
258
|
+
}
|
|
259
|
+
return [controlX, controlY];
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* 获取右边控制点
|
|
263
|
+
* @param controlCoords
|
|
264
|
+
* @param t
|
|
265
|
+
*/
|
|
266
|
+
function getRightMostControlCoord(controlCoords, t) {
|
|
267
|
+
const coordlength = controlCoords.length;
|
|
268
|
+
const coord1 = controlCoords[coordlength - 3];
|
|
269
|
+
const coord2 = controlCoords[coordlength - 2];
|
|
270
|
+
const coord3 = controlCoords[coordlength - 1];
|
|
271
|
+
const normalLeft = getBisectorNormals(0, coord1, coord2, coord3)[1];
|
|
272
|
+
const normal = getNormal(coord1, coord2, coord3);
|
|
273
|
+
const dist = Math.hypot(normal[0], normal[1]);
|
|
274
|
+
let [controlX, controlY] = [0, 0];
|
|
275
|
+
if (dist > ZERO_TOLERANCE) {
|
|
276
|
+
const midCoord = mid(coord2, coord3);
|
|
277
|
+
const pX = coord3[0] - midCoord[0];
|
|
278
|
+
const pY = coord3[1] - midCoord[1];
|
|
279
|
+
const n = 2 / mathDistance(coord2, coord3);
|
|
280
|
+
const nX = -n * pY;
|
|
281
|
+
const nY = n * pX;
|
|
282
|
+
const a11 = nX * nX - nY * nY;
|
|
283
|
+
const a12 = 2 * nX * nY;
|
|
284
|
+
const a22 = nY * nY - nX * nX;
|
|
285
|
+
const dX = normalLeft[0] - midCoord[0];
|
|
286
|
+
const dY = normalLeft[1] - midCoord[1];
|
|
287
|
+
controlX = midCoord[0] + a11 * dX + a12 * dY;
|
|
288
|
+
controlY = midCoord[1] + a12 * dX + a22 * dY;
|
|
289
|
+
} else {
|
|
290
|
+
controlX = coord3[0] + t * (coord2[0] - coord3[0]);
|
|
291
|
+
controlY = coord3[1] + t * (coord2[1] - coord3[1]);
|
|
292
|
+
}
|
|
293
|
+
return [controlX, controlY];
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* 插值曲线点
|
|
297
|
+
* @param t
|
|
298
|
+
* @param controlCoords
|
|
299
|
+
*/
|
|
300
|
+
function getCurveCoords(t, controlCoords) {
|
|
301
|
+
let normals = [getLeftMostControlCoord(controlCoords, t)];
|
|
302
|
+
const coords = [];
|
|
303
|
+
let coord1, coord2, coord3;
|
|
304
|
+
for (let i = 0; i < controlCoords.length - 2; i++) {
|
|
305
|
+
[coord1, coord2, coord3] = [
|
|
306
|
+
controlCoords[i],
|
|
307
|
+
controlCoords[i + 1],
|
|
308
|
+
controlCoords[i + 2]
|
|
309
|
+
];
|
|
310
|
+
const normalCoords = getBisectorNormals(t, coord1, coord2, coord3);
|
|
311
|
+
normals = normals.concat(normalCoords);
|
|
312
|
+
}
|
|
313
|
+
const rightControl = getRightMostControlCoord(controlCoords, t);
|
|
314
|
+
if (rightControl) normals.push(rightControl);
|
|
315
|
+
for (let i = 0; i < controlCoords.length - 1; i++) {
|
|
316
|
+
coord1 = controlCoords[i];
|
|
317
|
+
coord2 = controlCoords[i + 1];
|
|
318
|
+
coords.push(coord1);
|
|
319
|
+
for (let j = 0; j < FITTING_COUNT; j++) {
|
|
320
|
+
const coord = getCubicValue(j / FITTING_COUNT, coord1, normals[i * 2], normals[i * 2 + 1], coord2);
|
|
321
|
+
coords.push(coord);
|
|
322
|
+
}
|
|
323
|
+
coords.push(coord2);
|
|
324
|
+
}
|
|
325
|
+
return coords;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* 贝塞尔曲线
|
|
329
|
+
* @param points
|
|
330
|
+
*/
|
|
331
|
+
function getBezierCoords(points) {
|
|
332
|
+
if (points.length <= 2) return points;
|
|
333
|
+
const bezierCoords = [];
|
|
334
|
+
const n = points.length - 1;
|
|
335
|
+
for (let t = 0; t <= 1; t += .01) {
|
|
336
|
+
let [x, y] = [0, 0];
|
|
337
|
+
for (let index = 0; index <= n; index++) {
|
|
338
|
+
const factor = getBinomialFactor(n, index);
|
|
339
|
+
const a = t ** index;
|
|
340
|
+
const b = (1 - t) ** (n - index);
|
|
341
|
+
x += factor * a * b * points[index][0];
|
|
342
|
+
y += factor * a * b * points[index][1];
|
|
343
|
+
}
|
|
344
|
+
bezierCoords.push([x, y]);
|
|
345
|
+
}
|
|
346
|
+
bezierCoords.push(points[n]);
|
|
347
|
+
return bezierCoords;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 获取阶乘数据
|
|
351
|
+
* @param n
|
|
352
|
+
*/
|
|
353
|
+
function getFactorial(n) {
|
|
354
|
+
let result = 1;
|
|
355
|
+
switch (true) {
|
|
356
|
+
case n <= 1:
|
|
357
|
+
result = 1;
|
|
358
|
+
break;
|
|
359
|
+
case n === 2:
|
|
360
|
+
result = 2;
|
|
361
|
+
break;
|
|
362
|
+
case n === 3:
|
|
363
|
+
result = 6;
|
|
364
|
+
break;
|
|
365
|
+
case n === 24:
|
|
366
|
+
result = 24;
|
|
367
|
+
break;
|
|
368
|
+
case n === 5:
|
|
369
|
+
result = 120;
|
|
370
|
+
break;
|
|
371
|
+
default:
|
|
372
|
+
for (let i = 1; i <= n; i++) result *= i;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* 获取二项分布
|
|
379
|
+
* @param n
|
|
380
|
+
* @param index
|
|
381
|
+
*/
|
|
382
|
+
function getBinomialFactor(n, index) {
|
|
383
|
+
return getFactorial(n) / (getFactorial(index) * getFactorial(n - index));
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* 插值线性点
|
|
387
|
+
* @param points
|
|
388
|
+
*/
|
|
389
|
+
function getQBSplineCoords(points) {
|
|
390
|
+
if (points.length <= 2) return points;
|
|
391
|
+
const [n, bSplineCoords] = [2, []];
|
|
392
|
+
const m = points.length - n - 1;
|
|
393
|
+
bSplineCoords.push(points[0]);
|
|
394
|
+
for (let i = 0; i <= m; i++) for (let t = 0; t <= 1; t += .05) {
|
|
395
|
+
let [x, y] = [0, 0];
|
|
396
|
+
for (let k = 0; k <= n; k++) {
|
|
397
|
+
const factor = getQuadricBSplineFactor(k, t);
|
|
398
|
+
x += factor * points[i + k][0];
|
|
399
|
+
y += factor * points[i + k][1];
|
|
400
|
+
}
|
|
401
|
+
bSplineCoords.push([x, y]);
|
|
402
|
+
}
|
|
403
|
+
bSplineCoords.push(points.at(-1));
|
|
404
|
+
return bSplineCoords;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* 得到二次线性因子
|
|
408
|
+
* @param k
|
|
409
|
+
* @param t
|
|
410
|
+
*/
|
|
411
|
+
function getQuadricBSplineFactor(k, t) {
|
|
412
|
+
let res = 0;
|
|
413
|
+
if (k === 0) res = (t - 1) ** 2 / 2;
|
|
414
|
+
else if (k === 1) res = (-2 * t ** 2 + 2 * t + 1) / 2;
|
|
415
|
+
else if (k === 2) res = t ** 2 / 2;
|
|
416
|
+
return res;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/arc.ts
|
|
421
|
+
/**
|
|
422
|
+
* 标绘画弓形算法,继承线要素相关方法和属性
|
|
423
|
+
*/
|
|
424
|
+
function arc(coords) {
|
|
425
|
+
if (coords.length <= 2) throw new Error("coords.length must >= 3");
|
|
426
|
+
else {
|
|
427
|
+
let [coord1, coord2, coord3, startAngle, endAngle] = [
|
|
428
|
+
coords[0],
|
|
429
|
+
coords[1],
|
|
430
|
+
coords[2],
|
|
431
|
+
0,
|
|
432
|
+
0
|
|
433
|
+
];
|
|
434
|
+
const center = getCircleCenterOfThreeCoords(coord1, coord2, coord3);
|
|
435
|
+
const radius = mathDistance(coord1, center);
|
|
436
|
+
const angle1 = getAzimuth(coord1, center);
|
|
437
|
+
const angle2 = getAzimuth(coord2, center);
|
|
438
|
+
if (isClockWise(coord1, coord2, coord3)) {
|
|
439
|
+
startAngle = angle2;
|
|
440
|
+
endAngle = angle1;
|
|
441
|
+
} else {
|
|
442
|
+
startAngle = angle1;
|
|
443
|
+
endAngle = angle2;
|
|
444
|
+
}
|
|
445
|
+
return getArcCoords(center, radius, startAngle, endAngle);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
//#endregion
|
|
450
|
+
//#region src/arrowAttackDirection.ts
|
|
451
|
+
/**
|
|
452
|
+
* 尖曲箭头
|
|
453
|
+
*/
|
|
454
|
+
function arrowAttackDirection(coords, options = {}) {
|
|
455
|
+
if (coords.length < 3) throw new Error("coords.length must >= 3");
|
|
456
|
+
else {
|
|
457
|
+
let [tailLeft, tailRight] = [coords[0], coords[1]];
|
|
458
|
+
if (isClockWise(coords[0], coords[1], coords[2])) {
|
|
459
|
+
tailLeft = coords[1];
|
|
460
|
+
tailRight = coords[0];
|
|
461
|
+
}
|
|
462
|
+
const boneCoords = [mid(tailLeft, tailRight)].concat(coords.slice(2));
|
|
463
|
+
const headCoords = getArrowHeadCoords(boneCoords, {
|
|
464
|
+
tailLeft,
|
|
465
|
+
tailRight,
|
|
466
|
+
...options
|
|
467
|
+
});
|
|
468
|
+
if (headCoords && headCoords.length > 4) {
|
|
469
|
+
const [neckLeft, neckRight] = [headCoords[0], headCoords[4]];
|
|
470
|
+
const bodyCoords = getArrowBodyCoords(boneCoords, neckLeft, neckRight, mathDistance(tailLeft, tailRight) / getBaseLength(boneCoords));
|
|
471
|
+
const coordlength = bodyCoords.length;
|
|
472
|
+
let leftCoords = [tailLeft].concat(bodyCoords.slice(0, coordlength / 2));
|
|
473
|
+
leftCoords.push(neckLeft);
|
|
474
|
+
let rightCoords = [tailRight].concat(bodyCoords.slice(coordlength / 2, coordlength));
|
|
475
|
+
rightCoords.push(neckRight);
|
|
476
|
+
leftCoords = getQBSplineCoords(leftCoords);
|
|
477
|
+
rightCoords = getQBSplineCoords(rightCoords);
|
|
478
|
+
return leftCoords.concat(headCoords, rightCoords.reverse());
|
|
479
|
+
} else return [];
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* 插值箭形上的点
|
|
484
|
+
* @param coord1
|
|
485
|
+
* @param coord2
|
|
486
|
+
* @param coord3
|
|
487
|
+
* @param clockWise
|
|
488
|
+
*/
|
|
489
|
+
function getArrowCoords(coord1, coord2, coord3, clockWise, options = {}) {
|
|
490
|
+
const midCoord = mid(coord1, coord2);
|
|
491
|
+
const len = mathDistance(midCoord, coord3);
|
|
492
|
+
let midCoord1 = getThirdCoord(coord3, midCoord, 0, len * .3, true);
|
|
493
|
+
let midCoord2 = getThirdCoord(coord3, midCoord, 0, len * .5, true);
|
|
494
|
+
midCoord1 = getThirdCoord(midCoord, midCoord1, HALF_PI, len / 5, clockWise);
|
|
495
|
+
midCoord2 = getThirdCoord(midCoord, midCoord2, HALF_PI, len / 4, clockWise);
|
|
496
|
+
const points = [
|
|
497
|
+
midCoord,
|
|
498
|
+
midCoord1,
|
|
499
|
+
midCoord2,
|
|
500
|
+
coord3
|
|
501
|
+
];
|
|
502
|
+
const arrowCoords = getArrowHeadCoords(points, options);
|
|
503
|
+
if (arrowCoords && Array.isArray(arrowCoords) && arrowCoords.length > 0) {
|
|
504
|
+
const [neckLeftCoord, neckRightCoord] = [arrowCoords[0], arrowCoords[4]];
|
|
505
|
+
const bodyCoords = getArrowBodyCoords(points, neckLeftCoord, neckRightCoord, mathDistance(coord1, coord2) / getBaseLength(points) / 2);
|
|
506
|
+
if (bodyCoords) {
|
|
507
|
+
const n = bodyCoords.length;
|
|
508
|
+
let lCoords = bodyCoords.slice(0, n / 2);
|
|
509
|
+
let rCoords = bodyCoords.slice(n / 2, n);
|
|
510
|
+
lCoords.push(neckLeftCoord);
|
|
511
|
+
rCoords.push(neckRightCoord);
|
|
512
|
+
lCoords = lCoords.reverse();
|
|
513
|
+
lCoords.push(coord2);
|
|
514
|
+
rCoords = rCoords.reverse();
|
|
515
|
+
rCoords.push(coord1);
|
|
516
|
+
return lCoords.reverse().concat(arrowCoords, rCoords);
|
|
517
|
+
}
|
|
518
|
+
} else throw new Error("插值出错");
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* 插值头部点
|
|
522
|
+
*/
|
|
523
|
+
function getArrowHeadCoords(points, options) {
|
|
524
|
+
const { tailLeft, tailRight, headHeightFactor = .18, headWidthFactor = .3, neckHeightFactor = .85, neckWidthFactor = .15, headTailFactor = .8 } = options;
|
|
525
|
+
let len = getBaseLength(points);
|
|
526
|
+
let headHeight = len * headHeightFactor;
|
|
527
|
+
const headCoord = points.at(-1);
|
|
528
|
+
len = mathDistance(headCoord, points.at(-2));
|
|
529
|
+
let tailWidth = 0;
|
|
530
|
+
if (tailLeft && tailRight) tailWidth = mathDistance(tailLeft, tailRight);
|
|
531
|
+
if (headHeight > tailWidth * headTailFactor) headHeight = tailWidth * headTailFactor;
|
|
532
|
+
const headWidth = headHeight * headWidthFactor;
|
|
533
|
+
const neckWidth = headHeight * neckWidthFactor;
|
|
534
|
+
headHeight = Math.min(headHeight, len);
|
|
535
|
+
const neckHeight = headHeight * neckHeightFactor;
|
|
536
|
+
const headEndCoord = getThirdCoord(points.at(-2), headCoord, 0, headHeight, true);
|
|
537
|
+
const neckEndCoord = getThirdCoord(points.at(-2), headCoord, 0, neckHeight, true);
|
|
538
|
+
const headLeft = getThirdCoord(headCoord, headEndCoord, HALF_PI, headWidth, false);
|
|
539
|
+
const headRight = getThirdCoord(headCoord, headEndCoord, HALF_PI, headWidth, true);
|
|
540
|
+
return [
|
|
541
|
+
getThirdCoord(headCoord, neckEndCoord, HALF_PI, neckWidth, false),
|
|
542
|
+
headLeft,
|
|
543
|
+
headCoord,
|
|
544
|
+
headRight,
|
|
545
|
+
getThirdCoord(headCoord, neckEndCoord, HALF_PI, neckWidth, true)
|
|
546
|
+
];
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* 插值面部分数据
|
|
550
|
+
* @param points
|
|
551
|
+
* @param neckLeft
|
|
552
|
+
* @param neckRight
|
|
553
|
+
* @param tailWidthFactor
|
|
554
|
+
*/
|
|
555
|
+
function getArrowBodyCoords(points, neckLeft, neckRight, tailWidthFactor) {
|
|
556
|
+
const allLen = wholeDistance(points);
|
|
557
|
+
const tailWidth = getBaseLength(points) * tailWidthFactor;
|
|
558
|
+
const widthDif = (tailWidth - mathDistance(neckLeft, neckRight)) / 2;
|
|
559
|
+
let tempLen = 0;
|
|
560
|
+
const leftBodyCoords = [];
|
|
561
|
+
const rightBodyCoords = [];
|
|
562
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
563
|
+
const angle = getAngleOfThreeCoords(points[i - 1], points[i], points[i + 1]) / 2;
|
|
564
|
+
tempLen += mathDistance(points[i - 1], points[i]);
|
|
565
|
+
const w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle);
|
|
566
|
+
const left = getThirdCoord(points[i - 1], points[i], Math.PI - angle, w, true);
|
|
567
|
+
const right = getThirdCoord(points[i - 1], points[i], angle, w, false);
|
|
568
|
+
leftBodyCoords.push(left);
|
|
569
|
+
rightBodyCoords.push(right);
|
|
570
|
+
}
|
|
571
|
+
return leftBodyCoords.concat(rightBodyCoords);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* 获取对称点
|
|
575
|
+
* @param lineCoord1
|
|
576
|
+
* @param lineCoord2
|
|
577
|
+
* @param coord
|
|
578
|
+
*/
|
|
579
|
+
function getTempCoord4(lineCoord1, lineCoord2, coord) {
|
|
580
|
+
const midCoord = mid(lineCoord1, lineCoord2);
|
|
581
|
+
const len = mathDistance(midCoord, coord);
|
|
582
|
+
const angle = getAngleOfThreeCoords(lineCoord1, midCoord, coord);
|
|
583
|
+
let symCoord;
|
|
584
|
+
let distance1 = 0;
|
|
585
|
+
let distance2 = 0;
|
|
586
|
+
let midCoord2;
|
|
587
|
+
if (angle < HALF_PI) {
|
|
588
|
+
distance1 = len * Math.sin(angle);
|
|
589
|
+
distance2 = len * Math.cos(angle);
|
|
590
|
+
midCoord2 = getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, false);
|
|
591
|
+
symCoord = getThirdCoord(midCoord, midCoord2, HALF_PI, distance2, true);
|
|
592
|
+
} else if (angle >= HALF_PI && angle < Math.PI) {
|
|
593
|
+
distance1 = len * Math.sin(Math.PI - angle);
|
|
594
|
+
distance2 = len * Math.cos(Math.PI - angle);
|
|
595
|
+
midCoord2 = getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, false);
|
|
596
|
+
symCoord = getThirdCoord(midCoord, midCoord2, HALF_PI, distance2, false);
|
|
597
|
+
} else if (angle >= Math.PI && angle < Math.PI * 1.5) {
|
|
598
|
+
distance1 = len * Math.sin(angle - Math.PI);
|
|
599
|
+
distance2 = len * Math.cos(angle - Math.PI);
|
|
600
|
+
midCoord2 = getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, true);
|
|
601
|
+
symCoord = getThirdCoord(midCoord, midCoord2, HALF_PI, distance2, true);
|
|
602
|
+
} else {
|
|
603
|
+
distance1 = len * Math.sin(Math.PI * 2 - angle);
|
|
604
|
+
distance2 = len * Math.cos(Math.PI * 2 - angle);
|
|
605
|
+
midCoord2 = getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, true);
|
|
606
|
+
symCoord = getThirdCoord(midCoord, midCoord2, HALF_PI, distance2, false);
|
|
607
|
+
}
|
|
608
|
+
return symCoord;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/arrowAttackDirectionTailed.ts
|
|
613
|
+
/**
|
|
614
|
+
* 燕尾尖曲箭头
|
|
615
|
+
*/
|
|
616
|
+
function arrowAttackDirectionTailed(coords, options = {}) {
|
|
617
|
+
const { headHeightFactor = .18, headWidthFactor = .3, neckHeightFactor = .85, neckWidthFactor = .15, tailWidthFactor = .1, swallowTailFactor = 1 } = options;
|
|
618
|
+
if (coords.length < 3) throw new Error("coords.length must >= 3");
|
|
619
|
+
let [tailLeft, tailRight] = [coords[0], coords[1]];
|
|
620
|
+
if (isClockWise(coords[0], coords[1], coords[2])) {
|
|
621
|
+
tailLeft = coords[1];
|
|
622
|
+
tailRight = coords[0];
|
|
623
|
+
}
|
|
624
|
+
const boneCoords = [mid(tailLeft, tailRight)].concat(coords.slice(2));
|
|
625
|
+
const headCoords = getArrowHeadCoords(boneCoords, {
|
|
626
|
+
tailLeft,
|
|
627
|
+
tailRight,
|
|
628
|
+
headHeightFactor,
|
|
629
|
+
headWidthFactor,
|
|
630
|
+
neckWidthFactor,
|
|
631
|
+
neckHeightFactor
|
|
632
|
+
});
|
|
633
|
+
if (headCoords && headCoords.length > 4) {
|
|
634
|
+
const [neckLeft, neckRight] = [headCoords[0], headCoords[4]];
|
|
635
|
+
const tailWidth = mathDistance(tailLeft, tailRight);
|
|
636
|
+
const allLen = getBaseLength(boneCoords);
|
|
637
|
+
const len = allLen * tailWidthFactor * swallowTailFactor;
|
|
638
|
+
const swallowTailCoord = getThirdCoord(boneCoords[1], boneCoords[0], 0, len, true);
|
|
639
|
+
const bodyCoords = getArrowBodyCoords(boneCoords, neckLeft, neckRight, tailWidth / allLen);
|
|
640
|
+
const coordlength = bodyCoords.length;
|
|
641
|
+
let leftCoords = [tailLeft].concat(bodyCoords.slice(0, coordlength / 2));
|
|
642
|
+
leftCoords.push(neckLeft);
|
|
643
|
+
let rightCoords = [tailRight].concat(bodyCoords.slice(coordlength / 2, coordlength));
|
|
644
|
+
rightCoords.push(neckRight);
|
|
645
|
+
leftCoords = getQBSplineCoords(leftCoords);
|
|
646
|
+
rightCoords = getQBSplineCoords(rightCoords);
|
|
647
|
+
return leftCoords.concat(headCoords, rightCoords.reverse(), [swallowTailCoord, leftCoords[0]]);
|
|
648
|
+
} else return [];
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/arrowClamped.ts
|
|
653
|
+
/**
|
|
654
|
+
* 钳击箭头 有效点位长度3,4,5
|
|
655
|
+
*/
|
|
656
|
+
function arrowClamped(coords) {
|
|
657
|
+
const options = {
|
|
658
|
+
headHeightFactor: .25,
|
|
659
|
+
headWidthFactor: .3,
|
|
660
|
+
neckHeightFactor: .85,
|
|
661
|
+
neckWidthFactor: .15
|
|
662
|
+
};
|
|
663
|
+
if (coords.length < 3) throw new Error(`coords.length must >= 3`);
|
|
664
|
+
const [coord1, coord2, coord3] = coords;
|
|
665
|
+
let tempCoord4, connCoord;
|
|
666
|
+
if (coords.length === 3) {
|
|
667
|
+
tempCoord4 = getTempCoord4$1(coord1, coord2, coord3);
|
|
668
|
+
connCoord = mid(coord1, coord2);
|
|
669
|
+
} else if (coords.length === 4) {
|
|
670
|
+
tempCoord4 = coords[3];
|
|
671
|
+
connCoord = mid(coord1, coord2);
|
|
672
|
+
} else {
|
|
673
|
+
tempCoord4 = coords[3];
|
|
674
|
+
connCoord = coords[4];
|
|
675
|
+
}
|
|
676
|
+
let leftArrowCoords;
|
|
677
|
+
let rightArrowCoords;
|
|
678
|
+
if (isClockWise(coord1, coord2, coord3)) {
|
|
679
|
+
leftArrowCoords = getArrowCoords$1(coord1, connCoord, tempCoord4, false, options);
|
|
680
|
+
rightArrowCoords = getArrowCoords$1(connCoord, coord2, coord3, true, options);
|
|
681
|
+
} else {
|
|
682
|
+
leftArrowCoords = getArrowCoords$1(coord2, connCoord, coord3, false, options);
|
|
683
|
+
rightArrowCoords = getArrowCoords$1(connCoord, coord1, tempCoord4, true, options);
|
|
684
|
+
}
|
|
685
|
+
const m = leftArrowCoords.length;
|
|
686
|
+
const t = (m - 5) / 2;
|
|
687
|
+
const llBodyCoords = leftArrowCoords.slice(0, t);
|
|
688
|
+
const lArrowCoords = leftArrowCoords.slice(t, t + 5);
|
|
689
|
+
let lrBodyCoords = leftArrowCoords.slice(t + 5, m);
|
|
690
|
+
let rlBodyCoords = rightArrowCoords.slice(0, t);
|
|
691
|
+
const rArrowCoords = rightArrowCoords.slice(t, t + 5);
|
|
692
|
+
const rrBodyCoords = rightArrowCoords.slice(t + 5, m);
|
|
693
|
+
rlBodyCoords = getBezierCoords(rlBodyCoords);
|
|
694
|
+
const bodyCoords = getBezierCoords(rrBodyCoords.concat(llBodyCoords.slice(1)));
|
|
695
|
+
lrBodyCoords = getBezierCoords(lrBodyCoords);
|
|
696
|
+
return rlBodyCoords.concat(rArrowCoords, bodyCoords, lArrowCoords, lrBodyCoords);
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* 插值箭形上的点
|
|
700
|
+
* @param coord1 - Wgs84坐标
|
|
701
|
+
* @param coord2 - Wgs84坐标
|
|
702
|
+
* @param coord3 - Wgs84坐标
|
|
703
|
+
* @param clockWise - 是否顺时针
|
|
704
|
+
*/
|
|
705
|
+
function getArrowCoords$1(coord1, coord2, coord3, clockWise, options) {
|
|
706
|
+
const midCoord = mid(coord1, coord2);
|
|
707
|
+
const len = mathDistance(midCoord, coord3);
|
|
708
|
+
let midCoord1 = getThirdCoord(coord3, midCoord, 0, len * .3, true);
|
|
709
|
+
let midCoord2 = getThirdCoord(coord3, midCoord, 0, len * .5, true);
|
|
710
|
+
midCoord1 = getThirdCoord(midCoord, midCoord1, HALF_PI, len / 5, clockWise);
|
|
711
|
+
midCoord2 = getThirdCoord(midCoord, midCoord2, HALF_PI, len / 4, clockWise);
|
|
712
|
+
const coords = [
|
|
713
|
+
midCoord,
|
|
714
|
+
midCoord1,
|
|
715
|
+
midCoord2,
|
|
716
|
+
coord3
|
|
717
|
+
];
|
|
718
|
+
const arrowCoords = getArrowHeadCoords$1(coords, options);
|
|
719
|
+
if (arrowCoords && Array.isArray(arrowCoords) && arrowCoords.length > 0) {
|
|
720
|
+
const [neckLeftCoord, neckRightCoord] = [arrowCoords[0], arrowCoords[4]];
|
|
721
|
+
const bodyCoords = getArrowBodyCoords$1(coords, neckLeftCoord, neckRightCoord, mathDistance(coord1, coord2) / getBaseLength(coords) / 2);
|
|
722
|
+
const n = bodyCoords.length;
|
|
723
|
+
let lCoords = bodyCoords.slice(0, n / 2);
|
|
724
|
+
let rCoords = bodyCoords.slice(n / 2, n);
|
|
725
|
+
lCoords.push(neckLeftCoord);
|
|
726
|
+
rCoords.push(neckRightCoord);
|
|
727
|
+
lCoords = lCoords.reverse();
|
|
728
|
+
lCoords.push(coord2);
|
|
729
|
+
rCoords = rCoords.reverse();
|
|
730
|
+
rCoords.push(coord1);
|
|
731
|
+
return lCoords.reverse().concat(arrowCoords, rCoords);
|
|
732
|
+
} else throw new Error("插值出错");
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* 插值头部点
|
|
736
|
+
* @param coords
|
|
737
|
+
*/
|
|
738
|
+
function getArrowHeadCoords$1(coords, options) {
|
|
739
|
+
const { headHeightFactor, headWidthFactor, neckWidthFactor, neckHeightFactor } = options;
|
|
740
|
+
const headHeight = getBaseLength(coords) * headHeightFactor;
|
|
741
|
+
const headCoord = coords.at(-1);
|
|
742
|
+
const headWidth = headHeight * headWidthFactor;
|
|
743
|
+
const neckWidth = headHeight * neckWidthFactor;
|
|
744
|
+
const neckHeight = headHeight * neckHeightFactor;
|
|
745
|
+
const headEndCoord = getThirdCoord(coords.at(-2), headCoord, 0, headHeight, true);
|
|
746
|
+
const neckEndCoord = getThirdCoord(coords.at(-2), headCoord, 0, neckHeight, true);
|
|
747
|
+
const headLeft = getThirdCoord(headCoord, headEndCoord, HALF_PI, headWidth, false);
|
|
748
|
+
const headRight = getThirdCoord(headCoord, headEndCoord, HALF_PI, headWidth, true);
|
|
749
|
+
return [
|
|
750
|
+
getThirdCoord(headCoord, neckEndCoord, HALF_PI, neckWidth, false),
|
|
751
|
+
headLeft,
|
|
752
|
+
headCoord,
|
|
753
|
+
headRight,
|
|
754
|
+
getThirdCoord(headCoord, neckEndCoord, HALF_PI, neckWidth, true)
|
|
755
|
+
];
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* 插值面部分数据
|
|
759
|
+
* @param coords
|
|
760
|
+
* @param neckLeft
|
|
761
|
+
* @param neckRight
|
|
762
|
+
* @param tailWidthFactor
|
|
763
|
+
*/
|
|
764
|
+
function getArrowBodyCoords$1(coords, neckLeft, neckRight, tailWidthFactor) {
|
|
765
|
+
const allLen = wholeDistance(coords);
|
|
766
|
+
const tailWidth = getBaseLength(coords) * tailWidthFactor;
|
|
767
|
+
const widthDif = (tailWidth - mathDistance(neckLeft, neckRight)) / 2;
|
|
768
|
+
let tempLen = 0;
|
|
769
|
+
const leftBodyCoords = [];
|
|
770
|
+
const rightBodyCoords = [];
|
|
771
|
+
for (let i = 1; i < coords.length - 1; i++) {
|
|
772
|
+
const angle = getAngleOfThreeCoords(coords[i - 1], coords[i], coords[i + 1]) / 2;
|
|
773
|
+
tempLen += mathDistance(coords[i - 1], coords[i]);
|
|
774
|
+
const w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle);
|
|
775
|
+
const left = getThirdCoord(coords[i - 1], coords[i], Math.PI - angle, w, true);
|
|
776
|
+
const right = getThirdCoord(coords[i - 1], coords[i], angle, w, false);
|
|
777
|
+
leftBodyCoords.push(left);
|
|
778
|
+
rightBodyCoords.push(right);
|
|
779
|
+
}
|
|
780
|
+
return leftBodyCoords.concat(rightBodyCoords);
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* 获取对称点
|
|
784
|
+
* @param lineCoord1
|
|
785
|
+
* @param lineCoord2
|
|
786
|
+
* @param coord
|
|
787
|
+
*/
|
|
788
|
+
function getTempCoord4$1(lineCoord1, lineCoord2, coord) {
|
|
789
|
+
const midCoord = mid(lineCoord1, lineCoord2);
|
|
790
|
+
const len = mathDistance(midCoord, coord);
|
|
791
|
+
const angle = getAngleOfThreeCoords(lineCoord1, midCoord, coord);
|
|
792
|
+
if (angle < HALF_PI) {
|
|
793
|
+
const distance1 = len * Math.sin(angle);
|
|
794
|
+
const distance2 = len * Math.cos(angle);
|
|
795
|
+
return getThirdCoord(midCoord, getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, false), HALF_PI, distance2, true);
|
|
796
|
+
} else if (angle >= HALF_PI && angle < Math.PI) {
|
|
797
|
+
const distance1 = len * Math.sin(Math.PI - angle);
|
|
798
|
+
const distance2 = len * Math.cos(Math.PI - angle);
|
|
799
|
+
return getThirdCoord(midCoord, getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, false), HALF_PI, distance2, false);
|
|
800
|
+
} else if (angle >= Math.PI && angle < Math.PI * 1.5) {
|
|
801
|
+
const distance1 = len * Math.sin(angle - Math.PI);
|
|
802
|
+
const distance2 = len * Math.cos(angle - Math.PI);
|
|
803
|
+
return getThirdCoord(midCoord, getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, true), HALF_PI, distance2, true);
|
|
804
|
+
} else {
|
|
805
|
+
const distance1 = len * Math.sin(Math.PI * 2 - angle);
|
|
806
|
+
const distance2 = len * Math.cos(Math.PI * 2 - angle);
|
|
807
|
+
return getThirdCoord(midCoord, getThirdCoord(lineCoord1, midCoord, HALF_PI, distance1, true), HALF_PI, distance2, false);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
//#endregion
|
|
812
|
+
//#region src/arrowStraightSharp.ts
|
|
813
|
+
/**
|
|
814
|
+
* 尖箭头
|
|
815
|
+
*
|
|
816
|
+
*/
|
|
817
|
+
function arrowStraightSharp(coords, options = {}) {
|
|
818
|
+
const { tailWidthFactor = .1, neckWidthFactor = .2, headWidthFactor = .25, headAngle = Math.PI / 8.5, neckAngle = Math.PI / 13 } = options;
|
|
819
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
820
|
+
const [coord1, coord2] = [coords[0], coords[1]];
|
|
821
|
+
const len = getBaseLength(coords);
|
|
822
|
+
const tailWidth = len * tailWidthFactor;
|
|
823
|
+
const neckWidth = len * neckWidthFactor;
|
|
824
|
+
const headWidth = len * headWidthFactor;
|
|
825
|
+
const tailLeft = getThirdCoord(coord2, coord1, HALF_PI, tailWidth, true);
|
|
826
|
+
const tailRight = getThirdCoord(coord2, coord1, HALF_PI, tailWidth, false);
|
|
827
|
+
const headLeft = getThirdCoord(coord1, coord2, headAngle, headWidth, false);
|
|
828
|
+
const headRight = getThirdCoord(coord1, coord2, headAngle, headWidth, true);
|
|
829
|
+
return [
|
|
830
|
+
tailLeft,
|
|
831
|
+
getThirdCoord(coord1, coord2, neckAngle, neckWidth, false),
|
|
832
|
+
headLeft,
|
|
833
|
+
coord2,
|
|
834
|
+
headRight,
|
|
835
|
+
getThirdCoord(coord1, coord2, neckAngle, neckWidth, true),
|
|
836
|
+
tailRight
|
|
837
|
+
];
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
//#endregion
|
|
841
|
+
//#region src/arrowStraight.ts
|
|
842
|
+
/**
|
|
843
|
+
* 直箭头
|
|
844
|
+
*/
|
|
845
|
+
function arrowStraight(coords) {
|
|
846
|
+
return arrowStraightSharp(coords, {
|
|
847
|
+
tailWidthFactor: .05,
|
|
848
|
+
neckWidthFactor: .1,
|
|
849
|
+
headWidthFactor: .15,
|
|
850
|
+
headAngle: Math.PI / 4,
|
|
851
|
+
neckAngle: Math.PI * .17741
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
//#endregion
|
|
856
|
+
//#region src/arrowStraightFine.ts
|
|
857
|
+
/**
|
|
858
|
+
* 细直箭头
|
|
859
|
+
*/
|
|
860
|
+
function arrowStraightFine(coords) {
|
|
861
|
+
const maxArrowLength = 3e6;
|
|
862
|
+
const arrowLengthScale = 5;
|
|
863
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
864
|
+
const [coord1, coord2] = [coords[0], coords[1]];
|
|
865
|
+
let len = mathDistance(coord1, coord2) / arrowLengthScale;
|
|
866
|
+
len = Math.min(len, maxArrowLength);
|
|
867
|
+
return [
|
|
868
|
+
coord1,
|
|
869
|
+
coord2,
|
|
870
|
+
getThirdCoord(coord1, coord2, Math.PI / 6, len, false),
|
|
871
|
+
coord2,
|
|
872
|
+
getThirdCoord(coord1, coord2, Math.PI / 6, len, true)
|
|
873
|
+
];
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
//#endregion
|
|
877
|
+
//#region src/arrowUnitCombatOperation.ts
|
|
878
|
+
/**
|
|
879
|
+
* 分队战斗行动(尖曲箭头)
|
|
880
|
+
*/
|
|
881
|
+
function arrowUnitCombatOperation(coords, options = {}) {
|
|
882
|
+
const { headHeightFactor = .18, headWidthFactor = .3, neckHeightFactor = .85, neckWidthFactor = .15, tailWidthFactor = .1 } = options;
|
|
883
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
884
|
+
else {
|
|
885
|
+
const tailWidth = getBaseLength(coords) * tailWidthFactor;
|
|
886
|
+
const tailLeft = getThirdCoord(coords[1], coords[0], HALF_PI, tailWidth, false);
|
|
887
|
+
const tailRight = getThirdCoord(coords[1], coords[0], HALF_PI, tailWidth, true);
|
|
888
|
+
const headCoords = getArrowHeadCoords(coords, {
|
|
889
|
+
tailLeft,
|
|
890
|
+
tailRight,
|
|
891
|
+
headHeightFactor,
|
|
892
|
+
headWidthFactor,
|
|
893
|
+
neckWidthFactor,
|
|
894
|
+
neckHeightFactor
|
|
895
|
+
});
|
|
896
|
+
if (headCoords && headCoords.length > 4) {
|
|
897
|
+
const neckLeft = headCoords[0];
|
|
898
|
+
const neckRight = headCoords[4];
|
|
899
|
+
const bodyCoords = getArrowBodyCoords(coords, neckLeft, neckRight, tailWidthFactor);
|
|
900
|
+
const coordlength = bodyCoords.length;
|
|
901
|
+
let leftCoords = [tailLeft].concat(bodyCoords.slice(0, coordlength / 2));
|
|
902
|
+
leftCoords.push(neckLeft);
|
|
903
|
+
let rightCoords = [tailRight].concat(bodyCoords.slice(coordlength / 2, coordlength));
|
|
904
|
+
rightCoords.push(neckRight);
|
|
905
|
+
leftCoords = getQBSplineCoords(leftCoords);
|
|
906
|
+
rightCoords = getQBSplineCoords(rightCoords);
|
|
907
|
+
return leftCoords.concat(headCoords, rightCoords.reverse());
|
|
908
|
+
} else return [];
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region src/arrowUnitCombatOperationTailed.ts
|
|
914
|
+
/**
|
|
915
|
+
* 燕尾尖箭头
|
|
916
|
+
*/
|
|
917
|
+
function arrowUnitCombatOperationTailed(coords, options = {}) {
|
|
918
|
+
const { headHeightFactor = .18, headWidthFactor = .3, neckHeightFactor = .85, neckWidthFactor = .15, tailWidthFactor = .1, swallowTailFactor = 1 } = options;
|
|
919
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
920
|
+
const tailWidth = getBaseLength(coords) * tailWidthFactor;
|
|
921
|
+
const tailLeft = getThirdCoord(coords[1], coords[0], HALF_PI, tailWidth, false);
|
|
922
|
+
const tailRight = getThirdCoord(coords[1], coords[0], HALF_PI, tailWidth, true);
|
|
923
|
+
const len = tailWidth * swallowTailFactor;
|
|
924
|
+
const tailCoords = [
|
|
925
|
+
tailLeft,
|
|
926
|
+
getThirdCoord(coords[1], coords[0], 0, len, true),
|
|
927
|
+
tailRight
|
|
928
|
+
];
|
|
929
|
+
const headCoords = getArrowHeadCoords(coords, {
|
|
930
|
+
tailLeft: tailCoords[0],
|
|
931
|
+
tailRight: tailCoords[2],
|
|
932
|
+
headHeightFactor,
|
|
933
|
+
headWidthFactor,
|
|
934
|
+
neckWidthFactor,
|
|
935
|
+
neckHeightFactor
|
|
936
|
+
});
|
|
937
|
+
if (headCoords && headCoords.length > 4) {
|
|
938
|
+
const neckLeft = headCoords[0];
|
|
939
|
+
const neckRight = headCoords[4];
|
|
940
|
+
const bodyCoords = getArrowBodyCoords(coords, neckLeft, neckRight, tailWidthFactor);
|
|
941
|
+
const coordlength = bodyCoords.length;
|
|
942
|
+
let leftCoords = [tailCoords[0]].concat(bodyCoords.slice(0, coordlength / 2));
|
|
943
|
+
leftCoords.push(neckLeft);
|
|
944
|
+
let rightCoords = [tailCoords[2]].concat(bodyCoords.slice(coordlength / 2, coordlength));
|
|
945
|
+
rightCoords.push(neckRight);
|
|
946
|
+
leftCoords = getQBSplineCoords(leftCoords);
|
|
947
|
+
rightCoords = getQBSplineCoords(rightCoords);
|
|
948
|
+
return leftCoords.concat(headCoords, rightCoords.reverse(), [tailCoords[1], leftCoords[0]]);
|
|
949
|
+
}
|
|
950
|
+
return [];
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
//#endregion
|
|
954
|
+
//#region src/assemblingPlace.ts
|
|
955
|
+
/**
|
|
956
|
+
* 集结地
|
|
957
|
+
*
|
|
958
|
+
*/
|
|
959
|
+
function assemblingPlace(coords) {
|
|
960
|
+
if (coords.length < 3) throw new Error(`coords.length must >= 3`);
|
|
961
|
+
const t = .4;
|
|
962
|
+
const midCoord = mid(coords[0], coords[2]);
|
|
963
|
+
coords.push(midCoord, coords[0], coords[1]);
|
|
964
|
+
let normals = [];
|
|
965
|
+
const pList = [];
|
|
966
|
+
for (let i = 0; i < coords.length - 2; i++) {
|
|
967
|
+
const coord1 = coords[i];
|
|
968
|
+
const coord2 = coords[i + 1];
|
|
969
|
+
const coord3 = coords[i + 2];
|
|
970
|
+
const normalCoords = getBisectorNormals(t, coord1, coord2, coord3);
|
|
971
|
+
normals = normals.concat(normalCoords);
|
|
972
|
+
}
|
|
973
|
+
const count = normals.length;
|
|
974
|
+
normals = [normals[count - 1]].concat(normals.slice(0, count - 1));
|
|
975
|
+
for (let i = 0; i < coords.length - 2; i++) {
|
|
976
|
+
const coord1 = coords[i];
|
|
977
|
+
const coord2 = coords[i + 1];
|
|
978
|
+
pList.push(coord1);
|
|
979
|
+
for (let t$1 = 0; t$1 <= FITTING_COUNT; t$1++) {
|
|
980
|
+
const coord = getCubicValue(t$1 / FITTING_COUNT, coord1, normals[i * 2], normals[i * 2 + 1], coord2);
|
|
981
|
+
pList.push(coord);
|
|
982
|
+
}
|
|
983
|
+
pList.push(coord2);
|
|
984
|
+
}
|
|
985
|
+
return pList;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/circle.ts
|
|
990
|
+
/**
|
|
991
|
+
* 标绘画圆算法,继承面要素相关方法和属性
|
|
992
|
+
*/
|
|
993
|
+
function circle(coords) {
|
|
994
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
995
|
+
const center = coords[0];
|
|
996
|
+
const radius = mathDistance(center, coords[1]);
|
|
997
|
+
let [x, y, angle] = [
|
|
998
|
+
0,
|
|
999
|
+
0,
|
|
1000
|
+
0
|
|
1001
|
+
];
|
|
1002
|
+
const _coords = [];
|
|
1003
|
+
for (let i = 0; i <= 100; i++) {
|
|
1004
|
+
angle = Math.PI * 2 * i / 100;
|
|
1005
|
+
x = center[0] + radius * Math.cos(angle);
|
|
1006
|
+
y = center[1] + radius * Math.sin(angle);
|
|
1007
|
+
_coords.push([x, y]);
|
|
1008
|
+
}
|
|
1009
|
+
return _coords;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
//#endregion
|
|
1013
|
+
//#region src/closedCurve.ts
|
|
1014
|
+
/**
|
|
1015
|
+
* 闭合曲面
|
|
1016
|
+
*
|
|
1017
|
+
*/
|
|
1018
|
+
function closedCurve(coords) {
|
|
1019
|
+
const t = .3;
|
|
1020
|
+
if (coords.length < 3) throw new Error("coords.length must >= 3");
|
|
1021
|
+
else {
|
|
1022
|
+
coords.push(coords[0], coords[1]);
|
|
1023
|
+
let normals = [];
|
|
1024
|
+
const pList = [];
|
|
1025
|
+
for (let i = 0; i < coords.length - 2; i++) {
|
|
1026
|
+
const normalCoords = getBisectorNormals(t, coords[i], coords[i + 1], coords[i + 2]);
|
|
1027
|
+
normals = normals.concat(normalCoords);
|
|
1028
|
+
}
|
|
1029
|
+
const coordlength = normals.length;
|
|
1030
|
+
normals = [normals[coordlength - 1]].concat(normals.slice(0, coordlength - 1));
|
|
1031
|
+
for (let i = 0; i < coords.length - 2; i++) {
|
|
1032
|
+
const coord1 = coords[i];
|
|
1033
|
+
const coord2 = coords[i + 1];
|
|
1034
|
+
pList.push(coord1);
|
|
1035
|
+
for (let t$1 = 0; t$1 <= FITTING_COUNT; t$1++) {
|
|
1036
|
+
const coord = getCubicValue(t$1 / FITTING_COUNT, coord1, normals[i * 2], normals[i * 2 + 1], coord2);
|
|
1037
|
+
pList.push(coord);
|
|
1038
|
+
}
|
|
1039
|
+
pList.push(coord2);
|
|
1040
|
+
}
|
|
1041
|
+
return pList;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
//#endregion
|
|
1046
|
+
//#region src/curve.ts
|
|
1047
|
+
/**
|
|
1048
|
+
* 标绘曲线算法
|
|
1049
|
+
*/
|
|
1050
|
+
function curve(coords) {
|
|
1051
|
+
const t = .3;
|
|
1052
|
+
if (coords.length < 3) throw new Error("coords.length must >= 2");
|
|
1053
|
+
else return getCurveCoords(t, coords);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
//#endregion
|
|
1057
|
+
//#region src/ellipse.ts
|
|
1058
|
+
/**
|
|
1059
|
+
* 标绘画椭圆算法,继承面要素相关方法和属性
|
|
1060
|
+
*/
|
|
1061
|
+
function ellipse(coords) {
|
|
1062
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
1063
|
+
const [coord1, coord2] = [coords[0], coords[1]];
|
|
1064
|
+
const center = mid(coord1, coord2);
|
|
1065
|
+
const majorRadius = Math.abs((coord1[0] - coord2[0]) / 2);
|
|
1066
|
+
const minorRadius = Math.abs((coord1[1] - coord2[1]) / 2);
|
|
1067
|
+
let [x, y, angle] = [
|
|
1068
|
+
0,
|
|
1069
|
+
0,
|
|
1070
|
+
0
|
|
1071
|
+
];
|
|
1072
|
+
const _coords = [];
|
|
1073
|
+
for (let i = 0; i <= FITTING_COUNT; i++) {
|
|
1074
|
+
angle = Math.PI * 2 * i / FITTING_COUNT;
|
|
1075
|
+
x = center[0] + majorRadius * Math.cos(angle);
|
|
1076
|
+
y = center[1] + minorRadius * Math.sin(angle);
|
|
1077
|
+
coords.push([x, y]);
|
|
1078
|
+
}
|
|
1079
|
+
return _coords;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
//#endregion
|
|
1083
|
+
//#region src/lune.ts
|
|
1084
|
+
/**
|
|
1085
|
+
* 弓形
|
|
1086
|
+
*/
|
|
1087
|
+
function lune(coords) {
|
|
1088
|
+
coords = [...coords];
|
|
1089
|
+
const coordLength = coords.length;
|
|
1090
|
+
if (coordLength < 2) throw new Error("coords.length must >= 2");
|
|
1091
|
+
if (coordLength === 2) {
|
|
1092
|
+
const midCoord = mid(coords[0], coords[1]);
|
|
1093
|
+
const d = mathDistance(coords[0], midCoord);
|
|
1094
|
+
const coord = getThirdCoord(coords[0], midCoord, HALF_PI, d);
|
|
1095
|
+
coords.push(coord);
|
|
1096
|
+
}
|
|
1097
|
+
let [coord1, coord2, coord3, startAngle, endAngle] = [
|
|
1098
|
+
coords[0],
|
|
1099
|
+
coords[1],
|
|
1100
|
+
coords[2],
|
|
1101
|
+
0,
|
|
1102
|
+
0
|
|
1103
|
+
];
|
|
1104
|
+
const center = getCircleCenterOfThreeCoords(coord1, coord2, coord3);
|
|
1105
|
+
const radius = mathDistance(coord1, center);
|
|
1106
|
+
const angle1 = getAzimuth(coord1, center);
|
|
1107
|
+
const angle2 = getAzimuth(coord2, center);
|
|
1108
|
+
if (isClockWise(coord1, coord2, coord3)) {
|
|
1109
|
+
startAngle = angle2;
|
|
1110
|
+
endAngle = angle1;
|
|
1111
|
+
} else {
|
|
1112
|
+
startAngle = angle1;
|
|
1113
|
+
endAngle = angle2;
|
|
1114
|
+
}
|
|
1115
|
+
coords = getArcCoords(center, radius, startAngle, endAngle);
|
|
1116
|
+
coords.push(coords[0]);
|
|
1117
|
+
return coords;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
//#endregion
|
|
1121
|
+
//#region src/rectAngle.ts
|
|
1122
|
+
/**
|
|
1123
|
+
* 规则矩形
|
|
1124
|
+
*
|
|
1125
|
+
*/
|
|
1126
|
+
function rectAngle(coords) {
|
|
1127
|
+
if (coords.length < 2) throw new Error("coords.length must >= 2");
|
|
1128
|
+
const [startCoord, endCoord] = coords;
|
|
1129
|
+
return [
|
|
1130
|
+
startCoord,
|
|
1131
|
+
[startCoord[0], endCoord[1]],
|
|
1132
|
+
endCoord,
|
|
1133
|
+
[endCoord[0], startCoord[1]],
|
|
1134
|
+
startCoord
|
|
1135
|
+
];
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/rectinclined1.ts
|
|
1140
|
+
/**
|
|
1141
|
+
* 斜矩形1
|
|
1142
|
+
*
|
|
1143
|
+
*/
|
|
1144
|
+
function rectinclined1(coords) {
|
|
1145
|
+
if (coords.length < 3) throw new Error("coords.length must >= 3");
|
|
1146
|
+
else {
|
|
1147
|
+
const [coord1, coord2, mouse] = [
|
|
1148
|
+
coords[0],
|
|
1149
|
+
coords[1],
|
|
1150
|
+
coords[2]
|
|
1151
|
+
];
|
|
1152
|
+
const d = calculatePerpendicularDistance(coord1, coord2, mouse);
|
|
1153
|
+
const coord3 = calculatePerpendicularCoord(coord1, coord2, calculatePositionRelativeToLine(coord1, coord2, mouse) * d);
|
|
1154
|
+
const coord4 = calculateFourthCoord(coord1, coord2, coord3);
|
|
1155
|
+
const pList = [];
|
|
1156
|
+
pList.push(coord1, coord2, coord3, coord4, coord1);
|
|
1157
|
+
return pList;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* 已知p1,p2,p3三点,计算p3到p1p2的垂直距离
|
|
1162
|
+
* @param {*} p1
|
|
1163
|
+
* @param {*} p2
|
|
1164
|
+
* @param {*} p3
|
|
1165
|
+
*/
|
|
1166
|
+
function calculatePerpendicularDistance(p1, p2, p3) {
|
|
1167
|
+
const vx = p2[0] - p1[0];
|
|
1168
|
+
const vy = p2[1] - p1[1];
|
|
1169
|
+
const px = p3[0] - p1[0];
|
|
1170
|
+
const py = p3[1] - p1[1];
|
|
1171
|
+
const vMagnitude = Math.hypot(vx, vy);
|
|
1172
|
+
const projectionLength = (px * vx + py * vy) / vMagnitude;
|
|
1173
|
+
const pMagnitude = Math.hypot(px, py);
|
|
1174
|
+
return Math.sqrt(pMagnitude * pMagnitude - projectionLength * projectionLength);
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* 已知p1,p2,两点,判断p3点在p1p2的左右,返回-1右侧,0线上,1左侧
|
|
1178
|
+
* @param {*} p1
|
|
1179
|
+
* @param {*} p2
|
|
1180
|
+
* @param {*} p3
|
|
1181
|
+
*/
|
|
1182
|
+
function calculatePositionRelativeToLine(p1, p2, p3) {
|
|
1183
|
+
const v1 = {
|
|
1184
|
+
x: p2[0] - p1[0],
|
|
1185
|
+
y: p2[1] - p1[1]
|
|
1186
|
+
};
|
|
1187
|
+
const v2 = {
|
|
1188
|
+
x: p3[0] - p1[0],
|
|
1189
|
+
y: p3[1] - p1[1]
|
|
1190
|
+
};
|
|
1191
|
+
const direction = v1.x * v2.y - v1.y * v2.x > 0 ? 1 : -1;
|
|
1192
|
+
if (p1[1] > p2[1]) return direction;
|
|
1193
|
+
return -direction;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* 已知p1,p2,p3点求矩形的p4点
|
|
1197
|
+
* @param {*} p1
|
|
1198
|
+
* @param {*} p2
|
|
1199
|
+
* @param {*} p3
|
|
1200
|
+
*/
|
|
1201
|
+
function calculateFourthCoord(p1, p2, p3) {
|
|
1202
|
+
return [p1[0] + p3[0] - p2[0], p1[1] + p3[1] - p2[1]];
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* 已知p1,p2两点和距离d,求距离p1p2垂直距离为d的点p3
|
|
1206
|
+
* @param {*} p1
|
|
1207
|
+
* @param {*} p2
|
|
1208
|
+
* @param {*} d
|
|
1209
|
+
*/
|
|
1210
|
+
function calculatePerpendicularCoord(p1, p2, d) {
|
|
1211
|
+
const m = (p2[1] - p1[1]) / (p2[0] - p1[0]);
|
|
1212
|
+
let x, y;
|
|
1213
|
+
if (m !== 0) {
|
|
1214
|
+
const perpendicularSlope = -1 / m;
|
|
1215
|
+
const c = p2[1] - perpendicularSlope * p2[0];
|
|
1216
|
+
x = d * Math.sqrt(1 / (1 + perpendicularSlope ** 2)) + p2[0];
|
|
1217
|
+
y = perpendicularSlope * x + c;
|
|
1218
|
+
} else {
|
|
1219
|
+
x = p2[0];
|
|
1220
|
+
y = p2[1] - d;
|
|
1221
|
+
}
|
|
1222
|
+
return [x, y];
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
//#endregion
|
|
1226
|
+
exports.FITTING_COUNT = FITTING_COUNT;
|
|
1227
|
+
exports.HALF_PI = HALF_PI;
|
|
1228
|
+
exports.TWO_PI = TWO_PI;
|
|
1229
|
+
exports.ZERO_TOLERANCE = ZERO_TOLERANCE;
|
|
1230
|
+
exports.arc = arc;
|
|
1231
|
+
exports.arrowAttackDirection = arrowAttackDirection;
|
|
1232
|
+
exports.arrowAttackDirectionTailed = arrowAttackDirectionTailed;
|
|
1233
|
+
exports.arrowClamped = arrowClamped;
|
|
1234
|
+
exports.arrowStraight = arrowStraight;
|
|
1235
|
+
exports.arrowStraightFine = arrowStraightFine;
|
|
1236
|
+
exports.arrowStraightSharp = arrowStraightSharp;
|
|
1237
|
+
exports.arrowUnitCombatOperation = arrowUnitCombatOperation;
|
|
1238
|
+
exports.arrowUnitCombatOperationTailed = arrowUnitCombatOperationTailed;
|
|
1239
|
+
exports.assemblingPlace = assemblingPlace;
|
|
1240
|
+
exports.calculateFourthCoord = calculateFourthCoord;
|
|
1241
|
+
exports.calculatePerpendicularCoord = calculatePerpendicularCoord;
|
|
1242
|
+
exports.calculatePerpendicularDistance = calculatePerpendicularDistance;
|
|
1243
|
+
exports.calculatePositionRelativeToLine = calculatePositionRelativeToLine;
|
|
1244
|
+
exports.circle = circle;
|
|
1245
|
+
exports.closedCurve = closedCurve;
|
|
1246
|
+
exports.curve = curve;
|
|
1247
|
+
exports.ellipse = ellipse;
|
|
1248
|
+
exports.getAngleOfThreeCoords = getAngleOfThreeCoords;
|
|
1249
|
+
exports.getArcCoords = getArcCoords;
|
|
1250
|
+
exports.getArrowBodyCoords = getArrowBodyCoords;
|
|
1251
|
+
exports.getArrowCoords = getArrowCoords;
|
|
1252
|
+
exports.getArrowHeadCoords = getArrowHeadCoords;
|
|
1253
|
+
exports.getAzimuth = getAzimuth;
|
|
1254
|
+
exports.getBaseLength = getBaseLength;
|
|
1255
|
+
exports.getBezierCoords = getBezierCoords;
|
|
1256
|
+
exports.getBinomialFactor = getBinomialFactor;
|
|
1257
|
+
exports.getBisectorNormals = getBisectorNormals;
|
|
1258
|
+
exports.getCircleCenterOfThreeCoords = getCircleCenterOfThreeCoords;
|
|
1259
|
+
exports.getCoordOnLine = getCoordOnLine;
|
|
1260
|
+
exports.getCubicValue = getCubicValue;
|
|
1261
|
+
exports.getCurveCoords = getCurveCoords;
|
|
1262
|
+
exports.getFactorial = getFactorial;
|
|
1263
|
+
exports.getIntersectCoord = getIntersectCoord;
|
|
1264
|
+
exports.getLeftMostControlCoord = getLeftMostControlCoord;
|
|
1265
|
+
exports.getNormal = getNormal;
|
|
1266
|
+
exports.getQBSplineCoords = getQBSplineCoords;
|
|
1267
|
+
exports.getQuadricBSplineFactor = getQuadricBSplineFactor;
|
|
1268
|
+
exports.getRightMostControlCoord = getRightMostControlCoord;
|
|
1269
|
+
exports.getTempCoord4 = getTempCoord4;
|
|
1270
|
+
exports.getThirdCoord = getThirdCoord;
|
|
1271
|
+
exports.isClockWise = isClockWise;
|
|
1272
|
+
exports.lune = lune;
|
|
1273
|
+
exports.mathDistance = mathDistance;
|
|
1274
|
+
exports.mid = mid;
|
|
1275
|
+
exports.rectAngle = rectAngle;
|
|
1276
|
+
exports.rectinclined1 = rectinclined1;
|
|
1277
|
+
exports.wholeDistance = wholeDistance;
|
|
1278
|
+
//# sourceMappingURL=index.cjs.map
|