Search code examples
javascriptmathellipse

How to divide an ellipse to equal angle segments?


the following code is creating svg paths to split a circle into 8 or 24 sections with the same angle at the center of the circle. The factor is only used to create paths that end at the border of the outer rectangle so we end up having a rectangle around the end of all paths.

function get8Or24PiePath(is24Pie, pieChartKind, width, height, customAngle) {
    let resultPath = '';
    const maxIndex = is24Pie ? 12 : 4;
    const circleAngleStep = (2 * Math.PI) / (maxIndex * 2);
    const additionalIndexValue = (customAngle / 360) * (maxIndex * 2);

    for (let index = 0; index < maxIndex; index++) {
        if (!is24Pie || (index + 2) % 3 !== 0) {
            const fromIndex = index + 0.5 + additionalIndexValue;
            const toIndex = fromIndex + maxIndex;
            const factorFrom =
                pieChartKind === 'S' || pieChartKind === 'R'
                    ? Math.sqrt(1.0) /
                      Math.max(
                            Math.abs(Math.cos(circleAngleStep * fromIndex)),
                            Math.abs(Math.sin(circleAngleStep * fromIndex)),
                      )
                    : 1;
            const factorTo =
                pieChartKind === 'S' || pieChartKind === 'R'
                    ? Math.sqrt(1.0) /
                      Math.max(
                            Math.abs(Math.cos(circleAngleStep * toIndex)),
                            Math.abs(Math.sin(circleAngleStep * toIndex)),
                      )
                    : 1;
            const xFrom =
                factorFrom * Math.cos(circleAngleStep * fromIndex) * (width * 0.5) + width * 0.5;
            const yFrom =
                factorFrom * Math.sin(circleAngleStep * fromIndex) * (height * 0.5) + height * 0.5;
            const xTo =
                factorTo * Math.cos(circleAngleStep * toIndex) * (width * 0.5) + width * 0.5;
            const yTo =
                factorTo * Math.sin(circleAngleStep * toIndex) * (height * 0.5) + height * 0.5;

            resultPath += `M ${xFrom} ${yFrom} L ${xTo} ${yTo} `;
        }
    }

    return resultPath;
}

Circle Example

But if I use the same calculation for an ellipse it will stretch the lines and the angles at the center of the ellipse arent equal anymore. What do I need to change to get the desired behaviour?

Ellipse Example


Solution

  • Seems you calculate circle circumference points, then squeeze coordinates - yes, in this case angles become wrong.

    Instead calculate points at ellipse (Polar form relative to center here)

    enter image description here

    enter image description here

    ro(theta) = a * b / sqrt(a^2*sin^2(theta) + b^2*cos^2(theta))   
    x(theta) = ro * cos(theta)
    y(theta) = ro * sin(theta)