Align end of lines of ellipse on top of rectangle border

39 Views Asked by At

I know the question includes source code but the problem itself is purely mathematical, so maybe this is the right place anyway

I have the following code to draw circles, squares, ellipses and (wrong) rectangles with equal angle sections. Circles, squares and ellipses work fine, but what i want to achieve with the rectangle code is that the end of the sections lines don't end on the border of the ellipsis but on the border of the rectangle. Using the same code as I am using for the square isn't working because the lines will get stretched and the angles are wrong afterwards.

The ellipsis I am drawing looks like this, the orange lines show how the lines should be when I select the rectangle version ("R"):

ellipsis with rectangle lines

Code to get points for the current angle for the ellipsis, circle, square and rectangle This will be called in a loop to get all points and draw lines between the coordinates.

const a = width * 0.5;
const b = height * 0.5;
let x;
let y;

const ro =
    pieChartKind === 'E' || pieChartKind === 'R'
        ? (a * b) /
          Math.sqrt((b * Math.cos(currentAngle)) ** 2 + (a * Math.sin(currentAngle)) ** 2)
        : 1;

const factor =
    pieChartKind === 'S' || pieChartKind === 'R'
        ? Math.sqrt(1.0) /
          Math.max(
                Math.abs(ro * Math.cos(currentAngle)),
                Math.abs(ro * Math.sin(currentAngle)),
          )
        : 1;

if (pieChartKind === 'E') {
    x = factor * ro * Math.cos(currentAngle) + width * 0.5;
    y = factor * ro * Math.sin(currentAngle) + height * 0.5;
} else {
    x = factor * ro * Math.cos(currentAngle) * a + width * 0.5;
    y = factor * ro * Math.sin(currentAngle) * b + height * 0.5;
}

return { x, y };
1

There are 1 best solutions below

1
On BEST ANSWER

Answer

Let:

  • $O_x$ be the $x$-coordinate of the rectangle's center,
  • $O_y$ be the $y$-coordinate of the rectangle's center,
  • $l$ be the length of the rectangle (length of the horizontal sides),
  • $w$ be the width of the rectangle (length of the vertical sides),
  • $a$ be the angle in radians, between some line starting from the center and ending on the side of a rectangle, and the positive $x$-axis, where the positive angle is in the anti-clockwise direction,
  • $\mathrm{arctan}(y, x)$ be the function that outputs the angle formed between the positive $x$-axis, and the line segment from $(O_x, O_y)$ to $(x, y)$ between -π and π radians, where the positive angle is in the anti-clockwise direction

The function, $f(O_x, O_y, l, w, a)$ that gives the endpoint of the line, $\begin{bmatrix} x\\y \end{bmatrix}$, that touches the rectangle, is: $$ f(O_x, O_y, l, w, a)= \begin{cases} \begin{bmatrix} O_x \\ O_y + w \end{bmatrix}, a=π/2 \\ \begin{bmatrix} O_x \\ O_y - w \end{bmatrix}, a=-π/2 \\ \begin{bmatrix} O_x - \frac{w}{\tan a} \\ O_y - w \end{bmatrix}, \mathrm{arctan}(-w, -l) ≤ a < \mathrm{arctan}(-w, l) \cap a≠-\frac{π}{2} \\ \begin{bmatrix} O_x + l \\ O_y + l \tan a \end{bmatrix}, \mathrm{arctan}(-w, l) ≤ a < \mathrm{arctan}(w, l) \\ \begin{bmatrix} O_x + \frac{w}{\tan a} \\ O_y + w \end{bmatrix}, \mathrm{arctan}(w, l) ≤ a < \mathrm{arctan}(w, -l) \cap a≠\frac{π}{2}\\ \begin{bmatrix} O_x - l \\ O_y - l \tan a \end{bmatrix}, \mathrm{arctan}(w, -l) ≤ a < π \cup \mathrm{arctan}(-w, -l) ≤ a < -π \end{cases} $$

Derivation

The function can be derived from right-angle trigonometry; see this in Desmos for right triangles formed in each case.


For implementation details with regards to programming, folks in Stack Overflow can help you better. This answer may be extended for more detailed derivation.