JavaScript - rotate SVG based line's angle - javascript

I draw the line on Canvas and want to merge svg image on line based it's position. How can I find the angle between start and end points of draw line?
Edit
This function for get Angle of Line
public angleOfWall(p1,p2){
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
return angleDeg;
}
var angleOfWall = this.angleOfWall(closestWall.getStart(), closestWall.getEnd());
After find the angle, I want to merge img to on it.
for (let i = 0; i < this.model.floorplan.items.length; i++) {
item = this.model.floorplan.items[i];
var hover = item===this.viewmodel.activeItem;
var itemWidth = item.width|32;
var itemHeight = item.height|32;
if (!item.el) {
item.el = document.createElement('img');
// draw door line on that position
item.el.src = this.model.floorplan.items[i].model_url_2d;
item.el.onload = (( /** image **/ ) => {
this.context.drawImage(item.el,
this.viewmodel.convertX(item.xpos * item.scale_x) - itemWidth/2.,
this.viewmodel.convertY(item.zpos * item.scale_z) - itemHeight/2.,
itemWidth, itemHeight);
}
.("model_url2d" is SVG image's url )
private rotateSVG(rotateSVG) {
var innerArrow = document.getElementById("#add-items");
innerArrow.setAttribute("transform", rotateSVG);
}
Is it right way to follow line rotate position? Just Im new in JS side so need some help. thanks
here What I have now
but want to rotate img angle as line's angle

IMPORTANT: This answer addresses the question as of revision 1
This is the content of the question I answered:
"I draw the line on Canvas and want to merge svg image on line based it's position. How can I find the angle between start and end points of draw line?"
Given 2 points p1 and p2 you may calculate the angle between start and end points of the line drawn from p1 to p2 using the atan2 method.
If you consider the line as the hypotenuse and the distance in x (dx) & y (dy) as catheti you can write: let angle = Math.atan2(dy, dx);. This will give you the angle in radians. If you need the angle in degrees you have to: let angleInDegrees = angle*180/Math.PI
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 300,
cx = cw / 2;
let ch = canvas.height = 300,
cy = ch / 2;
// given 2 points: p1 and p2
let p1 = {x:50, y:200},
p2= {x:200, y:50}
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
//the distance in x & y between the 2 points
let dx = p2.x - p1.x;
let dy = p2.y - p1.y;
// the angle in radians
let angle = Math.atan2(dy, dx);
// the angle in degrees
console.log(angle*180/Math.PI)
canvas{border:1px solid #d9d9d9;}
<canvas></canvas>
I hope this helps.

Related

Drawing diagonal lines at an angle within a rectangle

I'm trying to fill a rectangle with diagonal lines at 30 degrees that don't get clipped by the canvas. Each line should start and end on the edges of the canvas, but do not go outside the canvas.
I've gotten somewhat of a result but is struggling to understand how I can fix the ends so the lines become evenly distributed:
Here is the code I got so far:
const myCanvas = document.getElementById("myCanvas");
const _ctx = myCanvas.getContext("2d");
const canvasWidth = 600;
const canvasHeight = 300;
// Helper function
const degToRad = (deg) => deg * (Math.PI / 180);
const angleInDeg = 30;
const spaceBetweenLines = 16;
const lineThickness = 16;
_ctx.fillStyle = `black`;
_ctx.fillRect(0, 0, canvasWidth, canvasHeight);
const step = (spaceBetweenLines + lineThickness) / Math.cos(angleInDeg * (Math.PI / 180));
for (let distance = -canvasHeight + step; distance < canvasWidth; distance += step) {
let x = 0;
let y = 0;
if(distance < 0) {
// Handle height
y = canvasHeight - (distance + canvasHeight);
} else {
// Handle height
x = distance;
}
const lineLength = canvasHeight - y;
const slant = lineLength / Math.tan(degToRad((180 - 90 - angleInDeg)));
const x2 = Math.min(x + slant, canvasWidth);
const y2 = y + lineLength;
_ctx.beginPath();
_ctx.moveTo(x, y);
_ctx.lineTo(x2, y2);
_ctx.lineWidth = lineThickness;
_ctx.strokeStyle = 'green';
_ctx.stroke();
}
and a JSFiddle for the code.
What I'm trying to achieve is drawing a pattern where I can control the angle of the lines, and that the lines are not clipped by the canvas. Reference photo (the line-ends don't have flat):
Any help?
My example is in Javascript, but it's more the logic I'm trying to wrap my head around. So I'm open to suggestions/examples in other languages.
Update 1
If the angle of the lines is 45 degree, you will see the gutter becomes correct on the left side. So I'm suspecting there is something I need to do differently on my step calculations.
My current code is based on this answer.
Maybe try something like this for drawing the lines
for(var i = 0; i < 20; i++){
_ctx.fillrect(i * spaceBetweenLines + lineThickness, -100, canvas.height + 100, lineThickness)
}

how i get a coordinate of each rectangle?

i have tried this,
public drawNumbers(ctx, x1, y1, length, count) {
let angle = 0;
for (let i = 0; i <= count; i++ ) {
angle += 2 * Math.PI / (count );
const x2 = x1 + length * Math.cos(angle),
y2 = y1 + length * Math.sin(angle);
ctx.beginPath();
ctx.fillRect(x2, y2, 10, 20);
ctx.stroke();
}
}
this.canvas.drawNumbers(ctx, this.midX, this.midY, 160, 60);
output:
expected result:
i want to calculate a four coordinate(rectangle) of rotated axis.
How do i detect click event on each rectangle?
Using setTransform
Salix alba answer is a solution though a few too many steps.
It can be done in a single transform using setTransform and applying the translate and rotations in one step. Also the second translation is where you draw the box relative to its origin. When using transforms always draw objects around the center of rotation.
ctx.strokeRect(-10,-10,20,20); // rotation is always around 0,0
const ctx = canvas.getContext("2d");
const centerX = 250;
const centerY = 250;
const radius = 200;
const boxWidth = 10;
const bobLength = 20;
// draw boxs around circle center at cx,cy and radius rad
// box width bw, and box height bh
// spacing optional is the distance between boxes
function drawCircleOfBoxes(cx,cy,rad,bw,bh,spacing = 5){
var steps = ((rad - bw /2) * Math.PI * 2) / (bw + spacing) | 0; // get number boxes that will fit circle
ctx.beginPath();
for(var i = 0; i < steps; i ++){
const ang = (i / steps) * Math.PI * 2;
var xAxisX = Math.cos(ang); // get the direction of he xAxis
var xAxisY = Math.sin(ang);
// set the transform to circle center x Axis out towards box
// y axis at 90 deg to x axis
ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, cx, cy);
// draw box offset from the center so its center is distance radius
ctx.rect(rad - bh / 2, -bw / 2, bh, bw);
}
ctx.fill();
ctx.stroke();
ctx.setTransform(1,0,0,1,0,0); // reset transform
}
ctx.fillStyle = "#FCD";
ctx.strokeStyle = "#000";
drawCircleOfBoxes(centerX, centerY, radius, boxWidth, bobLength);
<canvas id="canvas" width="500" height="500"></canvas>
Manually apply the transform to a point
If you wish to transform the box in code you can use the transform applied in the above and apply it directly to a set of points. You can not apply it to the ctx.rect function that needs the API transform.
To transform a point px,py you need the the direction of the rotated x axis
const xAx = Math.cos(dirOfXAxis);
const xAy = Math.sin(dirOfXAxis);
You can then move the point px distance along the xAxis and then turn 90 deg and move py distance along the y axis
var x = px * xAx; // move px dist along x axis
var y = px * xAy;
x += py * -xAy; // move px dist along y axis
y += py * xAx;
Then just add the translation
x += translateX;
y += translateY;
Or done in one go
var x = px * xAx - py * xAy + translateX; // move px dist along x axis
var y = px * xAy + py * xAx + translateY;
The snippet shows it in action
const ctx = canvas.getContext("2d");
const centerX = 250;
const centerY = 250;
const radius = 200;
const boxWidth = 10;
const boxLength = 20;
// draw boxs around circle center at cx,cy and radius rad
// box width bw, and box height bh
// spacing optional is the distance between boxes
function drawCircleOfBoxes(cx,cy,rad,bw,bh,spacing = 5){
var points = [ // setout points of box with coord (0,0) as center
{x : bh / 2, y : -bw / 2},
{x : bh / 2 + bh, y : -bw / 2},
{x : bh / 2 + bh, y : -bw / 2 + bw},
{x : bh / 2, y : -bw / 2 + bw},
];
var steps = (((rad - bw /2) * Math.PI * 2) / (bw + spacing) )+ 4| 0; // get number boxes that will fit circle
ctx.beginPath();
for(var i = 0; i < steps; i ++){
const ang = (i / steps) * Math.PI * 2;
const xAx = Math.cos(ang); // get the direction of he xAxis
const xAy = Math.sin(ang);
var first = true
for(const p of points){ // for each point
// Apply the transform to the point after moving it
// to the circle (the p.x + rad)
const x = (p.x + rad) * xAx - p.y * xAy + cx;
const y = (p.x + rad) * xAy + p.y * xAx + cy;
if(first){
ctx.moveTo(x,y);
first = false;
}else{
ctx.lineTo(x,y);
}
}
ctx.closePath();
}
ctx.fill();
ctx.stroke();
}
ctx.fillStyle = "#CFD";
ctx.strokeStyle = "#000";
for(var i = boxLength + 5; i < radius; i += boxLength + 5){
drawCircleOfBoxes(centerX, centerY, i , boxWidth, boxLength);
}
<canvas id="canvas" width="500" height="500"></canvas>
To get rotated rectangles you need to use the transform() method of the graphics context.
Imagine a set of axis at the top left of the drawing area. Any drawing will be done relative to these axis which we can move with transform.
To translate by xshift, yshift
ctx.transform(1,0,0,1, xshift, yshift);
ctx.fillRect(0,0,100,100);
To rotate by angle ang in radians
ctx.transform(Math.cos(ang),Math.sin(ang),
-Math.sin(ang),Math.cos(ang), 0,0);
We can combine things with three transformations. The first moves the origin to the center of the circle. Then rotate the axes about this point,
then shift the axes to where you want the shape to appear. Finally, draw the shape.
for(deg = 0; deg < 360; deg+=20) {
ctx.setTransform(1,0,0,1,0,0); // reset transformation
ang = deg * Math.PI/180;
ctx.transform(1,0,0,1,100,100); // shift origin
ctx.transform(Math.cos(ang),Math.sin(ang),
-Math.sin(ang),Math.cos(ang), 0,0);
ctx.transform(1,0,0,1,50,0);
ctx.fillRect(0,0,30,10);
}
You can achieve the same this using the translate and rotate
for(deg = 0; deg < 360; deg+=20) {
ctx.setTransform(1,0,0,1,0,0); // reset transformation
ang = deg * Math.PI/180;
ctx.translate(100,100); // shift origin
ctx.rotate(ang);
ctx.translate(50,0);
ctx.fillRect(0,0,30,10);
}

Apply noise on circle according to mouseX and mouseY

I have created a blob with small points. I want my blob to show noise on its surface according to mouseX and mouseY. I want it to show high noise in the quadrant in which the mouse lies. I want it to be wavy. Below is my code.
var ctx = document.querySelector("canvas").getContext("2d");
var cx = 200;
var cy = 200;
var radius = 50;
var amp = 2;
var mouseX = 0;
var mouseY = 0;
document.querySelector("canvas").addEventListener("mousemove", function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
function drawTheBlob() {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, 400, 400);
ctx.beginPath();
ctx.strokeStyle = "#fff";
for (var a = 0; a < 360; a ++) {
var angle = a * Math.PI/180;
var x = cx + radius * Math.cos(angle) + Math.random() * amp;
var y = cy + radius * Math.sin(angle) + Math.random() * amp;
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.closePath();
requestAnimationFrame(drawTheBlob);
}
drawTheBlob();
<canvas width="400" height="400"></canvas>
Adds a sin wave on the circle. Use ctx.arc to draw the flat part of the circle for speed as drawing many circles with lines will be slow. See code for comments on what is done.
var ctx = document.querySelector("canvas").getContext("2d");
ctx.lineWidth = 3;
ctx.lineJoin = "round";
var cx = 100;
var cy = 100;
var radius = 50;
var mouseX = 0;
var mouseY = 0;
const quadWidth = Math.PI / 2; // area of effect PI/2 is 90 degree
const steps = radius / quadWidth; // number steps around the circle matches 1 pixel per step,
const noiseAmpMax = 5; // in pixels
const noiseWaveMoveSpeed = 2; // speed of waves on circle in radians per second
const noiseWaveFreq = 16; // how many waves per 360 deg
document.querySelector("canvas").addEventListener("mousemove", function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
function drawTheBlob(time) { // time is passed from the requestAnimationFrame call
var amp = 0; // amplitude of noise
var wavePos = ((time / 1000) * Math.PI) * noiseWaveMoveSpeed;
var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, 400, 400);
ctx.beginPath();
ctx.strokeStyle = "#fff";
ctx.fillStyle = "red";
// draw arc for parts that have no noise as it is a log quicker
ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);
for (var a = 0; a < 1; a += 1 / steps) {
var angle = (mouseDir - quadWidth / 2) + a * quadWidth;
var angDist = Math.abs(angle - mouseDir); // find angular distance from mouse
// as a positive value, it does not mater
// what the sign is
if (angDist < quadWidth / 2) { // is angle distance within the range of effect
// normalise the distance (make it 0 to 1)
amp = 1 - angDist / (quadWidth / 2);
} else {
amp = 0; // no noise
}
// amp will be zero if away from mouse direction and 0 to 1 the closer to
// mouse angle it gets.
// add a sin wave to the radius and scale it by amp
var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp;
var x = cx + dist * Math.cos(angle);
var y = cy + dist * Math.sin(angle);
ctx.lineTo(x, y);
}
ctx.closePath(); // use close path to close the gap (only needed if you need to draw a line from the end to the start. It is not needed to match beginPath
ctx.fill();
ctx.stroke();
requestAnimationFrame(drawTheBlob);
}
requestAnimationFrame(drawTheBlob); // start this way so that you get the time argument
<canvas width="200" height="200"></canvas>
How it works.
Mouse direction
First we need the direction from the circle to the mouse. To do that we use the function Math.atan2 It takes the vector from the circle to the mouse and returns the direction in radians. The function is a little weird as it takes y first, then x.
var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);
Draw arc to save CPU time
Now that we have the direction to the mouse we can draw the parts of the circle that has no noise using arc .
ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);
The variable quadWidth is angular size of the noise bit so from the mouseDir we add half that angular width and draw the arc around to mouseDir plus 360deg take half the quadWidth.
Quick word on Radians
Almost all programming languages use radians to define angles, 360deg is equal to 2 * PI or 2 * 3.1415, which can be hard to get your head around, but there is good reason to use radians. For now just remember that a full circle in radians is 2 * Math.PI = 360deg, Math.PI = 180deg, Math.PI / 2 = 90deg, Math.PI / 4 = 45Deg and Math.PI / 180 = 1deg. You dont have to remember the digits just Math.PI is half a circle.
quadWidth from above is a constant defined as const quadWidth = Math.PI / 2; which is 90deg.
The for loop
The for loop only draws the (Math.PI / 2) 90deg section around the mouseDir, from 45 deg left to 45 right. or whatever you set quadWidth to.
for (var a = 0; a < 1; a += 1 / steps) {
I loop from 0 to 1 the number of steps that give a reasonably smooth curve. We can find what part of the noisy arc we are drawing by multiplying the value a *
quadWidth and adding that to the mouseDir - quadWidth / 2. This means that we start at mouseDir - 45deg and move clock wise to mouseDir + 45deg
var angle = (mouseDir - quadWidth / 2) + a * quadWidth;
Next i find how far that angle is from the mouseDir (could optimize it here a bit here but this way is a little more flexible, if you want to draw more noise on the other part of the arc)
var angDist = Math.abs(angle - mouseDir);
If that number is less than quadWidth / 2 convert the value to the range 0 to 1 where 0 is at the angle furthest from the mouse direction and 1 closest.
if (angDist < quadWidth / 2) {
amp = 1 - angDist / (quadWidth / 2);
} else {
amp = 0;
}
The sin wave
Now we calculate the radius of the circle at the current angle and add a sin wave to it. First the radius then the sin wave multiplied by the amp calculated in the last step. Where amp is zero none of the sin wave is added, where amp is 1 (in the direction of the mouse) the full sin wave is added.
var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp
The values wavePos, noiseWaveFreq, and noiseAmpMax control the animation of the sin wave. Play around with these values to get a feel of what they do, wavePos is calculated based on the time at the start of the function.
With dist we can calculate the x,y position for the next line of the circle
var x = cx + dist * Math.cos(angle);
var y = cy + dist * Math.sin(angle);
ctx.lineTo(x, y);
Experiment
I added some constants
const quadWidth = Math.PI / 2; // area of effect PI/2 is 90 degree
const steps = radius / quadWidth; // number steps around the circle matches 1 pixel per step,
const noiseAmpMax = 5; // in pixels
const noiseWaveMoveSpeed = 2; // speed of waves on circle in radians per second
const noiseWaveFreq = 16; // how many waves per 360 deg
To get a understanding what they do experiment and change the numbers to see what happens.

Stretch image to fit polygon html5 canvas

I have a square image like this:
I am trying to stretch this image into a polygon like this:
So far I have been able to create a polygon on the canvas as the above image using the following javascript:
function drawCanvas() {
var c2 = document.getElementById('myCanvas6').getContext('2d');
var img = document.getElementById("scream");
c2.fillStyle = '#000';
c2.beginPath();
c2.moveTo(20, 20);
c2.lineTo(320, 50);
c2.lineTo(320, 170);
c2.lineTo(20, 200);
//c2.drawImage(img, 150, 10, img.width, img.height);
c2.closePath();
c2.fill();
}
I tried using drawImage() method, but it does not stretch the points A, B, C, D to the new positions. Is there anyway this can be achieved?
The 2D canvas is called 2D for a very good reason. You can not transform a square such that any of its side converge (are not parallel) hence 2D
But where there is a need there is always a way..
You can do it by cutting the image into slices and then draw each slice slightly smaller than the last.
We humans don't like to see an image distort when it converges, so you need to add the distortion we expect, perspective. The further away the object the smaller the distance between points appears to the eye.
So the function below draws an image with the top and bottom edges converging..
It is not true 3D but it does make the image appear as distorted as jus converging the top and bottom without decreasing the y step. The animation introduced a bit of an optical illusion. the second render shortens the image to make it appear a little less fake.
See the code on how to use the function.
/** CreateImage.js begin **/
// creates a blank image with 2d context
var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
/** CreateImage.js end **/
var can = createImage(512,512);
document.body.appendChild(can);
var ctx = can.ctx;
const textToDisplay = "Perspective"
const textSize = 80;
ctx.font = textSize+"px arial";
var w = ctx.measureText(textToDisplay).width + 8;
var text = createImage(w + 64,textSize + 32);
text.ctx.fillStyle = "#08F";
text.ctx.strokeStyle = "black";
text.ctx.lineWidth = 16;
text.ctx.fillRect(0,0,text.width,text.height);
text.ctx.strokeRect(0,0,text.width,text.height);
text.ctx.font = textSize+"px arial";
text.ctx.fillStyle = "#F80";
text.ctx.strokeStyle = "Black";
text.ctx.lineWidth = 4;
text.ctx.strokeText(textToDisplay,38,textSize + 8);
text.ctx.fillText(textToDisplay,38,textSize + 8);
// Not quite 3D
// ctx is the context to draw to
// image is the image to draw
// x1,x2 left and right edges of the image
// zz1,zz2 top offset for left and right
// image top edge has a slops from zz1 to zz2
// yy if the position to draw top. This is where the top would be if z = 0
function drawPerspective(ctx, image, x1, zz1, x2, zz2, yy){
var x, w, h, h2,slop, topLeft, botLeft, zDistR, zDistL, lines, ty;
w = image.width; // image size
h = image.height;
h2 = h /2; // half height
slop = (zz2 - zz1) / (x2 - x1); // Slope of top edge
z1 = h2 - zz1; // Distance (z) to first line
z2 = (z1 / (h2 - zz2)) * z1 - z1; // distance (z) between first and last line
if(z2 === 0){ // if no differance in z then is square to camera
topLeft = - x1 * slop + zz1; // get scan line top left edge
ctx.drawImage(image,0, 0, w, h,x1, topLeft + yy ,x2-x1, h - topLeft * 2) // render to desination
return;
}
// render each display line getting all pixels that will be on that line
for (x = x1; x < x2; x++) { // for each line horizontal line
topLeft = (x - x1) * slop + zz1; // get scan line top left edge
botLeft = ((x + 1) - x1) * slop + zz1; // get scan line bottom left edge
zDistL = (z1 / (h2 - topLeft)) * z1; // get Z distance to Left of this line
zDistR = (z1 / (h2 - botLeft)) * z1; // get Z distance to right of this line
ty = ((zDistL - z1) / z2) * w; // get y bitmap coord
lines = ((zDistR - z1) / z2) * w - ty;// get number of lines to copy
ctx.drawImage(image,
ty % w, 0, lines, h, // get the source location of pixel
x, topLeft + yy,1 , h - topLeft * 2 // render to desination
);
}
}
var animTick = 0;
var animRate = 0.01;
var pos = 0;
var short = 0;
function update1(){
animTick += animRate;
pos = Math.sin(animTick) * 20 + 20;
short = Math.cos((pos / 40) * Math.PI) * text.width * 0.12 - text.width * 0.12;
ctx.clearRect(0,0,can.width,can.height)
drawPerspective(ctx,text,0,0,text.width,pos,20)
drawPerspective(ctx,text,0,0,text.width+short,pos,textSize + 32 + 30)
requestAnimationFrame(update1);
}
update1();
I think this is a good solution for you: http://jsfiddle.net/fQk4h/
Here is the magic:
for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
i, 0, 1, h,
i, dy, 1, dh);
}
ctx.restore();

aligning n-circels on a circle > no overlapping

for a data visualization im aligning n-circels on a circle.
That just works fine - but i dont't know how to stop the circles
overlapping each other. Anybody here knows howto?
The result should work like this sketch:
Link: http://www.xup.to/dl,79345003/sketch.jpg
So i dont know how to calculate the angle for the second node
- based on the radius an position of the first node - and the
radius of the second ...
JSFIDDLE to show what i mean: http://jsfiddle.net/0z9hyvxk/
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
canvas.width = 500;
canvas.height = 500;
var midx = 250;
var midy = 250;
var radius = 200;
var angle = 0;
var count = 30;
var step = 2 * Math.PI / count;
var xpos;
var ypos;
var nodeSize;
var node = function(size){
var dot = new createjs.Shape();
dot.graphics.beginFill("#000").drawCircle(0, 0, size);
dot.x = dot.y = -5;
dot.alpha = .25;
return dot
};
for(var i = 0; i<count; i++)
{
xpos = radius * Math.cos(angle) + midx;
ypos = radius * Math.sin(angle) + midx;
nodeSize = i;
var n = new node(nodeSize);
n.x = xpos;
n.y = ypos;
stage.addChild(n)
angle += step;
}
stage.update();
thanks in advance
simon
Your program does not make corrections based on circle sizes and angle. Smaller circles are too far from each other, bigger ones are too close.
r1 = radius of the n-th small circle
r2 = radius of the (n+1)-th small circle.
r3 = radius of the (n+2)-th small circle
r1<r2<3, so angle between 1 and 2 is smaller than between 2 and 3.
Try to tangentially increase angle correction. I can't test code at work :(

Categories

Resources