UNPKG

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