How change the spiral movement in 2D space? - geometry

I have two points in 2D space as we can see in the figure to move from the blue point to the red points we can use the equation (1). Where b is a constant used to limit the shape of the logarithmic spiral, l is a random number in [−1,1], which is used to
control the indentation effect of the movement, D indicates the distance between blue points and the current point
I need another movement that can move from blue points to the red points like in the figure

You can use sinusoidal model.
For start point (X0, Y0) and end point (X1,Y1) we have vector end-start, determine it's length - distance between points L, and angle of vector Fi (using atan2).
Then generate sinusoidal curve for some standard situation - for example, along OX axis, with magnitude A, N periods for distance 2 * Pi * N:
Scaled sinusoid in intermediate point with parameter t, where t is in range 0..1 (t=0 corresponds to start point (X0,Y0))
X(t) = t * L
Y(t) = A * Sin(2 * N * Pi * t)
Then shift and rotate sinusoid using X and Y calculated above
X_result = X0 + X * Cos(Fi) - Y * Sin(Fi)
Y_result = Y0 + X * Sin(Fi) + Y * Cos(Fi)
Example Python code:
import math
x0 = 100
y0 = 100
x1 = 400
y1 = 200
nperiods = 4
amp = 120
nsteps = 20
leng = math.hypot(x1 - x0, y1 - y0)
an = math.atan2(y1 - y0, x1 - x0)
arg = 2 * nperiods* math.pi
points = []
for t in range(1, nsteps + 1):
r = t / nsteps
xx = r * leng
yy = amp * math.sin(arg * r)
rx = x0 + xx * math.cos(an) - yy * math.sin(an)
ry = y0 + xx * math.sin(an) + yy * math.cos(an)
points.append([rx, ry])
print(points)
Draw points:

Related

Drawing markers on a quadratic curve

I am trying to place evenly-spaced markers/dots on a quadratic curve drawn with HTML Canvas API. Found a nice article explaining how the paths are calculated in the first place, at determining coordinates on canvas curve.
There is a formula, at the end, to calculate the angle:
function getQuadraticAngle(t, sx, sy, cp1x, cp1y, ex, ey) {
var dx = 2*(1-t)*(cp1x-sx) + 2*t*(ex-cp1x);
var dy = 2*(1-t)*(cp1y-sy) + 2*t*(ey-cp1y);
return Math.PI / 2 - Math.atan2(dx, dy);
}
The x/y pairs that we pass, are the current position, the control point and the end position of the curve - exactly what is needed to pass to the canvas context, and t is a value from 0 to 1. Unless I somehow misunderstood the referenced article.
I want to do something very similar - place my markers over the distance specified s, rather than use t. This means, unless I am mistaken, that I need to calculate the length of the "curved path" and from there, I could probably use the above formula.
I found a solution for the length in JavaScript at length of quadratic curve. The formula is similar to:
.
And added the below function:
function quadraticBezierLength(x1, y1, x2, y2, x3, y3) {
let a, b, c, d, e, u, a1, e1, c1, d1, u1, v1x, v1y;
v1x = x2 * 2;
v1y = y2 * 2;
d = x1 - v1x + x3;
d1 = y1 - v1y + y3;
e = v1x - 2 * x1;
e1 = v1y - 2 * y1;
c1 = a = 4 * (d * d + d1 * d1);
c1 += b = 4 * (d * e + d1 * e1);
c1 += c = e * e + e1 * e1;
c1 = 2 * Math.sqrt(c1);
a1 = 2 * a * (u = Math.sqrt(a));
u1 = b / u;
a = 4 * c * a - b * b;
c = 2 * Math.sqrt(c);
return (
(a1 * c1 + u * b * (c1 - c) + a * Math.log((2 * u + u1 + c1) / (u1 + c))) /
(4 * a1)
);
}
Now, I am trying to space markers evenly. I thought that making "entropy" smooth - dividing the total length by the step length would result in the n markers, so going using the 1/nth step over t would do the trick. However, this does not work. The correlation between t and distance on the curve is not linear.
How do I solve the equation "backwards" - knowing the control point, the start, and the length of the curved path, calculate the end-point?
Not sure I fully understand what you mean by "space markers evenly" but I do have some code that I did with curves and markers that maybe can help you ...
Run the code below, it should output a canvas like this:
function drawBezierCurve(p0, p1, p2, p3) {
distance = 0
last = null
for (let t = 0; t <= 1; t += 0.0001) {
const x = Math.pow(1 - t, 3) * p0[0] + 3 * Math.pow(1 - t, 2) * t * p1[0] + 3 * (1 - t) * Math.pow(t, 2) * p2[0] + Math.pow(t, 3) * p3[0];
const y = Math.pow(1 - t, 3) * p0[1] + 3 * Math.pow(1 - t, 2) * t * p1[1] + 3 * (1 - t) * Math.pow(t, 2) * p2[1] + Math.pow(t, 3) * p3[1];
ctx.lineTo(x, y);
if (last) {
distance += Math.sqrt((x - last[0]) ** 2 + (y - last[1]) ** 2)
if (distance >= 30) {
ctx.rect(x - 1, y - 1, 2, 2);
distance = 0
}
}
last = [x, y]
}
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
drawBezierCurve([0, 0], [40, 300], [200, -90], [300, 150]);
ctx.stroke();
<canvas id="canvas" width=300 height=150></canvas>
I created the drawBezierCurve function, there I'm using a parametric equation of a bezier curve and then I use lineTo to draw between points, and also we get a distance between points, the points are very close so my thinking is OK to use the Pythagorean theorem to calculate the distance, and the markers are just little rectangles.

(Tkinter, py3) How to make a rotation animation?

I want to rotate an oval around it's center. Currently I can display the static object witohut rotation, and I can't seem to find what to do wit it.
EDIT: I made a rotation function based on complex number multiplication, which seemed to work on lower polygons but the ellipse kinda looks the same.
A potato-level noob C.S. student.
also, the code:
from tkinter import*
import cmath, math
import time
def poly_rot(tup, deg):
rad=deg*0.0174533
crot=cmath.exp(rad*1j)
rotpol=[]
i=0
while i < len(tup):
x=tup[i]
y=tup[i+1]
z=crot*complex(x,y)
rotpol.append(400+z.real)
rotpol.append(400+z.imag)
i=i+2
return rotpol
def poly_oval(x0,y0, x1,y1, steps=60, rotation=0):
"""return an oval as coordinates suitable for create_polygon"""
# x0,y0,x1,y1 are as create_oval
# rotation is in degrees anti-clockwise, convert to radians
rotation = rotation * math.pi / 180.0
# major and minor axes
a = (x1 - x0) / 2.0
b = (y1 - y0) / 2.0
# center
xc = x0 + a
yc = y0 + b
point_list = []
# create the oval as a list of points
for i in range(steps):
# Calculate the angle for this step
# 360 degrees == 2 pi radians
theta = (math.pi * 2) * (float(i) / steps)
x1 = a * math.cos(theta)
y1 = b * math.sin(theta)
# rotate x, y
x = (x1 * math.cos(rotation)) + (y1 * math.sin(rotation))
y = (y1 * math.cos(rotation)) - (x1 * math.sin(rotation))
point_list.append(round(x + xc))
point_list.append(round(y + yc))
return point_list
inp= input("We need an ellipse. One to fit in a 800*800 window. Give the size of it's axes separated by ','-s (ex: lx,ly)!\n")
inpu= inp.split(',')
lx=int(inpu[0])
ly=int(inpu[1])
x0=400-lx//2
x1=400+lx//2
y0=400-ly//2
y1=400+ly//2
deg= float(input("Let's rotate this ellipse! But how much, in degrees, should we?"))
pre=poly_oval(x0, y0, x1, y1)
post=poly_rot(poly_oval(x0, y0, x1, y1), deg)
root =Tk()
w = Canvas(root, width=801, height=801)
w.config(background="dark green")
w.pack()
w.create_polygon(tuple(post), fill="yellow", outline="yellow" )
root.mainloop()

calculating parallel lines in a circle

I am calculating lines (2 sets of coordinates ) ( the purple and green-blue lines ) that are n perpendicular distance from an original line. (original line is pink ) ( distance is the green arrow )
How do I get the coordinates of the four new points?
I have the coordinates of the 2 original points and their angles. ( pink line )
I need it to work if the lines are vertical, or any other orientation.
Right now I am trying to calculate it by:
1. get new point n distance perpendicular to the two old points
2. find where the circle intersects the new line I have defined.
I feel like there is an easier way.
Similarly to #MBo's answer, let's assume that the center is (0,0) and that your initial two points are:
P0 = (x0, y0) and P1 = (x1, y1)
A point on the line P0P1 has the form:
(x, y) = c(x1 - x0, y1 - y0) + (x0, y0)
for some constant c.
Let (u, v) be the normal to the line P0P1:
(u, v) = (y1 - y0, x1 - x0) / sqrt((x1 - x0)^2 + (y1 - y0)^2)
A point on any of the lines parallel to P0P1 has the form:
(x, y) = c(x1 - x0, y1 - y0) + (x0, y0) +/- (u, v)* n {eq 1}
where n is the perpendicular distance between lines and c is a constant.
What remains here is to find the values of c such that (x,y) is on the circle. But these can be calculated by solving the following two quadratic equations:
(c(x1 - x0) + x0 +/- u*n)^2 + (c(y1 - y0) + y0 +/- v*n)^2 = r^2
where r is the radius. Note that these equations can be written as:
c^2(x1 - x0)^2 + 2c(x1 - x0)*(x0 +/- u*n) + (x0 +/- u*n)^2
+ c^2(y1 - y0)^2 + 2c(y1 - y0)*(y0 +/- v*n) + (y0 +/- v*n)^2 = r^2
or
A*c^2 + B*c + D = 0
where
A = (x1 - x0)^2 + (y1 - y0)^2
B = 2(x1 - x0)*(x0 +/- u*n) + 2(y1 - y0)*(y0 +/- v*n)
D = (x0 +/- u*n)^2 + (y0 +/- v*n)^2 - r^2
which are actually two quadratic equations one for each selection of the +/- signs. The 4 solutions of these two equations will give you the four values of c from which you will get the four points using {eq 1}
UPDATE
Here are the two quadratic equations (I've reused the letters A, B and C but they are different in each case):
A*c^2 + B*c + D = 0 {eq 2}
where
A = (x1 - x0)^2 + (y1 - y0)^2
B = 2(x1 - x0)*(x0 + u*n) + 2(y1 - y0)*(y0 + v*n)
D = (x0 + u*n)^2 + (y0 + v*n)^2 - r^2
A*c^2 + B*c + D = 0 {eq 3}
where
A = (x1 - x0)^2 + (y1 - y0)^2
B = 2(x1 - x0)*(x0 - u*n) + 2(y1 - y0)*(y0 - v*n)
D = (x0 - u*n)^2 + (y0 - v*n)^2 - r^2
Let's circle radius is R, circle center is (0,0) (if not, shift all coordinates to simplify math), first chord end is P0=(x0, y0), second chord end is P1=(x1,y1), unknown new chord end is P=(x,y).
Chord length L is
L = Sqrt((x1-x0)^2 + (y1-y0)^2)
Chord ends lie on the circle, so
x^2 + y^2 = R^2 {1}
Doubled area of triangle PP0P1 might be expressed as product of the base and height and through absolute value of cross product of two edge vectors, so
+/- L * n = (x-x0)*(y-y1)-(x-x1)*(y-y0) = {2}
x*y - x*y1 - x0*y + x0*y1 - x*y + x*y0 + x1*y - x1*y0 =
x * (y0-y1) + y * (x1-x0) + (x0*y1-x1*y0)
Solve system of equation {1} and {2}, find coordinates of new chord ends.
(Up to 4 points - two for +L*n case, two for -L*n case)
I cannot claim though that this method is simpler - {2} is essentially an equation of parallel line, and substitution in {1} is intersection with circle.

How can i define coordinates of rectangle if i know two middle coordinates?

coordinates of black points is known. width of rectangle is 10. how can i define all coordinates of rectangle?
http://i.stack.imgur.com/Sc2oz.jpg
Let's M0, M1 are black points.
//vector M0-M1
mx = M1.X - M0.X
my = M1.Y - M0.Y
//perpendicular vector
px = - my
py = mx
//it's length
lp =Sqrt(px*px + py*py)
//unit perp. vector
upx = px / lp
upy = py / lp
//vertices
V1.x = M0.X + 5 * upx
V1.y = M0.Y + 5 * upy
V2.x = M0.X - 5 * upx
V2.y = M0.Y - 5 * upy
//the same for M1 and V3, V4
By width = 10, I assume the shortest side has a width of 10. Half of its width is therefore 5.
Lets first find the vector going from L to R, then normalize it to have length 1 and stretch it to length 5. Lets call this vector A. A can be calculated as follows: A = 5*(R-L) / |R-L|.
Now, A can be rotated 90 degrees clockwise or counterclockwise and be applied to L, to obtain S or W, respectively.
In the same way, A can be rotated 90 degrees clockwise or counter clockwise and be applied to R, to botain E or N, respectively.
That is:
S = L + A * Rotate(-90)
W = L + A * Rotate(90)
E = R + A * Rotate(-90)
N = R + A * Rotate(90)
where Rotate(x) is the rotation matrix for rotating a vector x degrees counter clockwise, as defined in https://en.wikipedia.org/wiki/Rotation_matrix
The complete calculations:
Ax = 5 * (Rx-Lx) / sqrt((Rx-Lx)^2 + (Ry-Ly)^2)
Ay = 5 * (Ry-Ly) / sqrt((Rx-Lx)^2 + (Ry-Ly)^2)
S = (Lx + Ay, Ly - Ax)
W = (Lx - Ay, Ly + Ax)
E = (Rx + Ay, Ry - Ax)
N = (Rx - Ay, Ry + Ax)

Line Segment Circle Intersection

I am trying to determine the point at which a line segment intersect a circle. For example, given any point between P0 and P3 (And also assuming that you know the radius), what is the easiest method to determine P3?
Generally,
find the angle between P0 and P1
draw a line at that angle from P0 at a distance r, which will give you P3
In pseudocode,
theta = atan2(P1.y-P0.y, P1.x-P0.x)
P3.x = P0.x + r * cos(theta)
P3.y = P0.y + r * sin(theta)
From the center of the circle and the radius you can write the equation describing the circle.
From the two points P0 and P1 you can write the equation describing the line.
So you have 2 equations in 2 unknowns, which you can solved through substitution.
Let (x0,y0) = coordinates of the point P0
And (x1,y1) = coordinates of the point P1
And r = the radius of the circle.
The equation for the circle is:
(x-x0)^2 + (y-y0)^2 = r^2
The equation for the line is:
(y-y0) = M(x-x0) // where M = (y1-y0)/(x1-x0)
Plugging the 2nd equation into the first gives:
(x-x0)^2*(1 + M^2) = r^2
x - x0 = r/sqrt(1+M^2)
Similarly you can find that
y - y0 = r/sqrt(1+1/M^2)
The point (x,y) is the intersection point between the line and the circle, (x,y) is your answer.
P3 = (x0 + r/sqrt(1+M^2), y0 + r/sqrt(1+1/M^2))
Go for this code..its save the time
private boolean circleLineIntersect(float x1, float y1, float x2, float y2, float cx, float cy, float cr ) {
float dx = x2 - x1;
float dy = y2 - y1;
float a = dx * dx + dy * dy;
float b = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
float c = cx * cx + cy * cy;
c += x1 * x1 + y1 * y1;
c -= 2 * (cx * x1 + cy * y1);
c -= cr * cr;
float bb4ac = b * b - 4 * a * c;
// return false No collision
// return true Collision
return bb4ac >= 0;
}
You have a system of equations. The circle is defined by: x^2 + y^2 = r^2. The line is defined by y = y0 + [(y1 - y0) / (x1 - x0)]·(x - x0). Substitute the second into the first, you get x^2 + (y0 + [(y1 - y0) / (x1 - x0)]·(x - x0))^2 = r^2. Solve this and you'll get 0-2 values for x. Plug them back into either equation to get your values for y.
MATLAB CODE
function [ flag] = circleLineSegmentIntersection2(Ax, Ay, Bx, By, Cx, Cy, R)
% A and B are two end points of a line segment and C is the center of
the circle, % R is the radius of the circle. THis function compute
the closest point fron C to the segment % If the distance to the
closest point > R return 0 else 1
Dx = Bx-Ax;
Dy = By-Ay;
LAB = (Dx^2 + Dy^2);
t = ((Cx - Ax) * Dx + (Cy - Ay) * Dy) / LAB;
if t > 1
t=1;
elseif t<0
t=0;
end;
nearestX = Ax + t * Dx;
nearestY = Ay + t * Dy;
dist = sqrt( (nearestX-Cx)^2 + (nearestY-Cy)^2 );
if (dist > R )
flag=0;
else
flag=1;
end
end

Resources