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')
Related
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.
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
So I have this recursive graphic that works perfectly fine, but I was wondering for turtle graphics, and in my case how do I get each line segment to be a random color?
from turtle import *
def line(t, x1, y1, x2, y2):
"""draws the line segment from x1,y1 to x2,y2"""
t.up()
t.goto(x1, y1)
t.down()
t.goto(x2, y2)
def drawLine(t, x1, y1, x2, y2, level):
"""forms the shape"""
if level == 0:
line(t, x1, y1, x2, y2)
else:
xm = ((x1 + x2) + (y2 - y1)) // 2
ym = ((y1 + y2) + (x1 - x2)) // 2
drawLine(t, x1, y1, xm, ym, level-1)
drawLine(t, xm, ym, x2, y2, level-1)
def main():
"""the main function"""
myTurtle = Turtle()
myTurtle.hideturtle()
num = int(input("Please enter the number of levels: "))
drawLine(myTurtle, 100, 0, 100, -200, num)
main()
You can create a list of colors then use random.choice to pick a random color from the list when drawing each line.
Here is the code update
from turtle import *
import random
colors = ['red','green','blue','indianred','firebrick','ForestGreen'] # color list
def line(t, x1, y1, x2, y2):
"""draws the line segment from x1,y1 to x2,y2"""
t.color(random.choice(colors)) # pick color from list
t.up()
t.goto(x1, y1)
t.down()
t.goto(x2, y2)
......
Output (10 levels)
You can get a random color triple using tuple(randint(0,255) for _ in range(3)) where randint is from random module. You can then call this function every time you draw a line t.pencolor(*get_rand_color()).
PS : colormode(255) must be set in the code for setting colors as tuples, now in theory you can get any of the 16.8 million colors possible.
from turtle import *
from random import randint
def line(t, x1, y1, x2, y2):
"""draws the line segment from x1,y1 to x2,y2"""
t.up()
t.goto(x1, y1)
t.down()
t.pencolor(*get_rand_color())
t.goto(x2, y2)
def get_rand_color():
"""
Returns a 3-tuple of random numbers in the range 0 - 255
eg : (89, 103, 108)
"""
return tuple(randint(0,255) for _ in range(3))
def drawLine(t, x1, y1, x2, y2, level):
"""forms the shape"""
if level == 0:
line(t, x1, y1, x2, y2)
else:
xm = ((x1 + x2) + (y2 - y1)) // 2
ym = ((y1 + y2) + (x1 - x2)) // 2
drawLine(t, x1, y1, xm, ym, level-1)
drawLine(t, xm, ym, x2, y2, level-1)
def main():
"""the main function"""
myTurtle = Turtle()
myTurtle.hideturtle()
colormode(255)
num = 6
drawLine(myTurtle, 100, 0, 100, -200, num)
main()
For level 5 this is how it looks like
Edit : As #cdlane points out in comments, "colormode(255) must be set to specify colors as values in the range 0 - 255. By default, turtle's color mode uses values in the range 0.0 - 1.0 and they can be specified by a tuple: (0.5, 0.125, 0.333)".
In other words if you don't do colormode(255), you can change the get_rand_color function to return values in the range 0.0 to 1.0 instead of 0 to 255.
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
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