divide ways on a map in parts of length one - python

I have these coordinates:
coord = [(10,10), (13,10), (13,13)]
Now i need new coordinates.
The way between two coordinates is always one.
For example:
(10,10)
(11,10)
(12,10)
(13,10)
(13,11)
(13,12)
(13,13)
Any ideas?
#
I found the solution.
for n in range(len(coord)-1):
lengthx = coord[n+1][0] - coord[n][0]
lengthy = coord[n+1][1] - coord[n][1]
length = (lengthx**2 + lengthy**2)**.5
for m in range(length):
print coord[n][0]+lengthx/length*m, coord[n][1]+lengthy/length*m

A simple variation on Bresenham's line algorithm will achieve what you want using integer arithmetic only (so it should be noticeably faster):
def steps(path):
if len(path) > 0:
for i in range(1, len(path)):
for step in steps_between(path[i - 1], path[i]):
yield step
yield path[-1]
def steps_between(start, end):
x0, y0 = start
x1, y1 = end
steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
x0, y0 = y0, x0
x1, y1 = y1, x1
if y0 > y1:
x0, x1 = x1, x0
y0, y1 = y1, y0
if y0 < y1:
ystep = 1
else:
ystep = -1
deltax = x1 - x0
deltay = abs(y1 - y0)
error = -deltax / 2
y = y0
for x in range(x0, x1):
if steep:
yield (y, x)
else:
yield (x, y)
error += deltay
if error > 0:
y += ystep
error -= deltax
if steep:
yield (y, x)
else:
yield (x, y)
coords = [(10, 10), (13, 10), (13, 13)]
print "\n".join(str(step) for step in steps(coords))
The above prints:
(10, 10)
(11, 10)
(12, 10)
(13, 10)
(13, 11)
(13, 12)
(13, 13)
Of course, Bresenham works as expected when both x and y change between two points on the path:
coords = [(10, 10), (13, 12), (15, 13)]
print "\n".join(str(step) for step in steps(coords))
That prints:
(10, 10)
(11, 10)
(11, 11)
(12, 11)
(12, 12)
(13, 12)
(14, 12)
(14, 13)
(15, 13)

Related

How to store an inner list to an outer list

#Total distance values are stored here
total_dis = []
#Permutation of cooridnates
perm = permutations(result_List, num_dot)
for i in perm:
route = list(i)
route.append(route[0])
print(route)
for (x1, y1), (x2, y2) in zip(route, route[1:]):
distance_formula = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
print(distance_formula)
I am calculating the distance between the points of each of the generated permutations.
[(5, 0), (4, 5), (2, 9), (5, 0)]
5.0990195135927845
4.47213595499958
9.486832980505138
[(5, 0), (2, 9), (4, 5), (5, 0)]
9.486832980505138
4.47213595499958
5.0990195135927845
[(4, 5), (5, 0), (2, 9), (4, 5)]
5.0990195135927845
9.486832980505138
4.47213595499958
...
I am trying to store the values of distance_formula in lists within the list total_dis. (I figured storing the floats in a list will allow me to find the sums of each list.) Like so:
[[5.0990195135927845, 4.47213595499958, 9.486832980505138],[9.486832980505138, 4.47213595499958, 5.0990195135927845], [5.0990195135927845, 9.486832980505138, 4.47213595499958],[...]]
I am having trouble creating the new lists for the distances between each point of each permutations to be stored.
Just add three lines
#Total distance values are stored here
total_dis = []
#Permutation of cooridnates
perm = permutations(result_List, num_dot)
for i in perm:
route = list(i)
route.append(route[0])
print(route)
dis_list = [] # <---- Add this line
for (x1, y1), (x2, y2) in zip(route, route[1:]):
distance_formula = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
print(distance_formula)
dis_list.append(distance_formula) # <---- Add this line
total_dis.append(dis_list) # <---- Add this line (outside the "distance" loop)
You might even opt to do it as a nested list comprehension, though it might be a lot less readable.
total_dis = [
[
math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
for (x1, y1), (x2, y2) in zip(
i + (i[0], )[:-1],
i + (i[0], )[1:]
)
[
for i in permutations(result_List, num_dot)
]

Finding clusters of line segments in a list

I have a list of line segments represented as x and y coordinates and I'm trying to find groups of lines such that all angles within the group are within 20 degrees. But my problem is that math.degrees(math.atan2(-0.1,-1)) (=-174.29) and math.degrees(math.atan2(0.1,-1)) (=174.29) should make two points in the same group, but the difference in face value is greater than 20. I wonder if my code should do what I want and avoids the 180/-180 problem:
import math
endpoints = [((2, 11), (2, 8)), ((11, 3), (2, 5)), ((13, 7), (9, 12)), ((5, 5), (15, 12)), ((15, 4), (8, 1)), ((15, 14), (14, 3)), ((2, 4), (6, 5)), ((1, 13), (13, 11)), ((8, 11), (12, 15)), ((12, 4), (7, 1))]
def find_angle(p1,p2):
x1 = p1[0]
y1 = p1[1]
x2 = p2[0]
y2 = p2[1]
dx = max(x2-x1,x1-x2)
if dx == x2-x1:
dy = y2-y1
else:
dy = y1-y2
return math.degrees(math.atan2(dy,dx))
endpointsbyangle = sorted([(find_angle(p1,p2), (p1,p2)) for p1, p2 in endpoints], key=lambda x: x[0])
prev = -190
group = []
allgroups = []
for (theta, (p1, p2)) in endpointsbyangle:
if prev == -190:
group.append((p1,p2))
prev = theta
else:
if abs(prev - theta) < 20:
group.append((p1,p2))
else:
allgroups.append(group)
group = [(p1,p2)]
prev = theta
print dict(enumerate(allgroups))
Any thought appreciated.
One way is to replace your line
if abs(prev - theta) < 20:
with
if abs(prev - theta) < 20 or abs(prev - theta) > 340:
This then captures the situations where the calculated angle is near 360 degrees.
However, if I understand you, you have another problem. If the angle ABC is exactly 5 degrees (for example), and angle CAB is also 5 degrees, then angle ACB is 170 degrees and would fail your test. In other words, it is not possible for "all angles within the group are within 20 degrees" for a group of 3 points. You should also allow an angle to be within 20 degrees of 180 degrees. So perhaps you should use the line
if (abs(prev - theta) < 20
or abs(prev - theta) > 340
or abs(prev - theta - 180) < 20):
That depends on exactly what you mean by your requirement "all angles within the group are within 20 degrees."

Is there a better way to find points along a curve than Bresenham's line algorithm

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.))

Python : How to store a value generated in a function for the second call of that function

I want to create a random number generation code that inputs "count" number which is that how many times it is called in the program. What I want to do is for the even number of calls of the function I want to create 2 random numbers which are "y1 ,y2" however I want to output y1 only and save y2 for the next call of the function. So at the odd number of calls the function will directly output y2 of the previous call. Thanks for help. The code so far:
import random
import math
def gaussianRandom ( count):
count += 1
if count%2 == 0:
while (1):
x1 = random.uniform(-1, 1)
x2 = random.uniform(-1, 1)
r = x1**2 + x2**2
if (r < 1):
break
y1 = x1 * math.sqrt( (-2 * math.log(r)) / r )
y2 = x2 * math.sqrt( (-2 * math.log(r)) / r )
return y1
functions can have attributes.
import random
import math
def gaussianRandom ( count):
count += 1
if count%2 == 0:
while (1):
x1 = random.uniform(-1, 1)
x2 = random.uniform(-1, 1)
r = x1**2 + x2**2
if (r < 1):
break
y1 = x1 * math.sqrt( (-2 * math.log(r)) / r )
gaussianRandom.y2 = x2 * math.sqrt( (-2 * math.log(r)) / r )
print(gaussianRandom.y2)
return y1
gaussianRandom.y2 = 99
print "y2", gaussianRandom(3)
print gaussianRandom(3)
print gaussianRandom(3)
y2 0.919282832355
-0.0887376744533
y2 -1.71553385287
0.422645022058
y2 -0.0668389339817
0.600351205084
Do you really need (or want) to tell gaussianRandom() how many times you intend to call it? That seems a bit restrictive to me.
I think this problem would be better solved using a generator function. The code below shows how to create one and a couple of ways of how to use it. Rather than implementing your Gaussian algorithm, this generator simply generates numbers of the form 6n±1, so you can easily see what's going on.
#! /usr/bin/env python
''' Generator demo '''
def gen():
x = 6
while True:
yield x-1
yield x+1
x += 6
def main():
g = gen()
for i in xrange(10):
print i, g.next()
print [(i, v) for i,v in zip(xrange(10), gen())]
if __name__ == "__main__":
main()
output
0 5
1 7
2 11
3 13
4 17
5 19
6 23
7 25
8 29
9 31
[(0, 5), (1, 7), (2, 11), (3, 13), (4, 17), (5, 19), (6, 23), (7, 25), (8, 29), (9, 31)]

Draw a line from start(X,Y) to destination(X,Y)

I'm struggling to make a simple game with an world map on which the player will move around, using a click-and-go-along-a-line method. For this I'm trying to make a simple function to calculate a list of XY of pixels for the player to go through.
Most of it works fine, but I'm having issues with it multiplying one of the results by 2 whenever destination X and Y are not equal. I'm having a really tough time troubleshooting this one, and if somebody would have an idea how to improve it or fix it - I'd be very grateful.
import math
def linePath(start, finish):
if start[0] == finish[0]:
a = 1
else:
a = (finish[1] - start[1]) / float((finish[0] - start[0]))
b = start[1] - (a * start[0])
if abs(a) >= 1:
rng = xrange(start[1], finish[1] + 1) or reversed(xrange(finish[1], start[1] + 1))
else:
rng = xrange(start[0], finish[0] + 1) or reversed(xrange(finish[0], start[0] + 1))
for i in rng:
if abs(a) >= 1:
y = i
x = int(math.ceil((y - b)/ a))
else:
x, y = i, start[1] + int(math.ceil(a * i + b))
if start[0] != finish[0]:
yield x, y
else:
yield start[0], y
start = (10, 10)
destination = (15, 15)
print list(linePath(start, destination))
#Bugs: when start[0] > start[1] and start > destination (eg. destination = (16, 15))
#when start[0] < start[1] and start < destination (eg. destination = (5, 6))
Luckily, Jack Elton Bresenham solved this problem 1962 for you.
Here's an implementation of the Bresenham's line algorithm, found at Roguebashin:
def get_line(x1, y1, x2, y2):
points = []
issteep = abs(y2-y1) > abs(x2-x1)
if issteep:
x1, y1 = y1, x1
x2, y2 = y2, x2
rev = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
rev = True
deltax = x2 - x1
deltay = abs(y2-y1)
error = int(deltax / 2)
y = y1
ystep = None
if y1 < y2:
ystep = 1
else:
ystep = -1
for x in range(x1, x2 + 1):
if issteep:
points.append((y, x))
else:
points.append((x, y))
error -= deltay
if error < 0:
y += ystep
error += deltax
# Reverse the list if the coordinates were reversed
if rev:
points.reverse()
return points
start = (10, 10)
destination = (16, 15)
print list(get_line(start[0], start[1], destination[0], destination[1]))
Output:
[(10, 10), (11, 11), (12, 12), (13, 12), (14, 13), (15, 14), (16, 15)]

Categories

Resources