So I have a line that rotates constantly and I want to have another line to be perpendicular to the rotating line. The problem is that it will occasionally point the perpendicular (yellow) line away from my rotating line (white). The math is done inside the function and the output looks like this. I would like the two lines to intersect sooner or later if lengthened. Any help would be greatly appreciated!
import cv2
import numpy as np
def perpendicular_finder(line, point):
x1, y1 = line[0]
x2, y2 = line[1]
x3, y3 = point
if ((y2 - y1) ^ 2 + (x2 - x1) ^ 2) !=0:
k = ((y2 - y1) * (x3 - x1) - (x2 - x1) * (y3 - y1)) / ((y2 - y1) ^ 2 + (x2 - x1) ^ 2)
x4 = x3 - k * (y2 - y1)
y4 = y3 + k * (x2 - x1)
x4 = np.int(x4)
y4 = np.int(y4)
return x4,y4
ballCircle = (200, 200)
purBall = (540,300)
cueX1 = 200
cueY1 = 200
cueX2 = 400
cueY2 = 400
count = 0
while True:
if count < 400:
cueX2 -= 1
elif count < 800:
cueY2 -= 1
elif count < 1200:
cueX2 += 1
else:
cueY2 += 1
if count == 1600:
count = 0
else:
count += 1
blank = np.zeros((500, 900, 3), np.uint8) # Create canvas the size of table
kek = perpendicular_finder((ballCircle, (cueX2,cueY2)), purBall)
cv2.line(blank, purBall, kek, (0, 255, 255), 1) # good path
cv2.circle(blank, ballCircle, 10, (255, 255, 255), -1) # Ball
cv2.circle(blank, purBall, 10, (0, 255, 255), -1) # Purple Ball
cv2.arrowedLine(blank, (cueX1, cueY1), (cueX2, cueY2), (255, 255, 255), 3) # Cue
cv2.imshow("kk", blank)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
Edit 1: This is what user MBo recommended.
Try this function for calculation of projection point
def proj(x1, y1, x2, y2, xp, yp):
x12 = x2 - x1
y12 = y2 - y1
dotp = x12 * (xp - x1) + y12 * (yp - y1)
dot12 = x12 * x12 + y12 * y12
if dot12:
coeff = dotp / dot12
lx = x1 + x12 * coeff
ly = y1 + y12 * coeff
return lx, ly
else:
return None
Seems you have occasionally used xor operator here: ^ 2 instead of squaring **2
Note that your function looses right direction, while mine projects point correctly for any angle (grey line is backward continuation of arrow)
ideone
How it looks
Related
This python code finds the intersection for lines and I have modified it for handling colinear lines so it returns the intersection of 2 lines when they are collinear.
How to handle cases when they are overlapping in that case it should not return any point of intersection.
The output for this comes
(2,0)
But it should not return an intersection as both of the 2 lines are overlapped.
Input
line1 = ((0, 0), (2, 0))
line2 = ((1, 0), (2, 0))
Code
def line_intersection(line1, line2):
x1, y1 = line1[0]
x2, y2 = line1[1]
x3, y3 = line2[0]
x4, y4 = line2[1]
# Check if the lines are collinear
if (y2 - y1) * (x4 - x3) == (y4 - y3) * (x2 - x1):
# Check if they have a common endpoint
if (x1, y1) == (x3, y3) or (x1, y1) == (x4, y4) or (x2, y2) == (x3, y3) or (x2, y2) == (x4, y4):
return (x1, y1) if (x1, y1) == (x3, y3) or (x1, y1) == (x4, y4) else (x2, y2)
else:
# Return "overlapping" if the lines overlap
if max(x1, x2) >= min(x3, x4) and min(x1, x2) <= max(x3, x4) and max(y1, y2) >= min(y3, y4) and min(y1, y2) <= max(y3, y4):
return "overlapping"
else:
return None
def det(a, b):
return a[0] * b[1] - a[1] * b[0]
xdiff = (x1 - x3, x2 - x4)
ydiff = (y1 - y3, y2 - y4)
div = det(xdiff, ydiff)
if div == 0:
return None
d = (det((x1, y1), (x2, y2)), det((x3, y3), (x4, y4)))
x = det(d, xdiff) / div
y = det(d, ydiff) / div
point = (x, y)
# Check if the intersection point is on both lines
if (x >= min(x1, x2) and x <= max(x1, x2)) and (y >= min(y1, y2) and y <= max(y1, y2)) and (x >= min(x3, x4) and x <= max(x3, x4)) and (y >= min(y3, y4) and y <= max(y3, y4)):
return point
else:
return None
Your method of vector differences makes it very hard to precisely dectect colinearity or overlapping lines.
I think it would be much easier if you used the angles of the directing vectors to detect colinearity (this way is also better to avoid aprox. erors in comparisons).
import math
def get_angle(vector):
#if vector lenght == 0
if vector[0] == vector[1] == 0:
return None
angle = math.atan(vector[0]/vector[1]) if not vector[1] == 0 else math.pi/2 if vector[0] > 0 else -math.pi/2
while angle < 0:
angle = angle+(math.pi)
return angle
def similar_angle(angle1, angle2):
if angle1 == None or angle2 == None:
return True
return abs(angle1 - angle2) < 0.0001
x1, y1 = 0,0
x2, y2 = 1,1
x3, y3 = 0,1
x4, y4 = 1,2
#direction vectors of both lines
v12 = (x2-x1, y2-y1)
v34 = (x4-x3, y4-y3)
#angles of each vector
vs = [v12, v34]
angles = list()
for v in vs:
angle = get_angle(v)
angles.append(angle)
#colinearity
if abs(angles[0] - angles[1]) < 0.0001:
print('colinear')
condition_1 = similar_angle( get_angle( (x4-x1, y4-y1) ), get_angle( (x3-x1, y3-y1) ) )
condition_2 = similar_angle( get_angle( (x4-x1, y4-y1) ), get_angle( (x4-x2, y4-y2) ) )
#overlapped
if condition_1 and condition_2:
print('overlapped')
else:
print('not colinear')
I have this problem:
Given a list of points in Euclidean coordinates, count the number of distinct, non-zero area rectangles can be formed by any 4 points in the input list (Axis-alignment does not matter)
I hope you guys can find edge cases to attack my solution.
This is my code: https://pastebin.com/fzzJEwY1
def countRectangles(intPoints):
ans = 0
def getDistance(point1, point2):
x1, y1 = point1[0], point1[1]
x2, y2 = point2[0], point2[1]
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)
def getMidPoint(point1, point2):
x1, y1 = point1[0], point1[1]
x2, y2 = point2[0], point2[1]
midPoint = ((x1 + x2) / 2, (y1 + y2) / 2)
return midPoint
def intToFloatList(points):
for i, point in enumerate(points):
curX, curY = point[0], point[1]
points[i] = (float(curX), float(curY))
return points
distanceMidPoint_PointsMap = {}
points = intToFloatList(intPoints)
for i, point in enumerate(points):
for j in range(i+1, len(points)):
nextPoint = points[j]
curSqrdDistance = getDistance(point, nextPoint)
curMidPoint = getMidPoint(point, nextPoint)
key = (curSqrdDistance, curMidPoint)
if key not in distanceMidPoint_PointsMap:
distanceMidPoint_PointsMap[key] = set()
distanceMidPoint_PointsMap[key].add((point, nextPoint))
for key, val in distanceMidPoint_PointsMap.items():
if len(val) > 1:
ans += len(val)
return ans // 2
I have tried both axis-aligned and non-axis-aligned test cases and my solution passed.
How to obtain pixel value of a gray scale image using the Bresenham line algorithm given a line at different angles as shown in this code fraction
I hope and you can help me
import cv2
import numpy as np
img= cv2.imread("0.L3Luzr_Esq.tif")
def bresenham(origin, dest):
# debug code
print origin
print dest
# end debug code
x0 = origin[0]; y0 = origin[1]
x1 = dest[0]; y1 = dest[1]
steep = abs(y1 - y0) > abs(x1 - x0)
backward = x0 > x1
if steep:
x0, y0 = y0, x0
x1, y1 = y1, x1
if backward:
x0, x1 = x1, x0
y0, y1 = y1, y0
dx = x1 - x0
dy = abs(y1 - y0)
error = dx / 2
y = y0
if y0 < y1: ystep = 1
else: ystep = -1
result = []
for x in range(x0, x1):
if steep: result.append((y, x))
else: result.append((x, y))
error -= dy
if error < 0:
y += ystep
error += dx
return result
if backward: return result.reverse()
else: return result
print result
return result
I have a travel time map, I want to get the integer points along the shortest path from source to receiver.
My present solution is that I make a runge-kutta integration from the receiver location and get a series of float points. Then I sample every 5 or some number of points and assume it a straight line between in order to use the Bresenham's line algorithm. With this approach, I will get the integer points.
However, it's not enough fast. Because I need to calculate a lot of receivers' shortest path, the sum of time will be very large.
I used line_profiler to analysis the time-consuming, which shows the major part of time is for function ruge-kutta and its calling function get_velocity
codes are below
def optimal_path_2d(gradx_interp,
grady_interp,
starting_point,
dx,
N=100):
"""
Find the optimal path from starting_point to the zero contour
of travel_time. dx is the grid spacing
Solve the equation x_t = - grad t / | grad t |
"""
def get_velocity(position):
""" return normalized velocity at pos """
x, y = position
vel = np.array([gradx_interp(y, x)[0][0], grady_interp(y, x)[0][0]])
return vel / np.linalg.norm(vel)
def runge_kutta(pos, ds):
""" Fourth order Runge Kutta point update """
k1 = ds * get_velocity(pos)
k2 = ds * get_velocity(pos - k1 / 2.0)
k3 = ds * get_velocity(pos - k2 / 2.0)
k4 = ds * get_velocity(pos - k3)
return pos - (k1 + 2 * k2 + 2 * k3 + k4) / 6.0
x = runge_kutta(starting_point, dx)
xl, yl = [], []
for i in range(N):
xl.append(x[0])
yl.append(x[1])
x = runge_kutta(x, dx)
distance = ((x[0] - xl[-1])**2 +
(x[1] - yl[-1])**2)**0.5
if distance < dx*0.9:
break
return yl, xl
def get_curve(x_curve, y_curve, num_interval):
"""Curve Algorithm based on Bresenham's Line Algorithm
Produces a list of tuples
"""
num = len(x_curve)
if num < num_interval:
print("num_interval is too large.")
ret_set = set()
x0 = x_curve[0]
y0 = y_curve[0]
for i in range(num_interval, num, num_interval):
x1 = x_curve[i]
y1 = y_curve[i]
points_on_line = get_line((x0, y0), (x1, y1))
ret_set.update(points_on_line)
x0 = x1
y0 = y1
if num % num_interval != 0:
n = int(num/num_interval)*num_interval
x0 = x_curve[n]
y0 = y_curve[n]
x1 = x_curve[-1]
y1 = y_curve[-1]
points_on_line = get_line((x0, y0), (x1, y1))
ret_set.update(points_on_line)
return list(ret_set)
def get_line(start, end):
"""modifed version of Bresenham's Line Algorithm
Produces a list of tuples from start and end
>>> points1 = get_line((0, 0), (3, 4))
>>> points2 = get_line((3, 4), (0, 0))
>>> assert(set(points1) == set(points2))
>>> print points1
[(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
>>> print points2
[(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
"""
# Setup initial conditions
x1, y1 = (int(x) for x in start)
x2, y2 = (int(x) for x in end)
dx = x2 - x1
dy = y2 - y1
# Determine how steep the line is
is_steep = abs(dy) > abs(dx)
# Rotate line
if is_steep:
x1, y1 = y1, x1
x2, y2 = y2, x2
# Swap start and end points if necessary and store swap state
swapped = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
swapped = True
# Recalculate differentials
dx = x2 - x1
dy = y2 - y1
# Calculate error
error = int(dx / 2.0)
ystep = 1 if y1 < y2 else -1
# Iterate over bounding box generating points between start and end
y = y1
points = []
for x in range(x1, x2 + 1):
coord = (y, x) if is_steep else (x, y)
points.append(coord)
error -= abs(dy)
if error < 0:
y += ystep
error += dx
# Reverse the list if the coordinates were swapped
if swapped:
points.reverse()
return points
nx = 100
ny = 100
num_interval = 5
loc_src = (10, 10)
loc_rec = (70, 90)
coordx = np.arange(nx)
coordy = np.arange(ny)
X, Y = np.meshgrid(coordx, coords)
travel_time = (X-loc_src[0])**2/5 + (Y-loc_src[1])**2/10 # for simplicity
grad_t_y, grad_t_x = np.gradient(travel_time, dx)
if isinstance(travel_time, np.ma.MaskedArray):
grad_t_y[grad_t_y.mask] = 0.0
grad_t_y = grad_t_y.data
grad_t_x[grad_t_x.mask] = 0.0
grad_t_x = grad_t_x.data
gradx_interp = RectBivariateSpline(coordy, coordx, grad_t_x)
grady_interp = RectBivariateSpline(coordy, coordx, grad_t_y)
yl, xl = optimal_path(gradx_interp, grady_interp, loc_rec, dx)
grid_indx = get_curve(xl, yl, num_interval)
I hear that Cython will be faster, then I learn a little recently and try it. the result is only 2 faster than codes above because I'm really new to Cython. The code below is incomplete, and I just wrote it for testing.
import numpy as np
from numpy.core.umath_tests import inner1d
def func(X_interp, Y_interp):
def get_velocity(double x, double y ):
""" return normalized velocity at pos """
cdef double vel[2], norm
a = X_interp(y, x)
vel[0] = a[0][0]
b = Y_interp(y, x)
vel[1] = b[0][0]
# norm = (vel[0]**2 + vel[1]**2)**0.5
# vel[0] = vel[0]/norm
# vel[1] = vel[1]/norm
return vel
def runge_kutta(double x, double y, double ds):
""" Fourth order Runge Kutta point update """
cdef double k1[2], k2[2], k3[2], k4[2], r[2], pos[2]
pos[0] = x; pos[1] = y
k1 = get_velocity(pos[0], pos[1])
k2 = get_velocity(pos[0] - k1[0]/2.0*ds,pos[1] - k1[1]/2.0*ds)
k3 = get_velocity(pos[0] - k2[0]/2.0*ds,pos[1] - k2[1]/2.0*ds)
k4 = get_velocity(pos[0] - k3[0]/2.0*ds,pos[1] - k3[1]/2.0*ds)
cdef size_t i
for i in range(2):
r[i] = pos[i] - ds * (k1[i] + 2*k2[i] + 2*k3[i] + k4[i])/6.0
return r
for i in range(50):
runge_kutta(0, 0, 1.)
# print(runge_kutta(0, 0, 1.))
If I have x,y coordinates for a point on line in 3D and I need to get this z-coordinate using python, how can I do it ?? I have the start point (x1,y1,z1) and end point (x2,y2,z2) of the line in 3D, so any suggestions please ???
You can easily setup a parametric equation for the line:
x = x1 + (x2 - x1)*t
y = y1 + (y2 - y1)*t
z = z1 + (z2 - z1)*t
So given a (x,y), solve this equation for t:
x = x1 + (x2 - x1)*t
so
t = (x - x1) / (x2 - x1)
or
t = (y - y1) / (y2 - y1)
Now that you know t, you can find z:
z = z1 + (z2 - z1)*t
So in Python it would be:
def computeZ(p1,p2,x,y):
x1,y1,z1 = p1
x2,y2,z2 = p2
if x2 - x1 != 0:
t = (x - x1) / (x2 - x1)
elif y2 - y1 != 0:
t = (y - y1) / (y2 - y1)
else:
print "no unique z value exists"
return 0
return z1 + (z2 - z1)*t
You only need to know either the X or the Y value, not both. The equation, if you have an X value, A, would be:
((A - x1)*(z2 - z1)/(x2 - x1)) + z1
Using this, you can plug in your two initial points and an x and get the new point like so:
def get_points(p1, p2, x):
x1, y1, z1 = p1
x2, y2, z2 = p2
new_z = ((x - x1)*(z2 - z1)/(x2 - x1)) + z1
new_y = ((x - x1)*(y2 - y1)/(x2 - x1)) + y1
new_p = (x, new_y, new_z)
return new_p