// ============================================ // DXF - AutoCAD R12 Export // ============================================ function svgToDxf(svgString, scaleFactor = 1) { const parser = new DOMParser(); const svg = parser.parseFromString(svgString, 'image/svg+xml').documentElement; const viewBox = svg.getAttribute('viewBox')?.split(' ').map(Number) || [0, 0, 64, 64]; const height = viewBox[3]; let entities = ''; function flipY(y) { return (height - y) * scaleFactor; } function scaleX(x) { return x * scaleFactor; } function processElement(el) { const tag = el.tagName?.toLowerCase(); if (!tag) return; switch(tag) { case 'line': const x1 = parseFloat(el.getAttribute('x1') || 0); const y1 = parseFloat(el.getAttribute('y1') || 0); const x2 = parseFloat(el.getAttribute('x2') || 0); const y2 = parseFloat(el.getAttribute('y2') || 0); entities += createDxfLine(scaleX(x1), flipY(y1), scaleX(x2), flipY(y2)); break; case 'rect': const rx = parseFloat(el.getAttribute('x') || 0); const ry = parseFloat(el.getAttribute('y') || 0); const rw = parseFloat(el.getAttribute('width') || 0); const rh = parseFloat(el.getAttribute('height') || 0); entities += createDxfLine(scaleX(rx), flipY(ry), scaleX(rx + rw), flipY(ry)); entities += createDxfLine(scaleX(rx + rw), flipY(ry), scaleX(rx + rw), flipY(ry + rh)); entities += createDxfLine(scaleX(rx + rw), flipY(ry + rh), scaleX(rx), flipY(ry + rh)); entities += createDxfLine(scaleX(rx), flipY(ry + rh), scaleX(rx), flipY(ry)); break; case 'circle': const cx = parseFloat(el.getAttribute('cx') || 0); const cy = parseFloat(el.getAttribute('cy') || 0); const r = parseFloat(el.getAttribute('r') || 0); entities += createDxfCircle(scaleX(cx), flipY(cy), r * scaleFactor); break; case 'ellipse': const ecx = parseFloat(el.getAttribute('cx') || 0); const ecy = parseFloat(el.getAttribute('cy') || 0); const erx = parseFloat(el.getAttribute('rx') || 0); const ery = parseFloat(el.getAttribute('ry') || 0); entities += createDxfCircle(scaleX(ecx), flipY(ecy), ((erx + ery) / 2) * scaleFactor); break; case 'polygon': case 'polyline': const points = el.getAttribute('points'); if (points) { const pts = points.trim().split(/[\s,]+/).map(Number); for (let i = 0; i < pts.length - 2; i += 2) { entities += createDxfLine( scaleX(pts[i]), flipY(pts[i+1]), scaleX(pts[i+2]), flipY(pts[i+3]) ); } if (tag === 'polygon' && pts.length >= 4) { entities += createDxfLine( scaleX(pts[pts.length-2]), flipY(pts[pts.length-1]), scaleX(pts[0]), flipY(pts[1]) ); } } break; case 'path': const d = el.getAttribute('d'); if (d) { const pathEntities = parseSvgPath(d, scaleX, flipY); entities += pathEntities; } break; case 'text': const tx = parseFloat(el.getAttribute('x') || 0); const ty = parseFloat(el.getAttribute('y') || 0); const textContent = el.textContent || ''; const fontSize = parseFloat(el.getAttribute('font-size') || 10); entities += createDxfText(scaleX(tx), flipY(ty), textContent, fontSize * scaleFactor * 0.7); break; case 'g': case 'svg': Array.from(el.children).forEach(child => processElement(child)); break; } } processElement(svg); const dxf = [ '0', 'SECTION', '2', 'HEADER', '9', '$ACADVER', '1', 'AC1009', '9', '$INSBASE', '10', '0.0', '20', '0.0', '30', '0.0', '9', '$EXTMIN', '10', '0.0', '20', '0.0', '30', '0.0', '9', '$EXTMAX', '10', String(height * scaleFactor), '20', String(height * scaleFactor), '30', '0.0', '0', 'ENDSEC', '0', 'SECTION', '2', 'TABLES', '0', 'TABLE', '2', 'LAYER', '70', '1', '0', 'LAYER', '2', '0', '70', '0', '62', '7', '6', 'CONTINUOUS', '0', 'ENDTAB', '0', 'ENDSEC', '0', 'SECTION', '2', 'ENTITIES', entities, '0', 'ENDSEC', '0', 'EOF' ].join('\r\n'); return dxf; } function createDxfLine(x1, y1, x2, y2) { return [ '0', 'LINE', '8', '0', '10', x1.toFixed(4), '20', y1.toFixed(4), '30', '0.0', '11', x2.toFixed(4), '21', y2.toFixed(4), '31', '0.0', '' ].join('\r\n'); } function createDxfCircle(cx, cy, r) { return [ '0', 'CIRCLE', '8', '0', '10', cx.toFixed(4), '20', cy.toFixed(4), '30', '0.0', '40', r.toFixed(4), '' ].join('\r\n'); } function createDxfText(x, y, text, height) { return [ '0', 'TEXT', '8', '0', '10', x.toFixed(4), '20', y.toFixed(4), '30', '0.0', '40', height.toFixed(4), '1', text, '' ].join('\r\n'); }