1 | const { geometries, primitives, transforms } = require('@jscad/modeling')
|
2 |
|
3 | const { svg2cagX, svg2cagY, cagLengthX, cagLengthY, cagLengthP, reflect } = require('./helpers')
|
4 |
|
5 |
|
6 | const shapesMapGeometry = (obj, objectify, params) => {
|
7 | const { svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, target, segments } = params
|
8 |
|
9 | const types = {
|
10 | group: (obj) => objectify({ target, segments }, obj),
|
11 |
|
12 | rect: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments) => {
|
13 | let x = cagLengthX(obj.x, svgUnitsPmm, svgUnitsX)
|
14 | let y = (0 - cagLengthY(obj.y, svgUnitsPmm, svgUnitsY))
|
15 | const w = cagLengthX(obj.width, svgUnitsPmm, svgUnitsX)
|
16 | const h = cagLengthY(obj.height, svgUnitsPmm, svgUnitsY)
|
17 | const rx = cagLengthX(obj.rx, svgUnitsPmm, svgUnitsX)
|
18 |
|
19 |
|
20 | let shape
|
21 | if (w > 0 && h > 0) {
|
22 | x = (x + (w / 2)).toFixed(4)
|
23 | y = (y - (h / 2)).toFixed(4)
|
24 | if (rx === 0) {
|
25 | shape = transforms.center({ center: [x, y, 0] }, primitives.rectangle({ size: [w, h] }))
|
26 | } else {
|
27 | shape = transforms.center({ center: [x, y, 0] }, primitives.roundedRectangle({ segments, size: [w, h], roundRadius: rx }))
|
28 | }
|
29 | if (target === 'path') {
|
30 | shape = geometries.path2.fromPoints({ closed: true }, geometries.geom2.toPoints(shape))
|
31 | }
|
32 | }
|
33 | return shape
|
34 | },
|
35 |
|
36 | circle: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments) => {
|
37 | const x = cagLengthX(obj.x, svgUnitsPmm, svgUnitsX)
|
38 | const y = (0 - cagLengthY(obj.y, svgUnitsPmm, svgUnitsY))
|
39 | const r = cagLengthP(obj.radius, svgUnitsPmm, svgUnitsV)
|
40 |
|
41 | let shape
|
42 | if (r > 0) {
|
43 | shape = transforms.center({ center: [x, y, 0] }, primitives.circle({ segments, radius: r }))
|
44 | if (target === 'path') {
|
45 | shape = geometries.path2.fromPoints({ closed: true }, geometries.geom2.toPoints(shape))
|
46 | }
|
47 | }
|
48 | return shape
|
49 | },
|
50 |
|
51 | ellipse: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments) => {
|
52 | const rx = cagLengthX(obj.rx, svgUnitsPmm, svgUnitsX)
|
53 | const ry = cagLengthY(obj.ry, svgUnitsPmm, svgUnitsY)
|
54 | const cx = cagLengthX(obj.cx, svgUnitsPmm, svgUnitsX)
|
55 | const cy = (0 - cagLengthY(obj.cy, svgUnitsPmm, svgUnitsY))
|
56 |
|
57 | let shape
|
58 | if (rx > 0 && ry > 0) {
|
59 | shape = transforms.center({ center: [cx, cy, 0] }, primitives.ellipse({ segments, radius: [rx, ry] }))
|
60 | if (target === 'path') {
|
61 | shape = geometries.path2.fromPoints({ closed: true }, geometries.geom2.toPoints(shape))
|
62 | }
|
63 | }
|
64 | return shape
|
65 | },
|
66 |
|
67 | line: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV) => {
|
68 | const x1 = cagLengthX(obj.x1, svgUnitsPmm, svgUnitsX)
|
69 | const y1 = (0 - cagLengthY(obj.y1, svgUnitsPmm, svgUnitsY))
|
70 | const x2 = cagLengthX(obj.x2, svgUnitsPmm, svgUnitsX)
|
71 | const y2 = (0 - cagLengthY(obj.y2, svgUnitsPmm, svgUnitsY))
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | const shape = primitives.line([[x1, y1], [x2, y2]])
|
83 | if (target === 'geom2') {
|
84 |
|
85 | }
|
86 | return shape
|
87 | },
|
88 |
|
89 | polygon: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY) => {
|
90 | const points = []
|
91 | for (let j = 0; j < obj.points.length; j++) {
|
92 | const p = obj.points[j]
|
93 | if ('x' in p && 'y' in p) {
|
94 | const x = cagLengthX(p.x, svgUnitsPmm, svgUnitsX)
|
95 | const y = (0 - cagLengthY(p.y, svgUnitsPmm, svgUnitsY))
|
96 | points.push([x, y])
|
97 | }
|
98 | }
|
99 | if (target === 'geom2') {
|
100 | return geometries.geom2.fromPoints(points)
|
101 | }
|
102 | return geometries.path2.fromPoints({}, points)
|
103 | },
|
104 |
|
105 | polyline: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV) => {
|
106 | const points = []
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | for (let j = 0; j < obj.points.length; j++) {
|
117 | const p = obj.points[j]
|
118 | if ('x' in p && 'y' in p) {
|
119 | const x = cagLengthX(p.x, svgUnitsPmm, svgUnitsX)
|
120 | const y = (0 - cagLengthY(p.y, svgUnitsPmm, svgUnitsY))
|
121 | points.push([x, y])
|
122 | }
|
123 | }
|
124 |
|
125 | const shape = primitives.line(points)
|
126 | if (target === 'geom2') {
|
127 |
|
128 |
|
129 | }
|
130 | return shape
|
131 | },
|
132 |
|
133 | path: (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments) => {
|
134 | const listofpaths = expandPath(obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments)
|
135 |
|
136 | const listofentries = Object.entries(listofpaths).sort((a, b) => a[0].localeCompare(b[0]))
|
137 | const shapes = listofentries.map((entry) => {
|
138 | const path = entry[1]
|
139 | if (target === 'geom2' && path.isClosed) {
|
140 | const points = geometries.path2.toPoints(path).slice()
|
141 | points.push(points[0])
|
142 | return geometries.geom2.fromPoints(points)
|
143 | }
|
144 | return path
|
145 | })
|
146 | return shapes
|
147 | }
|
148 | }
|
149 |
|
150 | return types[obj.type](obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments)
|
151 | }
|
152 |
|
153 | module.exports = shapesMapGeometry
|
154 |
|
155 | const expandPath = (obj, svgUnitsPmm, svgUnitsX, svgUnitsY, svgUnitsV, svgGroups, segments) => {
|
156 | const paths = {}
|
157 | const on = 'path'
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | let sx = 0
|
170 | let sy = 0
|
171 | let cx = 0
|
172 | let cy = 0
|
173 | let pi = 0
|
174 | let pathName = on + pi
|
175 | let pc = false
|
176 | let bx = 0
|
177 | let by = 0
|
178 | let qx = 0
|
179 | let qy = 0
|
180 |
|
181 | for (let j = 0; j < obj.commands.length; j++) {
|
182 | const co = obj.commands[j]
|
183 | const pts = co.p
|
184 |
|
185 | switch (co.c) {
|
186 | case 'm':
|
187 |
|
188 | if (j === 0) {
|
189 | cx = 0; cy = 0
|
190 | }
|
191 |
|
192 | if (pi > 0 && pc === false) {
|
193 |
|
194 | }
|
195 |
|
196 | if (pts.length >= 2) {
|
197 | cx = cx + parseFloat(pts.shift())
|
198 | cy = cy + parseFloat(pts.shift())
|
199 | pi++
|
200 | pathName = on + pi
|
201 | pc = false
|
202 | paths[pathName] = geometries.path2.fromPoints({ }, [[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]])
|
203 | sx = cx; sy = cy
|
204 | }
|
205 |
|
206 | while (pts.length >= 2) {
|
207 | cx = cx + parseFloat(pts.shift())
|
208 | cy = cy + parseFloat(pts.shift())
|
209 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
210 | }
|
211 | break
|
212 | case 'M':
|
213 |
|
214 | if (pi > 0 && pc === false) {
|
215 |
|
216 | }
|
217 |
|
218 | if (pts.length >= 2) {
|
219 | cx = parseFloat(pts.shift())
|
220 | cy = parseFloat(pts.shift())
|
221 | pi++
|
222 | pathName = on + pi
|
223 | pc = false
|
224 | paths[pathName] = geometries.path2.fromPoints({ }, [[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]])
|
225 | sx = cx; sy = cy
|
226 | }
|
227 |
|
228 | while (pts.length >= 2) {
|
229 | cx = parseFloat(pts.shift())
|
230 | cy = parseFloat(pts.shift())
|
231 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
232 | }
|
233 | break
|
234 | case 'a':
|
235 | while (pts.length >= 7) {
|
236 | const rx = parseFloat(pts.shift())
|
237 | const ry = parseFloat(pts.shift())
|
238 | const ro = 0 - parseFloat(pts.shift()) * 0.017453292519943295
|
239 | const lf = (pts.shift() === '1')
|
240 | const sf = (pts.shift() === '1')
|
241 | cx = cx + parseFloat(pts.shift())
|
242 | cy = cy + parseFloat(pts.shift())
|
243 | paths[pathName] = geometries.path2.appendArc({ segments, endpoint: [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)], radius: [svg2cagX(rx, svgUnitsPmm), svg2cagY(ry, svgUnitsPmm)], xaxisrotation: ro, clockwise: sf, large: lf }, paths[pathName])
|
244 | }
|
245 | break
|
246 | case 'A':
|
247 | while (pts.length >= 7) {
|
248 | const rx = parseFloat(pts.shift())
|
249 | const ry = parseFloat(pts.shift())
|
250 | const ro = 0 - parseFloat(pts.shift()) * 0.017453292519943295
|
251 | const lf = (pts.shift() === '1')
|
252 | const sf = (pts.shift() === '1')
|
253 | cx = parseFloat(pts.shift())
|
254 | cy = parseFloat(pts.shift())
|
255 | paths[pathName] = geometries.path2.appendArc({ segments, endpoint: [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)], radius: [svg2cagX(rx, svgUnitsPmm), svg2cagY(ry, svgUnitsPmm)], xaxisrotation: ro, clockwise: sf, large: lf }, paths[pathName])
|
256 | }
|
257 | break
|
258 | case 'c':
|
259 | while (pts.length >= 6) {
|
260 | const x1 = cx + parseFloat(pts.shift())
|
261 | const y1 = cy + parseFloat(pts.shift())
|
262 | bx = cx + parseFloat(pts.shift())
|
263 | by = cy + parseFloat(pts.shift())
|
264 | cx = cx + parseFloat(pts.shift())
|
265 | cy = cy + parseFloat(pts.shift())
|
266 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(x1, svgUnitsPmm), svg2cagY(y1, svgUnitsPmm)], [svg2cagX(bx, svgUnitsPmm), svg2cagY(by, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
267 | const rf = reflect(bx, by, cx, cy)
|
268 | bx = rf[0]
|
269 | by = rf[1]
|
270 | }
|
271 | break
|
272 | case 'C':
|
273 | while (pts.length >= 6) {
|
274 | const x1 = parseFloat(pts.shift())
|
275 | const y1 = parseFloat(pts.shift())
|
276 | bx = parseFloat(pts.shift())
|
277 | by = parseFloat(pts.shift())
|
278 | cx = parseFloat(pts.shift())
|
279 | cy = parseFloat(pts.shift())
|
280 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(x1, svgUnitsPmm), svg2cagY(y1, svgUnitsPmm)], [svg2cagX(bx, svgUnitsPmm), svg2cagY(by, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
281 | const rf = reflect(bx, by, cx, cy)
|
282 | bx = rf[0]
|
283 | by = rf[1]
|
284 | }
|
285 | break
|
286 | case 'q':
|
287 | while (pts.length >= 4) {
|
288 | qx = cx + parseFloat(pts.shift())
|
289 | qy = cy + parseFloat(pts.shift())
|
290 | cx = cx + parseFloat(pts.shift())
|
291 | cy = cy + parseFloat(pts.shift())
|
292 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
293 | const rf = reflect(qx, qy, cx, cy)
|
294 | qx = rf[0]
|
295 | qy = rf[1]
|
296 | }
|
297 | break
|
298 | case 'Q':
|
299 | while (pts.length >= 4) {
|
300 | qx = parseFloat(pts.shift())
|
301 | qy = parseFloat(pts.shift())
|
302 | cx = parseFloat(pts.shift())
|
303 | cy = parseFloat(pts.shift())
|
304 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
305 | const rf = reflect(qx, qy, cx, cy)
|
306 | qx = rf[0]
|
307 | qy = rf[1]
|
308 | }
|
309 | break
|
310 | case 't':
|
311 | while (pts.length >= 2) {
|
312 | cx = cx + parseFloat(pts.shift())
|
313 | cy = cy + parseFloat(pts.shift())
|
314 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [cx, cy]] }, paths[pathName])
|
315 | const rf = reflect(qx, qy, cx, cy)
|
316 | qx = rf[0]
|
317 | qy = rf[1]
|
318 | }
|
319 | break
|
320 | case 'T':
|
321 | while (pts.length >= 2) {
|
322 | cx = parseFloat(pts.shift())
|
323 | cy = parseFloat(pts.shift())
|
324 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(qx, svgUnitsPmm), svg2cagY(qy, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
325 | const rf = reflect(qx, qy, cx, cy)
|
326 | qx = rf[0]
|
327 | qy = rf[1]
|
328 | }
|
329 | break
|
330 | case 's':
|
331 | while (pts.length >= 4) {
|
332 | const x1 = bx
|
333 | const y1 = by
|
334 | bx = cx + parseFloat(pts.shift())
|
335 | by = cy + parseFloat(pts.shift())
|
336 | cx = cx + parseFloat(pts.shift())
|
337 | cy = cy + parseFloat(pts.shift())
|
338 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(x1, svgUnitsPmm), svg2cagY(y1, svgUnitsPmm)], [svg2cagX(bx, svgUnitsPmm), svg2cagY(by, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
339 | const rf = reflect(bx, by, cx, cy)
|
340 | bx = rf[0]
|
341 | by = rf[1]
|
342 | }
|
343 | break
|
344 | case 'S':
|
345 | while (pts.length >= 4) {
|
346 | const x1 = bx
|
347 | const y1 = by
|
348 | bx = parseFloat(pts.shift())
|
349 | by = parseFloat(pts.shift())
|
350 | cx = parseFloat(pts.shift())
|
351 | cy = parseFloat(pts.shift())
|
352 | paths[pathName] = geometries.path2.appendBezier({ segments, controlPoints: [[svg2cagX(x1, svgUnitsPmm), svg2cagY(y1, svgUnitsPmm)], [svg2cagX(bx, svgUnitsPmm), svg2cagY(by, svgUnitsPmm)], [svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]] }, paths[pathName])
|
353 | const rf = reflect(bx, by, cx, cy)
|
354 | bx = rf[0]
|
355 | by = rf[1]
|
356 | }
|
357 | break
|
358 | case 'h':
|
359 | while (pts.length >= 1) {
|
360 | cx = cx + parseFloat(pts.shift())
|
361 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
362 | }
|
363 | break
|
364 | case 'H':
|
365 | while (pts.length >= 1) {
|
366 | cx = parseFloat(pts.shift())
|
367 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
368 | }
|
369 | break
|
370 | case 'l':
|
371 | while (pts.length >= 2) {
|
372 | cx = cx + parseFloat(pts.shift())
|
373 | cy = cy + parseFloat(pts.shift())
|
374 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
375 | }
|
376 | break
|
377 | case 'L':
|
378 | while (pts.length >= 2) {
|
379 | cx = parseFloat(pts.shift())
|
380 | cy = parseFloat(pts.shift())
|
381 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
382 | }
|
383 | break
|
384 | case 'v':
|
385 | while (pts.length >= 1) {
|
386 | cy = cy + parseFloat(pts.shift())
|
387 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
388 | }
|
389 | break
|
390 | case 'V':
|
391 | while (pts.length >= 1) {
|
392 | cy = parseFloat(pts.shift())
|
393 | paths[pathName] = geometries.path2.appendPoints([[svg2cagX(cx, svgUnitsPmm), svg2cagY(cy, svgUnitsPmm)]], paths[pathName])
|
394 | }
|
395 | break
|
396 | case 'z':
|
397 | case 'Z':
|
398 | paths[pathName] = geometries.path2.close(paths[pathName])
|
399 | cx = sx
|
400 | cy = sy
|
401 | pc = true
|
402 | break
|
403 | default:
|
404 | console.log('Warning: Unknow PATH command [' + co.c + ']')
|
405 | break
|
406 | }
|
407 |
|
408 | }
|
409 | return paths
|
410 | }
|