Hello! Does anyone know to achieve something similar to what the graph shows, using matpltolib? I need to draw some lines, such as CC' and DD', that do not cross over a given line AB. Is there any way to achieve this?
To draw a line from a point C, perpendicular to a line AB and stopping at AB, a projection point P can be calculated. P should be on AB, so P = t*A + (1-t)*B
. This equation on points means it should hold both for the x and for the y coordinates: xp = t * xa + (1 - t) * xb
and yp = t * ya + (1 - t) * yb)
for some t
. P should also be on a line containing C, and having the perpendicular vector as its direction. The perpendicular vector is yb - ya, - (xb - xa)
. So, P = C + u * Perp
for some u
.
Sympy, Python's symbolic math library can be used to solve these equations:
from sympy import symbols, Eq, solve
t, u, xa, ya, xb, yb, xc, yc = symbols('t u xa ya xb yb xc yc ')
eqpx = Eq(xc + u * (yb - ya), t * xa + (1 - t) * xb)
eqpy = Eq(yc + u * (xa - xb), t * ya + (1 - t) * yb)
solution = solve([eqpx, eqpy])
This finds:
{t: -(xa*xb - xa*xc - xb**2 + xb*xc + ya*yb - ya*yc - yb**2 + yb*yc)/(xa**2 - 2*xa*xb + xb**2 + ya**2 - 2*ya*yb + yb**2),
u: (xa*yb - xa*yc - xb*ya + xb*yc + xc*ya - xc*yb)/(xa**2 - 2*xa*xb + xb**2 + ya**2 - 2*ya*yb + yb**2)}
The solution can be used to define a function to project a point C onto a line AB. Here is an example:
from matplotlib import pyplot as plt
def project_on_line(xc, yc, xa, ya, xb, yb):
t = -(xa * xb - xa * xc - xb ** 2 + xb * xc + ya * yb - ya * yc - yb ** 2 + yb * yc) / (
xa ** 2 - 2 * xa * xb + xb ** 2 + ya ** 2 - 2 * ya * yb + yb ** 2)
return t * xa + (1 - t) * xb, t * ya + (1 - t) * yb
def show_point(x, y, name):
plt.text(x, y, f' {name}', ha='left', va='top')
xa, ya = 0, 2
xb, yb = 6, 5
xc, yc = 5, 1
xd, yd = 7, 0
xcp, ycp = project_on_line(xc, yc, xa, ya, xb, yb)
xdp, ydp = project_on_line(xd, yd, xa, ya, xb, yb)
show_point(xa, ya, "A")
show_point(xb, yb, "B")
show_point(xc, yc, "C")
show_point(xcp, ycp, "C'")
show_point(xd, yd, "D")
show_point(xdp, ydp, "D'")
plt.plot([xa, xb], [ya, yb], color='dodgerblue')
plt.plot([xc, xcp], [yc, ycp], color='dodgerblue')
plt.plot([xd, xdp], [yd, ydp], color='dodgerblue')
plt.axis('equal')
plt.show()