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))
Related
I'm trying to find middlepoint on the circle between 2 points, pictorial drawing
There are given radius, p1, p2 and middle of the circle.
Distance betweeen p1 and p2 is an diameter, and I'm trying to make up python formula that returns point on the circle between those 2 points. I know this is rather silly question but I'm trying to make this for 3 hours now and all I can find on web is distance between those 2 points.
I'm trying to find formula for p3 (like in the picture)
That's what I ended up making so far:
import math
points = [[100, 200], [250, 350]]
midpoint = (int(((points[0][0] + points[1][0]) / 2)), int(((points[0][1] + points[1][1]) / 2)))
radius = int(math.sqrt(((points[1][0] - points[0][0])**2) + ((points[1][1] - points[0][1])**2))) // 2
# This below is wrong
print(int(midpoint[0] - math.sqrt((points[0][1] - midpoint[1]) ** 2)),
int(midpoint[1] - math.sqrt((points[0][0] - midpoint[1]) ** 2)))
There is no need for trigonometry, which is total overkill.
The center of the circle is Xs= (X1 + X2) / 2, Ys= (Y1 + Y2) / 2.
The two opposite "middlepoints" are given by X3 = Xs - (Y1 - Ys), Y3 = Ys + (X1 - Xs) and X4 = Xs + (Y1 - Ys), Y4 = Ys - (X1 - Xs).
If you prefer direct formulas, X3 = (X1 + X2 - Y1 + Y2) / 2, Y3 = (X1 - X2 + Y1 + Y2) / 2...
To generate points on the circle use polar equation (https://math.stackexchange.com/questions/154550/polar-equation-of-a-circle)
import math
import random
points = [[100, 200], [250, 350]]
midpoint = (int(((points[0][0] + points[1][0]) / 2)), int(((points[0][1] + points[1][1]) / 2)))
radius = int(math.sqrt(((points[1][0] - points[0][0])**2) + ((points[1][1] - points[0][1])**2))) // 2
angle = random.uniform(0, 2 * math.pi)
x_relative = radius * math.cos(angle)
y_relative = radius * math.sin(angle)
x = midpoint[0] + x_relative
y = midpoint[1] + y_relative
print(f"{x} {y}")
To find middle point on the circle between points:
import math
points = [[100, 200], [250, 350]]
midpoint = (int(((points[0][0] + points[1][0]) / 2)), int(((points[0][1] + points[1][1]) / 2)))
radius = int(math.sqrt(((points[1][0] - points[0][0])**2) + ((points[1][1] - points[0][1])**2))) // 2
points_relative = [[points[0][0] - midpoint[0], points[0][1] - midpoint[1]], [points[1][0] - midpoint[0], points[1][1] - midpoint[1]]]
midpoint_points_relative = [[points_relative[0][1], - points_relative[0][0]], [points_relative[1][1], - points_relative[1][0]]]
midpoint_points = [[midpoint_points_relative[0][0] + midpoint[0], midpoint_points_relative[0][1] + midpoint[1]], [midpoint_points_relative[1][0] + midpoint[0], midpoint_points_relative[1][1] + midpoint[1]]]
print(points)
print(midpoint)
print(points_relative)
print(midpoint_points)
You can use this page to test results: https://www.desmos.com/calculator/mhq4hsncnh
I am trying to write a numerical integral calculator as my first Python project. The method takes a starting x value, a delta x value, and a set of y values and returns a lower and an upper bound. I am expecting the result of the numerical integration to converge as dx gets smaller, but it is getting larger.
I am trying to integrate an exponential from 0 to 1 and get the result to converge to 1/3 as dx gets smaller. Currently a dx of 0.1 gives me bounds of (0.14000000000000004, 0.17200000000000004). A dx of 0.01 has bounds of (0.30894500000000014, 0.313747).
Here is my code:
class Linear:
"""Creates a linear function from 2 points"""
def __init__(self, x0, y0, x1, y1):
self.__x0 = x0
self.__y0 = y0
self.__x1 = x1
self.__y1 = y1
self.__a = ((y1 - y0) / (x1 - x0))
self.__b = y0 - (self.__a * x0)
def fun(self, x):
return self.__a * x + self.__b
def integrate(x0, dx, data):
if len(data) < 3:
raise ValueError("data passed to integrate doesn't have enough data")
else:
i, lb, ub = 2, 0, 0
while i < len(data):
y0, y1, y2 = data[i - 2], data[i - 1], data[i]
lin = Linear(x0, y0, x0 + dx + dx, y2)
lin_delta = lin.fun(x0 + dx)
if y1 < lin_delta:
if y0 < y1:
lb += (y0 * dx)
ub += ((((y1 - y0) * dx) / 2) + (y0 * dx))
else:
lb += (y1 * dx)
ub += ((((y0 - y1) * dx) / 2) + (y1 * dx))
else:
if y0 < y1:
ub += (y1 * dx)
lb += ((((y1 - y0) * dx) / 2) + (y0 * dx))
else:
ub += (y0 * dx)
lb += ((((y0 - y1) * dx) / 2) + (y1 * dx))
i += 1
x0 += dx
return lb, ub
if __name__ == '__main__':
j = 0
d = []
dxj = 0.1
while j < (1/dxj):
d += [(j * dxj) * (j * dxj)]
j += 1
print(d)
print(integrate(0, dxj, d))
Also, what is the best way to avoid name collisions with counters like i?
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/
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.")
I'm looking for a short smart way to find all integer points on a line segment. The 2 points are also integers, and the line can be at an angle of 0,45,90,135 etc. degrees.
Here is my long code(so far the 90 degree cases):
def getPoints(p1,p2)
if p1[0] == p2[0]:
if p1[1] < p2[1]:
return [(p1[0],x) for x in range(p1[1],p2[1])]
else:
return [(p1[0],x) for x in range(p1[1],p2[1],-1)]
if p2[1] == p2[1]:
if p1[0] < p2[0]:
return [(x,p1[1]) for x in range(p1[0],p2[0])]
else:
return [(x,p1[1]) for x in range(p1[0],p2[0],-1)]
EDIT: I haven't mentioned it clear enough, but the slope will always be an integer -1, 0 or 1, there are 8 cases that are need to be checked.
Reduce the slope to lowest terms (p/q), then step from one endpoint of the line segment to the other in increments of p vertically and q horizontally. The same code can work for vertical line segments if your reduce-to-lowest-terms code reduces 5/0 to 1/0.
Do a little bit of maths for each pair of points calculate m & c for mx+c and compare it to the formulae for the lines you are considering. (N.B. You Will get some divide by zeros to cope with.)
i could write code that works, but the amount of repeating code is
throwing me off, that's why i turned to you guys
This could stand a lot of improvement but maybe it gets you on the track.
(sorry, don't have time to make it better just now!)
def points(p1,p2):
slope = (p2[1]-p1[1])/float(p2[0]-p1[0])
[(x,x*slope) for x in range (p1[0], p2[0]) if int(x*slope) == x*slope)]
Extending the answer of #Jon Kiparsky.
def points_on_line(p1, p2):
fx, fy = p1
sx, sy = p2
if fx == sx and fy == sy:
return []
elif fx == sx:
return [(fx, y) for y in range(fy+1, sy)]
elif fy == sy:
return [(x, fy) for x in range(fx+1, sx)]
elif fx > sx and fy > sy:
p1, p2 = p2, p1
slope = (p2[1] - p1[1]) / float(p2[0] - p1[0])
return [(x, int(x*slope)) for x in range(p1[0], p2[0]) if int(x*slope) == x*slope and (x, int(x*slope)) != p1]
def getpoints(p1, p2):
# Sort both points first.
(x1, y1), (x2, y2) = sorted([p1, p2])
a = b = 0.0
# Not interesting case.
if x1 == x2:
yield p1
# First point is in (0, y).
if x1 == 0.0:
b = y1
a = (y2 - y1) / x2
elif x2 == 0.0:
# Second point is in (0, y).
b = y2
a = (y1 - y2) / x1
else:
# Both points are valid.
b = (y2 - (y1 * x2) / x1) / (1 - (x2 / x1))
a = (y1 - b) / x1
for x in xrange(int(x1), int(x2) + 1):
y = a * float(x) + b
# Delta could be increased for lower precision.
if abs(y - round(y)) == 0:
yield (x, y)