Calculate the length of polyline from csv - python

I'm still new to python. I need helps to calculate the length of polyline with simple distance calculation:
distance = sqrt( (x1 - x2)**2 + (y1 - y2)**2 )
For instance my input csv looks like this.
id x y sequence
1 1.5 2.5 0
1 3.2 4.9 1
1 3.6 6.6 2
1 4.4 5.0 3
2 2.0 4.5 0
2 3.5 6.0 1
I have 'id' and 'sequence' (sequence number of the line vertices). How read the csv file? if current 'id' has the same value as previous row 'id', then perform the distance calculation : sqrt( (x[i] - x[i-1])**2 + (y[i] - y[i-1])**2 ). After that, group by 'id' and sum their 'distance' value.
The output csv would look like this:
id distance
1 ?
2 ?
Thanks in advance.

Polyline:
Distance between two points and the distance between a point and polyline:
def lineMagnitude (x1, y1, x2, y2):
lineMagnitude = math.sqrt(math.pow((x2 - x1), 2)+ math.pow((y2 - y1), 2))
return lineMagnitude
#Calc minimum distance from a point and a line segment (i.e. consecutive vertices in a polyline).
def DistancePointLine (px, py, x1, y1, x2, y2):
#http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/source.vba
LineMag = lineMagnitude(x1, y1, x2, y2)
if LineMag < 0.00000001:
DistancePointLine = 9999
return DistancePointLine
u1 = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1)))
u = u1 / (LineMag * LineMag)
if (u < 0.00001) or (u > 1):
#// closest point does not fall within the line segment, take the shorter distance
#// to an endpoint
ix = lineMagnitude(px, py, x1, y1)
iy = lineMagnitude(px, py, x2, y2)
if ix > iy:
DistancePointLine = iy
else:
DistancePointLine = ix
else:
# Intersecting point is on the line, use the formula
ix = x1 + u * (x2 - x1)
iy = y1 + u * (y2 - y1)
DistancePointLine = lineMagnitude(px, py, ix, iy)
return DistancePointLine
For more information visit: http://www.maprantala.com/2010/05/16/measuring-distance-from-a-point-to-a-line-segment/

Related

Given coordinates of square, calculate new coordinates if diagonal is multiplied by factor n

As above: I'm trying to draw a bounding box. Given the x and y coordinates of the two opposite points that form a box, I'm trying to implement a function that multiplies the diagonal of that box by an arbitrary multiplier, then compute the new x and y coordinates. x and y can be positive or negative floats.
def return_box(x1, x2, y1, y2, multiplier = n):
do_magic()
return new_x, new_y
Assuming you want to keep (x1, y1) in the same place, scale the diagonal and return the new (x2, y2):
def return_box(x1, x2, y1, y2, multiplier = n):
return (
x1 + multiplier * (x2 - x1),
y1 + multiplier * (y2 - y1)
)
If you instead want to keep the center of the rectangle in the same place and return the two new corners:
def return_box(x1, x2, y1, y2, multiplier = n):
xmid = (x1 + x2) / 2
ymid = (y1 + y2) / 2
return (
xmid + multiplier * (x1 - xmid),
ymid + multiplier * (y1 - ymid),
), (
xmid + multiplier * (x2 - xmid),
ymid + multiplier * (y2 - ymid)
)

python: interpolation: finding a rectangle that minimally include a point

I am implementing a bilinear interpolation as in How to perform bilinear interpolation in Python
I have a sorted list of points that are the vertexes of my regular grid.
[[x1,y1,z1],[x2,y2,z2],[x3,y3,z3],[x4,y4,z4],[x5,y5,z5],...]
I want to interpolate linearly on the point (x,y). I have written the following code
def f(x, y, points):
for i in range(len(points)-1, -1, -1):
if (x>points[i][0])and(y>points[i][1]):
break
try:
pp = [points[i], points[i+1]]
except IndexError:
pp = [points[i], points[i-1]]
for j in range(len(points)):
if (x<points[j][0])and(y<points[j][1]):
break
pp.append(points[j-1])
pp.append(points[j])
(x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = pp
return (q11 * (x2 - x) * (y2 - y) +
q21 * (x - x1) * (y2 - y) +
q12 * (x2 - x) * (y - y1) +
q22 * (x - x1) * (y - y1)) / ((x2 - x1) * (y2 - y1))
but this code doesn't work on the boundaries. I would think this is common problem in interpolation, so I was wondering how I should select the smallest rectangle of points around (x,y) from my regular grid.
Your grid is regular, so you don't need to traverse all points to determine cell indexes. Just divide coordinates by cell size and round result to smaller integer. 1D example: if first point has coordinate 1 and cell size is 2, point 6 lies at int (6-1)/2 = 2-nd interval
Restrict result index to ensure that it is in grid limits - so points outside grid will use border cells
i = int((x - points[i][0]) / xsize) #not sure what is the best way in Python
if (i < 0):
i = 0
if (i >= XCount):
i = XCount - 1
// same for j and y-coordinate
Following the suggestions in the comments I have written the following code:
def f(x, y, points):
points = sorted(points)
xunique = np.unique([point[0] for point in points])
yunique = np.unique([point[1] for point in points])
xmax = np.max(xunique)
ymax = np.max(yunique)
deltax = xunique[1] - xunique[0]
deltay = yunique[1] - yunique[0]
x0 = xunique[0]
y0 = yunique[0]
ni = len(xunique)
nj = len(yunique)
i1 = int(np.floor((x-x0)/deltax))
if i1 == ni:
i1 = i1 - 1
i2 = int(np.ceil((x-x0)/deltax))
if i2 == ni:
i2 = i2 - 1
j1 = int(np.floor((y-y0)/deltay))
if j1 == nj:
j1 = j1 - 1
j2 = int(np.ceil((y-y0)/deltay))
if j2 == ni:
j2 = j2 - 1
pp=[]
if (i1==i2):
if i1>0:
i1=i1-1
else:
i2=i2+1
if (j1==j2):
if j1>0:
j1=j1-1
else:
j2=j2+1
pp=[points[i1 * nj + j1], points[i1 * nj + j2],
points[i2 * nj + j1], points[i2 * nj + j2]]
(x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = pp
return (q11 * (x2 - x) * (y2 - y) +
q21 * (x - x1) * (y2 - y) +
q12 * (x2 - x) * (y - y1) +
q22 * (x - x1) * (y - y1)) / ((x2 - x1) * (y2 - y1))

Calculating the sine, cosine and angle between 3 points

I've written a function to calculate the cosine, sine and degrees of the angle between three points of which I have the x and y coordinates - point 1 (x1, y1), point 2 (x2, y2) and point 3 (x3, y3). I've written the function and been trying to test it out, but I'm not completely confident in how accurate it is. Does anyone know if I've made a mistake in my calculations?
def path_angle_degree(x1, y1, x2, y2, x3, y3):
u = (x2 - x1, y2 - y1)
v = (x3 - x2, y3 - y2)
norm_u = math.sqrt(u[0] * u[0] + u[1] * u[1])
norm_v = math.sqrt(v[0] * v[0] + v[1] * v[1])
# this conditional is to check there has been movement between the points
if norm_u < 0.001 or norm_v < 0.001:
return (None, None, None)
prod_n = norm_u * norm_v
dot_uv = u[0] * v[0] + u[1] * v[1]
cos_uv = dot_uv / prod_n
# fixes floating point rounding
if cos_uv > 1.0 or cos_uv < -1.0:
cos_uv = round(cos_uv)
radians = math.acos(cos_uv)
sin_uv = math.sin(radians)
degree = math.degrees(radians)
return (cos_uv, sin_uv, degree)
An example of this function being called on a straight path would be:
print(path_angle_degree(6,6,7,6,8,6))
Thanks so much!
In addition to being expensive, sin_uv is unstable and doesn't cope with numerous edge cases. Use the cross product instead (you only need the z-component).
Also, you'll find it simpler and cheaper to normalize u and v before computing the products.
Once you have cos_uv and sin_uv, use atan2 to get the angle.
You might want to look at the arctan2() function.

Check if two lines (each with start-end positions) overlap in python

I have the following two sets of position each correspond to the start and end position:
line T: t1-t2 (t1 = start_pos, t2 = end_pos)
line S: s1-s2 (s1 = start_pos, t2 = end_pos)
I want to write the algorithm in Python to check if T intersect with S.
Example 1:
t1-t2=55-122 and s1-s2=58-97
s1------------s2
t1-----------------t2
This should return True
Example 2:
t1-t2=4-66 / t1-t2=143-166 and s1-s2=80-141
s1----s2
t1--t2 t1---t2
Both instances of T should return False
But why this code failed:
def is_overlap(pos, dompos):
"""docstring for is_overlap"""
t1,t2 = [int(x) for x in pos.split("-")]
s1,s2 = [int(x) for x in dompos.split("-")]
# Here we define the instance of overlapness
if (t1 >= s1 and t2 >= s2) or \
(t1 >= s1 and t2 <= s2) or \
(t1 <= s1 and t2 >= s2) or \
(t1 <= s1 and t2 <= s2):
return True
else:
return False
which output this:
In [2]: is_overlap('55-122', '58-97')
Out[2]: True
In [3]: is_overlap('4-66', '80-141')
Out[3]: True
In [4]: is_overlap('143-166', '80-141')
Out[4]: True
What's the right way to do it?
Consider a span [a, b] and another span [x, y]. They either overlap or they are separate.
If they are separate, one of two things must be true:
[a, b] is to the left of [x, y], or
[x, y] is to the left of [a, b].
If [a, b] is to the left of [x, y], we have b < x.
If [x, y] is to the left of [a, b], we have y < a.
If neither of these is true, the spans cannot be separate. They must overlap.
This logic is implemented in the following function.
def are_separate(r, s): # r and s are ordered pairs
(a, b) = r
(x, y) = s
if b < x or y < a:
return True
else:
return False
More concisely:
def are_separate(r, s):
(a, b) = r
(x, y) = s
return b < x or y < a
Even more concisely:
def are_separate(r, s):
return r[1] < s[0] or s[1] < r[0]
If you want the contrary function, are_overlapping, just negate the expression:
def are_overlapping(r, s):
return not(r[1] < s[0] or s[1] < r[0])
Which is logically equivalent to:
def are_overlapping(r, s):
return r[1] >= s[0] and s[1] >= r[0]
Your conditions are wrong; check them again. For instance, the first condition implies that (t_1, t_2) = (100, 200) and (s_1, s_2) = (50, 60) to be a valid set of overlapping lines. But clearly, they aren't.
Something else you might want to consider is if the user inputs the coordinates in backwards. What if he puts in something like '80-30'?
For those who want two lines in two dimensions, #michael's answer is not enough. The following code is based on the equation found in the Wikipedia page listed just above the code as well as a little Pythagoras to check the intersection lies between the appropriate points. https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
x1, y1, x2, y2 = 200, 200, 300, 300
x3, y3, x4, y4 = 200, 150, 300, 350
px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / \
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / \
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
if ((x1 - px) ** 2 + (y1 - py) ** 2) ** 0.5 + ((x2 - px) ** 2 + (y2 - py) ** 2) ** 0.5 == \
((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5 and \
((x3 - px) ** 2 + (y3 - py) ** 2) ** 0.5 + ((x4 - px) ** 2 + (y4 - py) ** 2) ** 0.5 == \
((x3 - x4) ** 2 + (y3 - y4) ** 2) ** 0.5:
print("Overlap at point: (%s, %s)" % (px, py))
else:
print("No overlap.")

Plane equation for 3D vectors

I want to find a 3D plane equation given 3 points. I have got the normal calculated after applying the cross product. But the equation of a plane is known to be the normal multiply by another vector which what I am taught to be as P.OP. I substitute my main reference point as OP and i want P to be in (x, y, z) form. So that I can get something like e.g,
OP = (1, 2, 3)
I want to get something like that:
(x-1)
(y-2)
(z-3)
May I know how?
Below is my reference code.(Note: plane_point_1_x(), plane_point_1_y(), plane_point_1_z() are all functions asking for the user input of the respective points)
"""
I used Point P as my reference point so I will make use of it in this section
"""
vector_pop_x = int('x') - int(plane_point_1_x())
vector_pop_y = int('y') - int(plane_point_1_y())
vector_pop_z = int('z') - int(plane_point_1_z())
print vector_pop_x, vector_pop_y, vector_pop_z
All the above is what i did, but for some reason it did not work. I think the problem lies in the x, y , z part.
Say you have three known points, each with (x, y, z). For example:
p1 = (1, 2, 3)
p2 = (4, 6, 9)
p3 = (12, 11, 9)
Make them into symbols that are easier to look at for further processing:
x1, y1, z1 = p1
x2, y2, z2 = p2
x3, y3, z3 = p3
Determine two vectors from the points:
v1 = [x3 - x1, y3 - y1, z3 - z1]
v2 = [x2 - x1, y2 - y1, z2 - z1]
Determine the cross product of the two vectors:
cp = [v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]]
A plane can be described using a simple equation ax + by + cz = d. The three coefficients from the cross product are a, b and c, and d can be solved by substituting a known point, for example the first:
a, b, c = cp
d = a * x1 + b * y1 + c * z1
Now do something useful, like determine the z value at x=4, y=5. Re-arrange the simple equation, and solve for z:
x = 4
y = 5
z = (d - a * x - b * y) / float(c) # z = 6.176470588235294
If I am not mistaken, one good solution here contains mistypes
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * (vector1[0] * vector2[2] - vector1[2] * vector2[0]), vector1[0] * vector2[1] - vector1[1] * vector2[0]]
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = - (cross_product[0] * x1 + cross_product[1] * y1 + cross_product[2] * z1)
Tried previous (author's) version, but had to check it. With couple more minuses in formulas seems correct now.
One good way is:
| x1 y1 z2 1 |
| x2 y2 z2 1 |
| x3 y3 z3 1 | = 0
| x y z 1 |
Where the vertical pipes mean the determinant of the matrix, and (x1 y1 z1), (x2 y2 z2), and (x3 y3 z3) are your given points.
Plane implicit Eqn:
All points P = (x, y, z) satisfying
<n, QP> = 0
where
n is the plane normal vector,
Q is some point on the plane (any will do)
QP is the vector from Q to P
<a, b> is the scalar (dot) product operator.
(Remember that QP can be computed as P - Q)
I wish this answer already existed. Coded from http://www.had2know.com/academics/equation-plane-through-3-points.html
Supposing 3 points p1, p2, p3 - consisting of [x1, y1, z1], etc.
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * vector1[0] * v2[2] - vector1[2] * vector2[0], vector1[0] * vector2[1] - vector1[1] * vector2[0]]
d = cross_product[0] * x1 - cross_product[1] * y1 + cross_product[2] * z1
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = d

Categories