Davtho1983
Davtho1983

Reputation: 3954

Improve trig calculation precision in JS

I have this code for a JS graphic that is supposed to draw three circles and no matter what their radiuses, their edges should always touch.

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function App() {
  //circles[0] = r1
  //circles[1] = r2
  //circles[2] = r3

  const circles = [40, 30, 20];
  const colours = ["green", "blue", "red"];


  let circle2xPos =
    2 * Math.sqrt(circles[0] * circles[1]) + circles[0]; // What Dr E has

  let r1r2 = circles[0] + circles[1];
  let r1r3 = circles[0] + circles[2];
  let r2r3 = circles[1] + circles[2];
    
   let newAngle = Math.atan2(r1r2,r1r3)
  let ycoord = Math.cos(newAngle) * r1r3
  let xcoord = Math.sin(newAngle) * r1r2 + circles[0]

  const getCircleY = index => {
    let yPos = 0;
    if (index === 2) {
      yPos = h
    }
    return yPos;
  };

  const getCircleX = (index, x) => {
    let xPos = 0;

    console.log(circles);
    for (let i = 0; i < index + 1; i++) {
      console.log(circles[i]);
      if (i === 0) {
        xPos = circles[1];
      } else if (i === 1) {
        xPos = circle2xPos;
        console.log("xPos", xPos);
      } else if (i === 2) {
        xPos = xcoord + circles[0]
      }
    }
    return xPos;
  };

  const getCircles = () => {
    return circles.map((item, index) => (
      <div
        className="circle"
        style={{
          position: "absolute",
          top: getCircleY(index),
          left: getCircleX(index, getCircleY(index)),
          height: 2 * item,
          width: 2 * item,
          padding: 0,
          margin: 0,
          backgroundColor: colours[index],
          borderRadius: "50%"
        }}
      />
    ));
  };
  return (
    <div className="App">
      <div className="circles">{getCircles()}</div>
    </div>
  );
}

It works sortof - the first two always touch, but the next circle only ends up in the right place sometimes.

I have tried lots of different ways to calculate the coords of the third circle and I always manage to find a solution for particular values, but I don't seem to be able to generalise so it will work with any numbers? It doesn't seem just to be about keeping cos or sin between 1 and -1 so the arc function doesn't return NaN, sometimes the trig values seem off and the third circle is in the wrong place.

For the second circle it would be ideal to start at (x,y) = (r1, 2r1+r3) (with radii directly in line with the y axis so circle 2 is stacked dead centre on top of circle 1), then rotate circle 2 around the centre of circle 1 until it meets the edge of circle 3 - how would I do that?

latest

Upvotes: 0

Views: 128

Answers (1)

ControlAltDel
ControlAltDel

Reputation: 35096

In your circles array, you have 40,30, 20. Below that, you have r1r2 = circle[0] + circles[1] so these appear to be radii, correct?

Assuming the above is correct, the proper way to go about this is:

Start point 1 at the origin(0,0) (you can translate all points later if you wish), and start point 2 on the x axis (r1 + r2, 0)

Pt3 is going to be r1 + r2 distance away from Pt1, and should be at angle atan(r2+ r1/r3 + r1), or just atan2(r2 + r1,r3 + r1);

I believe that should work

Upvotes: 1

Related Questions