Related
i am trying to create a function:calculate_distance_between_points(point1, point2) where i can get point 1 and 2 as strings in the form (x,y) in the main function.
This function calculates the distance between two points. The function gets two lists as a parameter: the first list contains the x and y coordinates of the start point and the other contains the x and y coordinates of the end point. Then it returns the distance between the two points.
here is my half-done code:
def calculate_distance_between_points(point1, point2):
point_list = []
text1 = point1.split(",")
text2 = point2.split(",")
for i in range(2):
row = [0.0] * 2
for j in range(1):
row[1] = float(text1[j])
row[2] = float(text2[j])
point_list.append(row)
I'm not so sure if it can create the list I want. Could you please check it out and shed some light on how to make it work?
Something like this?
from scipy.spatial import distance
def calculate_distance_between_points(point1, point2):
point1, point2 = point1.split(','), point2.split(',')
point1, point2 = [float(i) for i in point1], [float(i) for i in point2]
return distance.euclidean(point1, point2)
calculate_distance_between_points('1,1', '2,2')
You can use the math.hypot() function to calculate the Euclidean distance between the two points if you convert the coordinate string values to floats first.
import math
def calculate_distance_between_points(point1, point2):
p1 = (float(v) for v in point1.split(","))
p2 = (float(v) for v in point2.split(","))
return math.hypot(*(a-b for a, b in zip(p1, p2)))
d = calculate_distance_between_points('1,1', '2,2')
print(d) # -> 1.4142135623730951
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to convert a recursive function to an iterative one based on python limitations.
I am adapting an algorithm that I found in this answer from Javascript to Python. For a better explanation of the algorithm I'd suggest reading the answer I linked because it's much more concise. The high level purpose of this is to find equidistant points along a "line" made up of lat/lng pairs (points). However I'm running into issues in the recursive move_along_path function due to maximum recursion depth limitations in Python. After reading some similar questions, I found the best thing to do is to convert it to an iterative function. I am having trouble even beginning the conversion.
These are the two functions I have adapted, where move_along_path is the recursive function (only one that needs converting) that sometimes calls move_towards as well.
How can I begin this conversion and what are some basic steps to consider when converting?
# This is the base function that calls the recursive function
def get_equidistant_markers_from_polyline_points(self, points):
points = points[1::10]
# Get markers
next_marker_at = 0
markers = []
while True:
next_point = self.iterative_move_along_path(points, next_marker_at)
if next_point is not None:
markers.append({'lat': next_point[0], 'lng': next_point[1]})
next_marker_at += 80000 # About 50 miles
else:
break
print(markers)
return markers
# This function moves from point to point along a "path" of points.
# Once the "distance" threshold has been crossed then it adds the point
# to a list of equidistant markers.
def move_along_path(self, points, distance, index=0):
if index < len(points) - 1:
# There is still at least one point further from this point
# Turn points into tuples for geopy format
# point1_tuple = (points[index]['latitude'], points[index]['longitude'])
# point2_tuple = (points[index + 1]['latitude'], points[index + 1]['longitude'])
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
if distance <= distance_to_next_point:
# Distance_to_next_point is within this point and the next
# Return the destination point with moveTowards()
return self.move_towards(point1_tuple, point2_tuple, distance)
else:
# The destination is further from the next point
# Subtract distance_to_next_point from distance and continue recursively
return self.move_along_path(points, distance - distance_to_next_point, index + 1)
else:
# There are no further points, the distance exceeds the length of the full path.
# Return None
return None
def move_towards(point1, point2, distance):
# Convert degrees to radians
lat1 = math.radians(point1[0])
lon1 = math.radians(point1[1])
lat2 = math.radians(point2[0])
d_lon = math.radians(point2[1] - point1[1])
# Find the bearing from point1 to point2
bearing = math.atan2(math.sin(d_lon) * math.cos(lat2),
math.cos(lat1) * math.sin(lat2) -
math.sin(lat1) * math.cos(lat2) *
math.cos(d_lon))
# Earth's radius
ang_dist = distance / 6371000.0
# Calculate the destination point, given the source and bearing
lat2 = math.asin(math.sin(lat1) * math.cos(ang_dist) +
math.cos(lat1) * math.sin(ang_dist) *
math.cos(bearing))
lon2 = lon1 + math.atan2(math.sin(bearing) * math.sin(ang_dist) *
math.cos(lat1),
math.cos(ang_dist) - math.sin(lat1) *
math.sin(lat2))
if math.isnan(lat2) or math.isnan(lon2):
return None
return [math.degrees(lat2), math.degrees(lon2)]
Assuming that your posted code are right, I think the following function works as an iterative approach to replace your current recursive function:
def iterative_move_along_path(self, points, distance, index=0):
while index < len(points) - 1:
# There is still at least one point further from this point
# Turn points into tuples for geopy format
# point1_tuple = (points[index]['latitude'], points[index]['longitude'])
# point2_tuple = (points[index + 1]['latitude'], points[index + 1]['longitude'])
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
if distance <= distance_to_next_point:
# Distance_to_next_point is within this point and the next
# Return the destination point with moveTowards()
return self.move_towards(point1_tuple, point2_tuple, distance)
else:
# The destination is further from the next point
# Subtract distance_to_next_point from distance and continue recursively
distance -= distance_to_next_point
index += 1
# There are no further points, the distance exceeds the length of the full path.
# Return None
return None
As a step of your recursion doesn't seem to have a dependency relative to previously calculated values when returning from the recursion, a simple and right insertion of a while loop together with a proper update of the variables should work out.
I'm not the best with python so I'm sure you can optimize this but the general idea is that instead of calling a recursive function you can just do a while loop until your condition is met and in the loop you modify the variables in accordance to what you would've done had you sent them through as parameters to the recursive function.
def move_along_path(self, points, distance, index=0):
if index < len(points) - 1:
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
while distance > distance_to_next_point:
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
distance -= distance_to_next_point
index++
return self.move_towards(point1_tuple, point2_tuple, distance)
else
return None
I am extremely new to programming but I decided to take on an interesting project as I recently learnt how to represent a sphere in parametric form. When intersecting three spheres, there are two points of intersections that are distinct unless they only overlap at a singular point.
Parametric representation of a sphere:
The code I have is modified from the answer from Python/matplotlib : plotting a 3d cube, a sphere and a vector?, adding the ability to dictate the x, y and z origin and the radius of the sphere. Many similar questions were written in C++, Java, and C#, which I cannot understand at all (I barely know what I am doing so go easy on me).
My Code:
import numpy as np
def make_sphere_x(x, radius):
u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
x += radius * np.cos(u) * np.sin(v)
return x
def make_sphere_y(y, radius):
u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
y += radius * np.sin(u) * np.sin(v)
return y
def make_sphere_z(z, radius):
u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
z += radius * np.cos(v)
return z
#x values
sphere_1_x = make_sphere_x(0, 2)
sphere_2_x = make_sphere_x(1, 3)
sphere_3_x = make_sphere_x(-1, 4)
#y values
sphere_1_y = make_sphere_y(0, 2)
sphere_2_y = make_sphere_y(1, 3)
sphere_3_y = make_sphere_y(0, 4)
#z values
sphere_1_z = make_sphere_z(0, 2)
sphere_2_z = make_sphere_z(1, 3)
sphere_3_z = make_sphere_z(-2, 4)
#intercept of x-values
intercept_x = list(filter(lambda x: x in sphere_1_x, sphere_2_x))
intercept_x = list(filter(lambda x: x in intercept_x, sphere_3_x))
print(intercept_x)
Problems:
Clearly there must be a better way of finding the intercepts. Right now, the code generates points at equal intervals, with the number of intervals I specify under the imaginary number in np.mgrid. If this is increased, the chances of an intersection should increase (I think) but when I try to increase it to 10000j or above, it just spits a memory error.
There are obvious gaps in the array and this method would most likely be erroneous even if I have access to a super computer and can crank up the value to an obscene value. Right now the code results in a null set.
The code is extremely inefficient, not that this is a priority but people like things in threes right?
Feel free to flame me for rookie mistakes in coding or asking questions on Stack Overflow. Your help is greatly valued.
Using scipy.optimize.fsolve you can find the root of a given function, given an initial guess that is somewhere in the range of your solution. I used this approach to solve your problem and it seems to work for me. The only downside is that it only provides you one intersection. To find the second one you would have to tinker with the initial conditions until fsolve finds the second root.
First we define our spheres by defining (arbitrary) radii and centers for each sphere:
a1 = np.array([0,0,0])
r1 = .4
a2 = np.array([.3,0,0])
r2 = .5
a3 = np.array([0,.3,0])
r3 = .5
We then define how to transform back into cartesian coordinates, given angles u,v
def position(a,r,u,v):
return a + r*np.array([np.cos(u)*np.sin(v),np.sin(u)*np.sin(v),np.cos(v)])
Now we think about what equation we need to find the root of. For any intersection point, it holds that for perfect u1,v1,u2,v2,u3,v3 the positions position(a1,r1,u1,v1) = position(a2,r2,u2,v2) = position(a3,r3,u3,v3) are equal. We thus find three equations which must be zeros, namely the differences of two position vectors. In fact, as every vector has 3 components, we have 9 equations which is more than enough to determine our 6 variables.
We find the function to minimize as:
def f(args):
u1,v1,u2,v2,u3,v3,_,_,_ = args
pos1 = position(a1,r1,u1,v1)
pos2 = position(a2,r2,u2,v2)
pos3 = position(a3,r3,u3,v3)
return np.array([pos1 - pos2, pos1 - pos3, pos2 - pos3]).flatten()
fsolve needs the same amount of input and output arguments. As we have 9 equations but only 6 variables I simply used 3 dummy variables so the dimensions match. Flattening the array in the last line is necessary as fsolve only accepts 1D-Arrays.
Now the intersection can be found using fsolve and a (pretty random) guess:
guess = np.array([np.pi/4,np.pi/4,np.pi/4,np.pi/4,np.pi/4,np.pi/4,0,0,0])
x0 = fsolve(f,guess)
u1,v1,u2,v2,u3,v3,_,_,_ = x0
You can check that the result is correct by plugging the angles you received into the position function.
The problem would be better tackled using trigonometry.
Reducing the problem into 2D circles, we could do:
import math
import numpy
class Circle():
def __init__(self, cx, cy, r):
"""initialise Circle and set main properties"""
self.centre = numpy.array([cx, cy])
self.radius = r
def find_intercept(self, c2):
"""find the intercepts between the current Circle and a second c2"""
#Find the distance between the circles
s = c2.centre - self.centre
self.dx, self.dy = s
self.d = math.sqrt(numpy.sum(s**2))
#Test if there is an overlap. Note: this won't detect if one circle completly surrounds the other.
if self.d > (self.radius + c2.radius):
print("no interaction")
else:
#trigonometry
self.theta = math.atan2(self.dy,self.dx)
#cosine rule
self.cosA = (c2.radius**2 - self.radius**2 + self.d**2)/(2*c2.radius*self.d)
self.A = math.acos(self.cosA)
self.Ia = c2.centre - [math.cos(self.A+self.theta)*c2.radius, math.sin(self.A+self.theta)*c2.radius]
self.Ib = c2.centre - [math.cos(self.A-self.theta)*c2.radius,-math.sin(self.A-self.theta)*c2.radius]
print("Interaction points are : ", self.Ia, " and: ", self.Ib)
#define two arbitrary circles
c1 = Circle(2,5,5)
c2 = Circle(1,6,4)
#find the intercepts
c1.find_intercept(c2)
#test results by reversing the operation
c2.find_intercept(c1)
I need to take a list I have created and find the closest two points and print them out. How can I go about comparing each point in the list?
There isn't any need to plot or anything, just compare the points and find the closest two in the list.
import math # 'math' needed for 'sqrt'
# Distance function
def distance(xi,xii,yi,yii):
sq1 = (xi-xii)*(xi-xii)
sq2 = (yi-yii)*(yi-yii)
return math.sqrt(sq1 + sq2)
# Run through input and reorder in [(x, y), (x,y) ...] format
oInput = ["9.5 7.5", "10.2 19.1", "9.7 10.2"] # Original input list (entered by spacing the two points).
mInput = [] # Manipulated list
fList = [] # Final list
for o in oInput:
mInput = o.split()
x,y = float(mInput[0]), float(mInput[1])
fList += [(x, y)] # outputs [(9.5, 7.5), (10.2, 19.1), (9.7, 10.2)]
It is more convenient to rewrite your distance() function to take two (x, y) tuples as parameters:
def distance(p0, p1):
return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
Now you want to iterate over all pairs of points from your list fList. The function iterools.combinations() is handy for this purpose:
min_distance = distance(fList[0], fList[1])
for p0, p1 in itertools.combinations(fList, 2):
min_distance = min(min_distance, distance(p0, p1))
An alternative is to define distance() to accept the pair of points in a single parameter
def distance(points):
p0, p1 = points
return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
and use the key parameter to the built-in min() function:
min_pair = min(itertools.combinations(fList, 2), key=distance)
min_distance = distance(min_pair)
I realize that there are library constraints on this question, but for completeness if you have N points in an Nx2 numpy ndarray (2D system):
from scipy.spatial.distance import pdist
x = numpy.array([[9.5,7.5],[10.2,19.1],[9.7,10.2]])
mindist = numpy.min(pdist(x))
I always try to encourage people to use numpy/scipy if they are dealing with data that is best stored in a numerical array and it's good to know that the tools are out there for future reference.
Note that the math.sqrt function is both slow and, in this case, unnecessary. Try comparing the distance squared to speed it up (sorting distances vs. distance squared will always produce the same ordering):
def distSquared(p0, p1):
return (p0[0] - p1[0])**2 + (p0[1] - p1[1])**2
This might work:
oInput = ["9.5 7.5", "10.2 19.1", "9.7 10.2"]
# parse inputs
inp = [(float(j[0]), float(j[1])) for j in [i.split() for i in oInput]]
# initialize results with a really large value
min_distance = float('infinity')
min_pair = None
# loop over inputs
length = len(inp)
for i in xrange(length):
for j in xrange(i+1, length):
point1 = inp[i]
point2 = inp[j]
if math.hypot(point1[0] - point2[0], point1[1] - point2[0]) < min_distance:
min_pair = [point1, point2]
once the loops are done, min_pair should be the pair with the smallest distance.
Using float() to parse the text leaves room for improvement.
math.hypot is about a third faster than calculating the distance in a handwritten python-function
Your fixed code. No efficient algorithm, just the brute force one.
import math # math needed for sqrt
# distance function
def dist(p1, p2):
return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)
# run through input and reorder in [(x, y), (x,y) ...] format
input = ["9.5 7.5", "10.2 19.1", "9.7 10.2"] # original input list (entered by spacing the two points)
points = [map(float, point.split()) for point in input] # final list
# http://en.wikipedia.org/wiki/Closest_pair_of_points
mindist = float("inf")
for p1, p2 in itertools.combinations(points, 2):
if dist(p1, p2) < mindist:
mindist = dist(p1, p2)
closestpair = (p1, p2)
print(closestpair)
First, some notes:
a**2 # squares a
(xi - xii)**2 # squares the expression in parentheses.
mInput doesn't need to be declared in advance.
fList.append((x, y)) is more pythonic than using +=.
Now you have fList. Your distance function can be rewritten to take 2 2-tuple (point) arguments, which I won't bother with here.
Then you can just write:
shortest = float('inf')
for pair in itertools.combinations(fList, 2):
shortest = min(shortest, distance(*pair))
Many of the above questions suggest finding square root using math.sqrt which is slow as well as not a good approach to find square root. In spite of using such approach just recall the basic concepts from school: think of taking the square root of any positive number, x. The square root is then written as a power of one-half: x½. Thus, a fractional exponent indicates that some root is to be taken.
so rather than using math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
Use
def distance(a,b):
euclidean_distance = ((b[0]-a[0])**2 + (a[1]-a[1])**2)**0.5
return(euclidean_distance)
Hope it helps
def midpoint(p1, p2):
"""
PRE: p1 and p2 are Point objects (from the graphics module)
POST: a new Point equidistant from and co-linear with p1 and p2
is computed and returned
Write a function midpoint with the following specification
What graphics module are you using? (pypi contains several dozen, none named 'graphics') What does the interface of a Point look like?
If Point has named attributes (like p.x, p.y, etc) you could do something like
def midpoint(p1, p2):
return Point((p1.x+p2.x)/2, (p1.y+p2.y)/2)
If Point can be accessed as a list (like p[0], p[1], etc) you could instead do
def midpoint(p1, p2):
return Point((p1[0]+p2[0])/2, (p1[1]+p2[1])/2)
If Point has Point addition and scalar division or multiplication overloaded, you could do
def midpoint(p1, p2):
return (p1+p2)/2 # or *0.5
(although strictly speaking adding two Points should be meaningless, and subtracting one point from another should give you a Vector - thus
def midpoint(p1, p2):
return p1 + (p2-p1)/2 # or *0.5
You'd write it the same way you write any other function:
def midpoint(x1, y1, x2, y2):
return ((x1 + x2)/2, (y1 + y2)/2)
or something like that. It depends on whether you represent points as individual coordinates or objects or lists etc.
Calculate them yourself?
The midway point between two points is their average. That is,
P_mid = (P1 + P2) / 2
It's up to you how a "point" is represented. It could be 2D, 3D, or even nD. You might want to implement __add__ and __div__ and other "numerical" operations.
How about using Numpy?
If the points are represented by numpy.array, their dimension doesn't matter.
For example, consider 2D.
import numpy as np
x = np.array([-1, -1])
y = np.array([1, 1])
mid1 = (x + y)/2
# or
mid2 = np.mean([x, y])
NumPy is the fundamental package needed for scientific computing with Python.
visit Link
I am assuming the question is about "Point" objects in the module named graphics.
As per the documentation I am providing in the reference, the Point class has getX() and `getY() accessors to fetch the X and Y coordinates of the point respectively.
So the solution could be like this
def midpoint(p1, p2):
mx = (p1.getX() + p2.getX())/2.0
my = (p1.getY() + p2.getY())/2.0
return Point(mx,my)
or
def midpoint(p1,p2):
l = Line(p1,p2)
return l.getCenter()
Reference-
http://mcsp.wartburg.edu/zelle/python/graphics/graphics.pdf
from __future__ import division
def midpoint(p1, p2):
if len(p1) != len(p2):
raise TypeError('Points are from differing dimensions')
return map(lambda (e1, e2): (e1 + e2) / 2, zip(p1, p2))
Update0
Since it seems nobody actually answered the question in the form you wanted (except me ;)), here's the simplified version for 2 dimensional points:
def midpoint(p1, p2):
return (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2
I've noticed that the answers so far have involved averaging. Here are two somewhat novel approaches (based on Prof Daniel Lemire's article) using bitwise operations that take advantage of the fact the point will be integers. If you're using floating point math, these won't work.
def midpoint (x, y):
return ((x^y)>>1) + (x&y)
def midpoint2 (x, y):
return (x|y) - ((x^y)>>1)