svg-path-simplify 0.1.3 → 0.2.2
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/README.md +10 -0
- package/dist/svg-path-simplify.esm.js +3905 -1533
- package/dist/svg-path-simplify.esm.min.js +13 -1
- package/dist/svg-path-simplify.js +3923 -1551
- package/dist/svg-path-simplify.min.js +13 -1
- package/dist/svg-path-simplify.min.js.gz +0 -0
- package/index.html +61 -31
- package/package.json +3 -5
- package/src/constants.js +3 -0
- package/src/index-node.js +0 -1
- package/src/index.js +26 -0
- package/src/pathData_simplify_cubic.js +74 -31
- package/src/pathData_simplify_cubicsToArcs.js +566 -0
- package/src/pathData_simplify_harmonize_cpts.js +170 -0
- package/src/pathData_simplify_revertToquadratics.js +21 -0
- package/src/pathSimplify-main.js +253 -86
- package/src/poly-fit-curve-schneider.js +570 -0
- package/src/simplify_poly_RDP.js +146 -0
- package/src/simplify_poly_radial_distance.js +100 -0
- package/src/svg_getViewbox.js +1 -1
- package/src/svgii/geometry.js +389 -63
- package/src/svgii/geometry_area.js +2 -1
- package/src/svgii/pathData_analyze.js +259 -212
- package/src/svgii/pathData_convert.js +91 -663
- package/src/svgii/pathData_fromPoly.js +12 -0
- package/src/svgii/pathData_parse.js +90 -89
- package/src/svgii/pathData_parse_els.js +3 -0
- package/src/svgii/pathData_parse_fontello.js +449 -0
- package/src/svgii/pathData_remove_collinear.js +44 -37
- package/src/svgii/pathData_reorder.js +2 -1
- package/src/svgii/pathData_simplify_redraw.js +343 -0
- package/src/svgii/pathData_simplify_refineCorners.js +18 -9
- package/src/svgii/pathData_simplify_refineExtremes.js +19 -78
- package/src/svgii/pathData_split.js +42 -45
- package/src/svgii/pathData_toPolygon.js +130 -4
- package/src/svgii/poly_analyze.js +470 -14
- package/src/svgii/poly_to_pathdata.js +224 -19
- package/src/svgii/rounding.js +55 -112
- package/src/svgii/svg_cleanup.js +13 -1
- package/src/svgii/visualize.js +8 -3
- package/{debug.cjs → tests/debug.cjs} +3 -0
- /package/{test.js → tests/test.js} +0 -0
- /package/{testSVG.js → tests/testSVG.js} +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { checkLineIntersection, getDistManhattan, pointAtT } from "./geometry";
|
|
2
|
+
import { pathDataToD } from "./pathData_stringify";
|
|
3
|
+
import { renderPath, renderPoint } from "./visualize";
|
|
4
|
+
|
|
5
|
+
export function redrawPathData(pathData, {
|
|
6
|
+
tolerance = 1
|
|
7
|
+
|
|
8
|
+
} = {}) {
|
|
9
|
+
|
|
10
|
+
let pathDataN = [];
|
|
11
|
+
let chunks = [];
|
|
12
|
+
let chunk = [];
|
|
13
|
+
let idx = 0;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
let l = pathData.length;
|
|
17
|
+
//return pathData
|
|
18
|
+
|
|
19
|
+
//console.log('pathData', pathData);
|
|
20
|
+
|
|
21
|
+
//let d0 = pathDataToD(pathData)
|
|
22
|
+
//console.log(d0);
|
|
23
|
+
|
|
24
|
+
for (let i = 1; i < l; i++) {
|
|
25
|
+
let com = pathData[i];
|
|
26
|
+
let { type, values, p0, cp1 = null, cp2 = null, p, extreme = null, semiExtreme = null, corner = null, directionChange } = com;
|
|
27
|
+
|
|
28
|
+
let comN = pathData[i + 1] || null;
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
if (extreme || corner || semiExtreme || directionChange) {
|
|
32
|
+
|
|
33
|
+
if (extreme) renderPoint(markers, com.p, 'cyan', '1%', '0.5')
|
|
34
|
+
//if(directionChange) renderPoint(markers, com.p, 'blue', '1.75%', '0.5')
|
|
35
|
+
if (semiExtreme) renderPoint(markers, com.p, 'orange', '1%', '0.5')
|
|
36
|
+
if (corner) renderPoint(markers, com.p, 'magenta', '1.75%', '0.5')
|
|
37
|
+
}
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
//start new chunk
|
|
42
|
+
if (extreme || corner || (comN && comN.type !== type)) {
|
|
43
|
+
chunk.push(com)
|
|
44
|
+
chunks.push(chunk)
|
|
45
|
+
chunk = []
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
chunk.push(com)
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('!!!chunks', chunks);
|
|
54
|
+
|
|
55
|
+
renderChunks(chunks)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// cleanup chunks
|
|
60
|
+
//let chunksClean = [];
|
|
61
|
+
|
|
62
|
+
let chunksLen = chunks.length;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
for (let c = 0; c < chunksLen; c++) {
|
|
68
|
+
let chunk = chunks[c];
|
|
69
|
+
let chunkN = chunks[c + 1] || null;
|
|
70
|
+
|
|
71
|
+
let chunkLen = chunk.length;
|
|
72
|
+
|
|
73
|
+
if(c===chunksLen-1){
|
|
74
|
+
// renderPoint(markers, chunk[chunkLen-1].p, 'magenta', '0.5%', '0.5')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (chunkLen === 1 && chunkN && chunkN[0].type === 'C') {
|
|
78
|
+
//renderPoint(markers, chunk[0].p, 'red', '0.5%', '0.5')
|
|
79
|
+
//renderPoint(markers, chunkN[0].cp1, 'magenta', '0.5%', '0.5')
|
|
80
|
+
//chunkN[0].p0 = chunk[0].p0
|
|
81
|
+
//chunks[c] = null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//chunksClean.push(chunk)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
chunks = chunks.filter(Boolean)
|
|
88
|
+
|
|
89
|
+
// test render
|
|
90
|
+
//renderChunks(chunks)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
let pathDataC = [pathData[0]];
|
|
96
|
+
let stroke = 'green';
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* combine chunk based
|
|
101
|
+
*/
|
|
102
|
+
for (let c = 0; c < chunks.length; c++) {
|
|
103
|
+
let chunk = chunks[c]
|
|
104
|
+
let chunkLen = chunk.length;
|
|
105
|
+
|
|
106
|
+
stroke = c % 2 === 0 ? 'orange' : 'green';
|
|
107
|
+
let comChunk0 = chunk[0]
|
|
108
|
+
let comChunk1 = chunk[chunkLen - 1]
|
|
109
|
+
let thresh = getDistManhattan(comChunk0.p0, comChunk1.p) * 0.05
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// commands in chunk
|
|
113
|
+
for (let i = 0, l = chunkLen; i < l; i++) {
|
|
114
|
+
let com = chunk[i];
|
|
115
|
+
let comN = chunk[i + 1];
|
|
116
|
+
let comL = chunk[l - 1];
|
|
117
|
+
|
|
118
|
+
let isBezier = comChunk0.type === 'C' && comChunk1.type === 'C'
|
|
119
|
+
|
|
120
|
+
//console.log(com);
|
|
121
|
+
let { type, values, p0, cp1 = null, cp2 = null, p = null, extreme, semiExtreme = null, corner = null } = com;
|
|
122
|
+
|
|
123
|
+
let pI1 = null, pI2 = null;
|
|
124
|
+
let cp1_S = null, cp2_S = null;
|
|
125
|
+
let cp2_M = null;
|
|
126
|
+
let cp1_M = null;
|
|
127
|
+
let pathDataS = [];
|
|
128
|
+
let tSplit = 0.666
|
|
129
|
+
let comMid = null;
|
|
130
|
+
|
|
131
|
+
// 0. adjust Extreme cpts
|
|
132
|
+
if (isBezier) {
|
|
133
|
+
let dx1 = Math.abs(comChunk0.p0.x - comChunk0.cp1.x)
|
|
134
|
+
let dy1 = Math.abs(comChunk0.p0.y - comChunk0.cp1.y)
|
|
135
|
+
let dx2 = Math.abs(comChunk1.p.x - comChunk1.cp2.x)
|
|
136
|
+
let dy2 = Math.abs(comChunk1.p.y - comChunk1.cp2.y)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
let vertical1 = dx1 < thresh && dx1 < dy1;
|
|
140
|
+
let horizontal1 = dy1 < thresh && dx1 > dy1;
|
|
141
|
+
|
|
142
|
+
let vertical2 = dx2 < thresh && dx2 < dy2;
|
|
143
|
+
let horizontal2 = dy2 < thresh && dx2 > dy2;
|
|
144
|
+
|
|
145
|
+
if (horizontal1) comChunk0.cp1.y = comChunk0.p0.y
|
|
146
|
+
if (horizontal2) comChunk1.cp2.y = comChunk1.p.y
|
|
147
|
+
if (vertical1) comChunk0.cp1.x = comChunk0.p0.x
|
|
148
|
+
if (vertical2) comChunk1.cp2.x = comChunk1.p.x
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// test render - original pathdata
|
|
153
|
+
let pathDataChunk = [
|
|
154
|
+
{ type: 'M', values: [com.p0.x, com.p0.y] },
|
|
155
|
+
{ type, values },
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
let d = pathDataToD(pathDataChunk);
|
|
160
|
+
// renderPath(markers, d, stroke, '1%', '0.5')
|
|
161
|
+
// continue
|
|
162
|
+
/*
|
|
163
|
+
|
|
164
|
+
*/
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
// 1. only one command in chunk - nothing to simplify
|
|
168
|
+
if (chunkLen === 1 || type !== 'C') {
|
|
169
|
+
stroke = 'red'
|
|
170
|
+
pathDataC.push(com)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
// 2. could be simplified
|
|
176
|
+
else {
|
|
177
|
+
// 2.1 has semi extreme - extrapolate
|
|
178
|
+
// 2.2 has sdirection change
|
|
179
|
+
let semiExtremes = chunk.filter(ch => ch.semiExtreme);
|
|
180
|
+
let comsDirectionChange = chunk.filter(ch => ch.directionChange)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
if (semiExtremes.length || comsDirectionChange.length) {
|
|
184
|
+
stroke = c % 2 === 0 ? 'purple' : 'magenta';
|
|
185
|
+
|
|
186
|
+
// semiExtreme command
|
|
187
|
+
comMid = semiExtremes.length ? semiExtremes[0] : comsDirectionChange[0];
|
|
188
|
+
|
|
189
|
+
// zero length cpt vectors
|
|
190
|
+
if (comChunk0.p0.x === comChunk0.cp1.x && comChunk0.p0.y === comChunk0.cp1.y) {
|
|
191
|
+
comChunk0.cp1 = pointAtT([comChunk0.p0, comChunk0.cp1, comChunk0.cp2, comChunk0.p], 0.5)
|
|
192
|
+
}
|
|
193
|
+
else if (comChunk1.p.x === comChunk1.cp2.x && comChunk1.p.y === comChunk1.cp2.y) {
|
|
194
|
+
comChunk1.cp2 = pointAtT([comChunk1.p0, comChunk1.cp1, comChunk1.cp2, comChunk1.p], 0.5)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
pI1 = checkLineIntersection(comMid.p, comMid.cp2, comChunk0.p0, comChunk0.cp1, false)
|
|
199
|
+
pI2 = checkLineIntersection(comMid.p, comMid.cp2, comChunk1.p, comChunk1.cp2, false)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
// intersections try to extrapolate cpts
|
|
203
|
+
if (pI1 && pI2) {
|
|
204
|
+
|
|
205
|
+
cp1_S = pointAtT([comChunk0.p0, pI1], tSplit)
|
|
206
|
+
cp2_S = pointAtT([comChunk1.p, pI2], tSplit)
|
|
207
|
+
|
|
208
|
+
cp2_M = pointAtT([comMid.p, pI1], tSplit)
|
|
209
|
+
cp1_M = pointAtT([comMid.p, pI2], tSplit)
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
renderPoint(markers, cp1_S, 'magenta', '1%', '1' )
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
pathDataS = [
|
|
216
|
+
{ type: 'M', values: [comChunk0.p0.x, comChunk0.p0.y] },
|
|
217
|
+
{
|
|
218
|
+
type: 'C', values: [
|
|
219
|
+
cp1_S.x, cp1_S.y,
|
|
220
|
+
cp2_M.x, cp2_M.y,
|
|
221
|
+
comMid.p.x,
|
|
222
|
+
comMid.p.y
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
type: 'C', values: [
|
|
227
|
+
cp1_M.x, cp1_M.y,
|
|
228
|
+
cp2_S.x, cp2_S.y,
|
|
229
|
+
comChunk1.p.x,
|
|
230
|
+
comChunk1.p.y,
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
stroke = c % 2 === 0 ? 'green' : 'gold'
|
|
236
|
+
d = pathDataToD(pathDataS)
|
|
237
|
+
|
|
238
|
+
//renderPath(markers, d, 'green', '1%', '0.5')
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
pathDataC.push(
|
|
242
|
+
{
|
|
243
|
+
type: 'C', values: [
|
|
244
|
+
cp1_S.x, cp1_S.y,
|
|
245
|
+
cp2_M.x, cp2_M.y,
|
|
246
|
+
comMid.p.x,
|
|
247
|
+
comMid.p.y
|
|
248
|
+
],
|
|
249
|
+
p0: comChunk0.p0,
|
|
250
|
+
cp1: cp1_S,
|
|
251
|
+
cp2: cp2_M,
|
|
252
|
+
p: comMid.p,
|
|
253
|
+
dimA: getDistManhattan(comChunk0.p0, comMid.p)
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
{
|
|
257
|
+
type: 'C', values: [
|
|
258
|
+
cp1_M.x, cp1_M.y,
|
|
259
|
+
cp2_S.x, cp2_S.y,
|
|
260
|
+
comChunk1.p.x,
|
|
261
|
+
comChunk1.p.y,
|
|
262
|
+
],
|
|
263
|
+
p0: comMid.p,
|
|
264
|
+
cp1: cp1_M,
|
|
265
|
+
cp2: cp2_S,
|
|
266
|
+
p: comChunk1.p,
|
|
267
|
+
extreme: true,
|
|
268
|
+
dimA: getDistManhattan(comMid.p, comChunk1.p)
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
break
|
|
273
|
+
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
pathDataC.push(com)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/*
|
|
286
|
+
// render
|
|
287
|
+
let d = pathDataToD(pathDataC)
|
|
288
|
+
console.log(d);
|
|
289
|
+
renderPath(markers, d, 'red', '1%', '0.5')
|
|
290
|
+
*/
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
return pathDataC
|
|
294
|
+
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
function renderChunks(chunks) {
|
|
300
|
+
|
|
301
|
+
console.log('chunks', chunks);
|
|
302
|
+
|
|
303
|
+
let stroke = 'green';
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* combine chunk based
|
|
307
|
+
*/
|
|
308
|
+
for (let c = 0; c < chunks.length; c++) {
|
|
309
|
+
let chunk = chunks[c]
|
|
310
|
+
let chunkLen = chunk.length;
|
|
311
|
+
|
|
312
|
+
stroke = c % 2 === 0 ? 'orange' : 'green';
|
|
313
|
+
let comChunk0 = chunk[0]
|
|
314
|
+
let comChunk1 = chunk[chunkLen - 1]
|
|
315
|
+
|
|
316
|
+
let pathDataChunk = [
|
|
317
|
+
{ type: 'M', values: [comChunk0.p0.x, comChunk0.p0.y] }
|
|
318
|
+
]
|
|
319
|
+
|
|
320
|
+
// commands in chunk
|
|
321
|
+
for (let i = 0, l = chunkLen; i < l; i++) {
|
|
322
|
+
let com = chunk[i];
|
|
323
|
+
let comN = chunk[i + 1];
|
|
324
|
+
let comL = chunk[l - 1];
|
|
325
|
+
let isBezier = comChunk0.type === 'C' && comChunk1.type === 'C'
|
|
326
|
+
|
|
327
|
+
//console.log(com);
|
|
328
|
+
let { type, values, p0, cp1 = null, cp2 = null, p = null, extreme, semiExtreme = null, corner = null } = com;
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
// test render - original pathdata
|
|
332
|
+
pathDataChunk.push(
|
|
333
|
+
{ type, values },
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let d = pathDataToD(pathDataChunk);
|
|
339
|
+
renderPath(markers, d, stroke, '1%', '0.5')
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { checkLineIntersection,
|
|
1
|
+
import { checkLineIntersection, getDistManhattan, getSquareDistance, interpolate, pointAtT } from "./geometry";
|
|
2
2
|
import { getPolygonArea } from "./geometry_area";
|
|
3
3
|
import { commandIsFlat } from "./geometry_flatness";
|
|
4
4
|
import { renderPoint } from "./visualize";
|
|
@@ -33,7 +33,7 @@ export function refineRoundedCorners(pathData, {
|
|
|
33
33
|
//console.log('lastIsLine', lastIsLine, 'firstIsLine', firstIsLine, 'lastIsBez', lastIsBez, 'firstIsBez', firstIsBez, 'isClosed', isClosed, 'comLast1', comLast1);
|
|
34
34
|
|
|
35
35
|
let normalizeClose = isClosed && firstIsBez && (lastIsLine || zIsLineto);
|
|
36
|
-
let adjustStart = false
|
|
36
|
+
//let adjustStart = false
|
|
37
37
|
//normalizeClose = false
|
|
38
38
|
//console.log('normalizeClose', normalizeClose);
|
|
39
39
|
|
|
@@ -96,13 +96,14 @@ export function refineRoundedCorners(pathData, {
|
|
|
96
96
|
if (comL1) {
|
|
97
97
|
|
|
98
98
|
// linetos
|
|
99
|
-
let len1 =
|
|
100
|
-
let len2 =
|
|
99
|
+
let len1 = getDistManhattan(comL0.p0, comL0.p)
|
|
100
|
+
let len2 = getDistManhattan(comL1.p0, comL1.p)
|
|
101
101
|
|
|
102
102
|
// bezier
|
|
103
103
|
//comBez = comBez[0];
|
|
104
104
|
let comBezLen = comBez.length;
|
|
105
|
-
let len3 =
|
|
105
|
+
//let len3 = getDistManhattan(comBez[0].p0, comBez[comBezLen - 1].p)
|
|
106
|
+
let len3 = getDistManhattan(comL0.p, comL1.p0)
|
|
106
107
|
|
|
107
108
|
// check concaveness by area sign change
|
|
108
109
|
let area1 = getPolygonArea([comL0.p0, comL0.p, comL1.p0, comL1.p], false)
|
|
@@ -115,6 +116,7 @@ export function refineRoundedCorners(pathData, {
|
|
|
115
116
|
let bezThresh = len3*0.5 * tolerance
|
|
116
117
|
let isSmall = bezThresh < len1 && bezThresh < len2 ;
|
|
117
118
|
|
|
119
|
+
|
|
118
120
|
//len1 > len3 && len2 > len3
|
|
119
121
|
if (comBez.length && !signChange && isSmall ) {
|
|
120
122
|
|
|
@@ -125,17 +127,21 @@ export function refineRoundedCorners(pathData, {
|
|
|
125
127
|
|
|
126
128
|
// final check: mid point proximity
|
|
127
129
|
let ptM = pointAtT([comL0.p, ptQ, comL1.p0], 0.5)
|
|
128
|
-
//renderPoint(markers, ptM, 'red', '0.5%', '0.5')
|
|
129
130
|
|
|
130
131
|
let ptM_bez = comBez.length===1 ? pointAtT( [comBez[0].p0, comBez[0].cp1, comBez[0].cp2, comBez[0].p], 0.5 ) : comBez[0].p ;
|
|
131
132
|
|
|
132
|
-
let dist1 =
|
|
133
|
+
let dist1 = getDistManhattan(ptM, ptM_bez) * 0.75
|
|
134
|
+
|
|
135
|
+
//renderPoint(markers, ptM, 'red', '0.5%', '0.5')
|
|
136
|
+
//renderPoint(markers, ptM_bez, 'green', '0.5%', '0.5')
|
|
133
137
|
|
|
134
|
-
// not in tolerance –
|
|
135
|
-
if(dist1>len3){
|
|
138
|
+
// not in tolerance – return original command
|
|
139
|
+
if(bezThresh && dist1>bezThresh && dist1>len3*0.3){
|
|
136
140
|
//renderPoint(markers, ptM_bez, 'cyan', '0.5%', '0.5')
|
|
137
141
|
//renderPoint(markers, ptQ, 'magenta', '0.5%', '0.5')
|
|
138
142
|
pathDataN.push(com);
|
|
143
|
+
continue;
|
|
144
|
+
|
|
139
145
|
} else{
|
|
140
146
|
|
|
141
147
|
//renderPoint(markers, ptQ, 'magenta', '0.5%', '0.5')
|
|
@@ -148,6 +154,9 @@ export function refineRoundedCorners(pathData, {
|
|
|
148
154
|
// add quadratic command
|
|
149
155
|
pathDataN.push(comL0, comQ);
|
|
150
156
|
i += offset;
|
|
157
|
+
//i++
|
|
158
|
+
|
|
159
|
+
//offset++
|
|
151
160
|
continue;
|
|
152
161
|
}
|
|
153
162
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findSplitT, getExtrapolatedCommand } from "../pathData_simplify_cubic";
|
|
2
2
|
import { getCombinedByDominant } from "../pathData_simplify_cubic_extrapolate";
|
|
3
|
-
import { getDistAv, interpolate } from "./geometry";
|
|
3
|
+
import { bezierhasExtreme, checkLineIntersection, getDistAv, getDistManhattan, getSquareDistance, interpolate } from "./geometry";
|
|
4
4
|
import { getPathArea, getPolygonArea } from "./geometry_area";
|
|
5
5
|
import { getPathDataBBox } from "./geometry_bbox";
|
|
6
6
|
import { interpolatedPathData } from "./pathData_interpolate";
|
|
@@ -11,10 +11,14 @@ export function refineAdjacentExtremes(pathData, {
|
|
|
11
11
|
threshold = null, tolerance = 1
|
|
12
12
|
} = {}) {
|
|
13
13
|
|
|
14
|
+
//console.log('!!!refineAdjacentExtremes', pathData);
|
|
15
|
+
|
|
16
|
+
|
|
14
17
|
//dimA = dimA ? dimA :
|
|
15
18
|
if (!threshold) {
|
|
16
19
|
let bb = getPathDataBBox(pathData);
|
|
17
|
-
threshold = (bb.width + bb.height) / 2 * 0.05
|
|
20
|
+
//threshold = (bb.width + bb.height) / 2 * 0.05
|
|
21
|
+
threshold = (bb.width + bb.height) * 0.05
|
|
18
22
|
//console.log('new threshold', threshold);
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -32,29 +36,31 @@ export function refineAdjacentExtremes(pathData, {
|
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
// check dist
|
|
35
|
-
|
|
39
|
+
//threshold = threshold*1.05
|
|
40
|
+
let diff = comN ? getDistManhattan(p, comN.p) : Infinity;
|
|
36
41
|
let isCose = diff < threshold;
|
|
37
42
|
|
|
38
|
-
let diff2 = comN2 ?
|
|
39
|
-
let isCose2 = diff2 < threshold;
|
|
43
|
+
let diff2 = comN2 ? getDistManhattan(comN2.p, comN.p) : Infinity
|
|
44
|
+
let isCose2 = diff2 < threshold*1;
|
|
40
45
|
|
|
46
|
+
//let selfIntersecting = false
|
|
41
47
|
|
|
42
48
|
// next is extreme
|
|
43
|
-
if (comN && type === 'C' && comN.type === 'C' && extreme && comN2
|
|
49
|
+
if (comN && comN2 && type === 'C' && comN.type === 'C' && extreme && comN2.extreme) {
|
|
44
50
|
|
|
51
|
+
//renderPoint(markers, comN.p)
|
|
45
52
|
|
|
46
53
|
if (isCose2 || isCose) {
|
|
47
54
|
|
|
48
55
|
// extrapolate
|
|
49
56
|
let comEx = getCombinedByDominant(comN, comN2, threshold, tolerance, false)
|
|
50
|
-
//console.log('comEx', comEx);
|
|
51
|
-
//renderPoint(markers, comN.p)
|
|
52
57
|
|
|
53
58
|
if (comEx.length === 1) {
|
|
54
59
|
|
|
55
|
-
pathData[i + 1] = null;
|
|
56
60
|
comEx = comEx[0]
|
|
57
61
|
|
|
62
|
+
pathData[i + 1] = null;
|
|
63
|
+
|
|
58
64
|
pathData[i + 2].values = [comEx.cp1.x, comEx.cp1.y, comEx.cp2.x, comEx.cp2.y, comEx.p.x, comEx.p.y]
|
|
59
65
|
pathData[i + 2].cp1 = comEx.cp1
|
|
60
66
|
pathData[i + 2].cp2 = comEx.cp2
|
|
@@ -71,79 +77,22 @@ export function refineAdjacentExtremes(pathData, {
|
|
|
71
77
|
|
|
72
78
|
|
|
73
79
|
// short after extreme
|
|
74
|
-
|
|
75
|
-
if (comN && type === 'C' && comN.type === 'C' && extreme ) {
|
|
80
|
+
if (comN && type === 'C' && comN.type === 'C' && extreme) {
|
|
76
81
|
|
|
77
82
|
if (isCose) {
|
|
78
83
|
|
|
79
|
-
|
|
80
|
-
//renderPoint(markers, comN.p, 'cyan', '1%', '0.5')
|
|
81
|
-
//console.log(comN);
|
|
82
|
-
//console.log(diff, threshold);
|
|
83
|
-
|
|
84
|
-
let dx1 = (com.cp1.x - comN.p0.x)
|
|
85
|
-
let dy1 = (com.cp1.y - comN.p0.y)
|
|
86
|
-
|
|
87
|
-
let horizontal = Math.abs(dy1) < Math.abs(dx1);
|
|
88
|
-
|
|
89
|
-
let pN = comN.p;
|
|
90
|
-
let ptI;
|
|
91
|
-
let t = 1;
|
|
92
|
-
|
|
93
|
-
let area0 = getPolygonArea([com.p0, com.p , comN.p])
|
|
84
|
+
let area0 = getPolygonArea([com.p0, com.p, comN.p])
|
|
94
85
|
// cpts area
|
|
95
86
|
let area1 = getPolygonArea([com.p0, com.cp1, com.cp2, com.p])
|
|
96
87
|
|
|
97
88
|
// sign change: is corner => skip
|
|
98
|
-
if (
|
|
89
|
+
if ((area0 < 0 && area1 > 0) || (area0 > 0 && area1 < 0)) {
|
|
99
90
|
//renderPoint(markers, com.p, 'orange', '1%', '0.5')
|
|
100
91
|
continue;
|
|
101
92
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (comN.extreme) {
|
|
105
|
-
|
|
106
|
-
// extend cp2
|
|
107
|
-
if (horizontal) {
|
|
108
|
-
t = Math.abs(Math.abs(comN.cp2.x - comN.p.x) / Math.abs(com.cp2.x - com.p.x))
|
|
109
|
-
t = Math.min(1, t)
|
|
110
|
-
//console.log('t', t);
|
|
111
|
-
|
|
112
|
-
ptI = interpolate(comN.p, com.cp2, 1 + t)
|
|
113
|
-
com.cp2.x = ptI.x
|
|
114
|
-
//renderPoint(markers, com.cp2, 'cyan', '1%', '0.5')
|
|
115
|
-
//renderPoint(markers, ptI, 'orange', '1%', '0.5')
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
//renderPoint(markers, comN.p0, 'cyan', '1%', '0.5')
|
|
119
|
-
t = Math.abs(Math.abs(comN.cp2.y - comN.p.y) / Math.abs(com.cp2.y - com.p.y))
|
|
120
|
-
t = Math.min(1, t)
|
|
121
|
-
//console.log('t v', t);
|
|
122
|
-
|
|
123
|
-
ptI = interpolate(comN.p, com.cp2, 1 + t)
|
|
124
|
-
com.cp2.y = ptI.y
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
//merge commands
|
|
128
|
-
pathData[i + 1].values = [com.cp1.x, com.cp1.y, com.cp2.x, com.cp2.y, pN.x, pN.y]
|
|
129
|
-
pathData[i + 1].cp1 = com.cp1
|
|
130
|
-
pathData[i + 1].cp2 = com.cp2
|
|
131
|
-
pathData[i + 1].p0 = com.p0
|
|
132
|
-
pathData[i + 1].p = pN
|
|
133
|
-
pathData[i + 1].extreme = true
|
|
134
|
-
|
|
135
|
-
// nullify 1st
|
|
136
|
-
pathData[i] = null;
|
|
137
|
-
continue
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
93
|
}
|
|
142
94
|
}
|
|
143
95
|
|
|
144
|
-
/*
|
|
145
|
-
*/
|
|
146
|
-
|
|
147
96
|
|
|
148
97
|
}
|
|
149
98
|
|
|
@@ -175,21 +124,13 @@ export function refineAdjacentExtremes(pathData, {
|
|
|
175
124
|
|
|
176
125
|
|
|
177
126
|
|
|
178
|
-
let diff =
|
|
127
|
+
let diff = getDistManhattan(lastCom.p0, lastCom.p)
|
|
179
128
|
let isCose = diff < threshold;
|
|
180
129
|
|
|
181
130
|
|
|
182
131
|
if (penultimateCom && penultimateCom.type === 'C' && isCose && isClosingTo && fistExt) {
|
|
183
132
|
|
|
184
|
-
//let dx1 = Math.abs(fistExt.cp1.x - M.x)
|
|
185
|
-
//let dy1 = Math.abs(fistExt.cp1.y - M.y)
|
|
186
|
-
|
|
187
|
-
//let horizontal = dy1 < dx1;
|
|
188
|
-
//console.log(dx1, dx2);
|
|
189
|
-
//console.log('isCose', isCose, diff, dimA);
|
|
190
|
-
|
|
191
133
|
let comEx = getCombinedByDominant(penultimateCom, lastCom, threshold, tolerance, false)
|
|
192
|
-
//console.log('comEx', comEx);
|
|
193
134
|
|
|
194
135
|
if (comEx.length === 1) {
|
|
195
136
|
pathData[lastIdx - 1] = comEx[0];
|