I am working on creating a custom converter from svg to dxf and need a math wizard to help me figure out where my logic is flawed.
Here is my current code:
function svgArcToLWPolyline(rx, ry, rotation, largeArcFlag, sweepFlag, x1, y1, x2, y2) {
const scaleX = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / (2 * rx);
const scaleY = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / (2 * ry);
const arcInfo = svgArcToOvalArc(rx * scaleX, ry * scaleY, rotation, largeArcFlag, sweepFlag, x1, y1, x2, y2);
const numPoints = calculateNumberOfPoints(rx * scaleX, ry * scaleY, arcInfo.startAngle, arcInfo.endAngle);
// Calculate bulge factors
const bulgeFactors = [];
const angleIncrement = (arcInfo.endAngle - arcInfo.startAngle) / (numPoints - 1);
let currentAngle = arcInfo.startAngle;
for (let i = 0; i < numPoints - 1; i++) {
const nextAngle = currentAngle + angleIncrement;
const bulge = Math.tan((nextAngle - currentAngle) * Math.PI / 360);
bulgeFactors.push(bulge);
currentAngle = nextAngle;
}
bulgeFactors.push(0); // Last point has zero bulge
// Construct LWPOLYLINE points
const lwpolylinePoints = [];
for (let i = 0; i < numPoints; i++) {
const angle = arcInfo.startAngle + i * angleIncrement;
const x = arcInfo.cx + rx * scaleX * Math.cos(angle * Math.PI / 180);
const y = arcInfo.cy + ry * scaleY * Math.sin(angle * Math.PI / 180);
lwpolylinePoints.push([x, y, bulgeFactors[i]]);
}
return lwpolylinePoints;
}
function svgArcToOvalArc(rx, ry, rotation, largeArcFlag, sweepFlag, x1, y1, x2, y2) {
// Convert rotation angle to radians
const angle = rotation * Math.PI / 180;
// Calculate intermediate values
const dx = (x1 - x2) / 2;
const dy = (y1 - y2) / 2;
const x1p = Math.cos(angle) * dx + Math.sin(angle) * dy;
const y1p = -Math.sin(angle) * dx + Math.cos(angle) * dy;
const rxSq = rx * rx;
const rySq = ry * ry;
const x1pSq = x1p * x1p;
const y1pSq = y1p * y1p;
let radicand = (rxSq * rySq - rxSq * y1pSq - rySq * x1pSq) / (rxSq * y1pSq + rySq * x1pSq);
// Ensure non-negative radicand
if (radicand < 0) {
radicand = 0;
}
// Calculate root
let root = Math.sqrt(radicand);
if (largeArcFlag === sweepFlag) {
root = -root;
}
const cxp = root * rx * y1p / ry;
const cyp = -root * ry * x1p / rx;
// Calculate center
const cx = Math.cos(angle) * cxp - Math.sin(angle) * cyp + (x1 + x2) / 2;
const cy = Math.sin(angle) * cxp + Math.cos(angle) * cyp + (y1 + y2) / 2;
// Calculate start and end angles
let startAngle = Math.atan2((y1p - cyp) / ry, (x1p - cxp) / rx);
let endAngle = Math.atan2((-y1p - cyp) / ry, (-x1p - cxp) / rx);
// Convert angles to degrees
startAngle *= 180 / Math.PI;
endAngle *= 180 / Math.PI;
// Adjust angles to be in the range [0, 360]
if (startAngle < 0) {
startAngle += 360;
}
if (endAngle < 0) {
endAngle += 360;
}
return { cx: cx, cy: cy, startAngle: startAngle, endAngle: endAngle };
}
function calculateNumberOfPoints(rx, ry, startAngle, endAngle) {
// Calculate arc length
let arcLength;
if (startAngle <= endAngle) {
arcLength = (endAngle - startAngle) * Math.PI / 180;
} else {
arcLength = (360 - startAngle + endAngle) * Math.PI / 180;
}
arcLength *= (rx + ry) / 2;
// Choose a fixed length for each segment
const segmentLength = 1.0; // Adjust as needed
// Calculate the number of points
const numPoints = Math.max(Math.floor(arcLength / segmentLength), 2); // Minimum of 2 points
return numPoints;
}
Here is what the svg looks like using d=”M10,10L20,25A1,3,0,0,0,50,50L90,90V80Z”
enter image description here
And here is my dxf (don’t worry that it’s upside down
enter image description here
As you can see, the ry and rx aren’t being taken into account. And when I change my path to add a xRotationalAxis, my dxf breaks even more: d=”M10,10L20,25A1,3,45,0,0,50,50L90,90V80Z”:
SVG:
enter image description here
DXF:
enter image description here
I’ve spent 12 hours trying to tweek this and figure out mathmatically how to make it work (with a lot of help from ChatGPT) So any help I can get on this would be really nice!