Adricen
Adricen

Reputation: 33

Using Trigonometry to draw equidistant parralleles lines through a circle

enter image description here

As seen on the picture, I need a math formula that calculate the red circled point with cartesian coordonate that will make equidistant lines. It is not simple trigonometry I guess...

My goal is to be able to calculate cartesian point around half of the circle and trace my lines from it.

Using p5js, I'll use random value from Perlin noise mixing it with sin or cos (whatever...) to trace my lines from those points. At start it's a math problem, the rest should be pretty easy for me since I already have a good base that work, but need to be optimized with this math.

Any clue ?

Upvotes: 2

Views: 282

Answers (2)

Futurologist
Futurologist

Reputation: 1914

Given:

(x_cntr, y_cntr) = the center of the circle, 
radius = radius of the circle, 
dist = distance between lines, 
angle = angle of lines relative to the horizontal Ox axis, 
offset = distance of first line from the border of the circle:

here is another function that can do the job. This approach tries to avoid expensive calculations with cosine and arcsine in the loop and replace them with only one expensive calculation of sqrt. The rest are simple arithmetic operations (e.g. multiplication and addition). The idea is to calculate the locations of the points in the simple canonical case of equidistant horizontal lines running through a circle of the given radius and centred at the origin (0,0), and then rotate and translate the coordinates of the points to fit the boundary of the actual circle at the angle that the lines should define with respect to the horizontal axis Ox.

function get_points(x_cntr, y_cntr, radius, dist, angle, offset) {
    let list_of_points = [];
    let n = Math.floor( (2 * radius - offset) / dist ) + 1;
    let cos_angle = Math.cos(angle); 
    let sin_angle = Math.sin(angle);
    for (let m = 0; m < n; m = m+1) {
      let y = offset + m * dist - radius;
      let x = Math.sqrt(radius*radius - y*y);
      let point = [
          x_cntr + cos_angle * x - sin_angle * y,
          y_cntr + sin_angle * x + cos_angle * y
          ]
      list_of_points.push(point);
   }
   return list_of_points;
}

Upvotes: 0

trincot
trincot

Reputation: 350127

This is a matter of converting between angles (polar coordinates) and Cartesian coordinates.

Here is a function calculateLines(x, y, radius, dist, angle, shift) that takes the coordinate of the center, the radius of the circle, the distance between the lines, the angle of the lines (in radians), and the shift of the lines (perpendicular to their direction). It returns an array with segments. A segment is determined by a pair of coordinates, i.e. [x1, y1, x2, y2].

The below snippet allows you to play with these parameters and see the result interactively:

function calculateSegments(x, y, radius, dist, angle, shift=0) {
    let segments = [];
    for (let step = shift - Math.floor((radius + shift) / dist) * dist; step < radius; step += dist) {
        let polar = Math.acos(step / radius);
        let segment = [
            x + Math.cos(angle + polar) * radius,
            y + Math.sin(angle + polar) * radius,
            x + Math.cos(angle - polar) * radius,
            y + Math.sin(angle - polar) * radius
        ];
        segments.push(segment);
    }
    return segments;
}

// I/O management:

let [inpRadius, inpDistance, inpAngle, inpShift] = document.querySelectorAll("input");

document.addEventListener("input", refresh);

let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
let cx = canvas.width >> 1;
let cy = canvas.height >> 1;

function drawCircle(x, y, r) {
    ctx.beginPath();
    ctx.arc(x, y, r, 0, 2 * Math.PI, false);
    ctx.stroke();
}

function drawSegment([x1, y1, x2, y2]) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
}

function clear() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function refresh() {
    // Get current input
    let radius = Math.max(1, +inpRadius.value); // sanitise input
    let distance = Math.max(1, +inpDistance.value);
    let angle = +inpAngle.value * Math.PI / 180; // convert to radians
    let shift = +inpShift.value;
    
    // Perform the calculation
    let segments = calculateSegments(cx, cy, radius, distance, angle, shift);

    // Display result
    clear();
    drawCircle(cx, cy, radius);
    segments.forEach(drawSegment);
}

refresh();
input { width: 5em }
canvas { background: #eee }
<div style="float: left">
Radius of circle: <input type="number" id="radius" value="50" min="1"><br>
Distance between lines: <input type="number" id="distance" value="14" min="1"><br>
Angle of lines (degrees): <input type="number" id="angle" value="120"><br>
Shift: <input type="number" id="shift" value="0"><br>
</div>
<canvas width="180" height="180"></canvas>

Upvotes: 2

Related Questions