How can I find a point Q on line segment CD such that point P is projected perpendicularly from line segment AB onto line segment CD? So far I have only come across orthogonal projection ONTO another line segment but I want to do an orthogonal projection FROM a line segment. AB and CD are non-perpendicular and non-collinear.
Known:
Line segment 1: A(X,Y) to B(X,Y)
Line segment 2: C(X,Y) to D(X,Y)
Point to project: P(X,Y)
Unknown:
Q(X,Y)
See Image
Let vector
CD = D - C
In parametric form point Q at segment CD:
Q = C + t * CD (1)
Vector PQ
PQ = Q - P = C + t * CD - P
it is perpendicular to AB or AP, so dot product is zero
(C + t * (D - C) - P).dot.(P - A) = 0
Now solve this equation for unknown parameter t
t = (AP.dot.CP) / (AP.dot.CD)
and get point Q using (1)
Python example:
def backproj(ax, ay, px, py, cx, cy, dx, dy):
cdx = dx - cx
cdy = dy - cy
apx = px - ax
apy = py - ay
denom = cdx*apx+cdy*apy
if denom == 0:
return None #case of perpendicular segments
t = (apx*(px-cx)+apy*(py-cy)) / denom
if t < 0 or t > 1:
return None #case of point outside CD segment
qx = cx + cdx * t
qy = cy + cdy * t
return qx, qy
print(backproj(0, 0, 1, 0, 0, 1, 0, 5))
print(backproj(0, 0, -1, 0, 0, 1, 4, 5))
print(backproj(0, 0, 1, 0, 0, 1, 4, 5))
>>>
None
None
(1.0, 2.0)
Equation of AB:
(yB - yA)
y = yA + --------- (x - xA)
(xB - xA)
Equation of CD:
(yD - yC)
y = yC + --------- (x - xC)
(xD - xC)
Equation of PQ: orthogonal to AB
(xA - xB)
y = yP + --------- (x - xP)
(yB - yA)
Point Q is at intersection of CD and PQ; solving the system of two equations (2) and (3), you get the value of xQ, then the value of yQ by replacing x by xQ in equation (3).
Related
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.
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:
I am working through the book "Hands-on Machine Learning with Scikit-Learn and TensorFlow" by Aurélien Géron. The code below is written in Python 3.
On the GitHub page for the Chap. 5 solutions to the Support Vector Machine problems there is the following code for plotting the SVC decision boundary (https://github.com/ageron/handson-ml/blob/master/05_support_vector_machines.ipynb):
def plot_svc_decision_boundary(svm_clf, xmin, xmax):
w = svm_clf.coef_[0]
b = svm_clf.intercept_[0]
# At the decision boundary, w0*x0 + w1*x1 + b = 0
# => x1 = -w0/w1 * x0 - b/w1
x0 = np.linspace(xmin, xmax, 200)
decision_boundary = -w[0]/w[1] * x0 - b/w[1]
margin = 1/w[1]
gutter_up = decision_boundary + margin
gutter_down = decision_boundary - margin
svs = svm_clf.support_vectors_
plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='#FFAAAA')
plt.plot(x0, decision_boundary, "k-", linewidth=2)
plt.plot(x0, gutter_up, "k--", linewidth=2)
plt.plot(x0, gutter_down, "k--", linewidth=2)
My question is why is the margin defined as 1/w[1]? I believe the margin should be 1/sqrt(w[0]^2+w[1]^2). That is, the margin is half of 2/L_2_norm(weight_vector) which is 1/L_2_norm(weight_vector). See https://math.stackexchange.com/questions/1305925/why-does-the-svm-margin-is-frac2-mathbfw.
Is this an error in the code?
Given:
decision boundary: w0*x0 + w1*x1 + b = 0
gutter_up: w0*x0 + w1*x1 + b = 1, i.e. w0*x0 + w1*(x1 - 1/w1) + b = 0
gutter_down: w0*x0 + w1*x1 + b = -1, i.e. w0*x0 + w1*(x1 + 1/w1) + b = 0
corresponding to (x0, x1) in decision boundary line, (x0, x1 +1/w1) and (x0, x1 -1/w1) are points in gutter_up/down line.
I am making a dithering library. To find the relative position of an absolute point a in a 2-dimensional plane tiled with 4 unit squares, I use rel.x = abs.x % 4; rel.y = abs.y % 4. This is good, and produces the expected results. But what if I am tiling the plane with plus shapes, which are 3 units? How do I find the absolute position? The tile shape is showed here, 1's are parts of the shape, and 0's are empty areas.
0 1 0
1 1 1
0 1 0
For example, if I have point a resting on x = 1, y = 1, then the absolute position should be x = 1, y = 1. But if it is on, say x = 4, y = 1, then the absolute position should be x = 1, y = 2. You see, there would be another plus which's bottom is on the point x = 1, y = 2. How is this accomplished mathematically? Any language, pseudo code is great too. :)
There is periodicity along X and Y axes with period 5. So long switch expression might look like:
case y % 5 of:
0: case x % 5 of
0: cx = x - 1; cy = y;
1: cx = x; cy = y + 1;
2: cx = x; cy = y - 1;
3: cx = x + 1; cy = y;
4: cx = x; cy = y;
1:...
Or we can create constant array 5x5 and fill it with shifts -1, 0, 1.
dx: [[-1,0,0,1,0],[1,0,-1,0,0],[0,0,1,0,-1],[0,-1,0,0,1],[0,1,0,-1,0]]
dy: [[0,1,-1,0,0],[0,0,0,1,-1],[1,-1,0,0,0],[0,0,1,-1,0],[-1,0,0,0,1]]
I feel that some simple formula might exist.
Edit: simpler version:
const dx0: [-1,0,0,1,0]
const dy0: [0,1,-1,0,0]
ixy = (x - 2 * y + 10) % 5;
dx = dx0[ixy];
dy = dy0[ixy];
And finally crazy one-liners without constant arrays
dx = (((11 + x - 2 * (y%5)) % 5) ^ 1 - 2) / 2 //^=xor; /2 - integer division
dy = ((13 + x - 2 * (y%5)) % 5 - 2) / 2
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