combine two loops in python - python

suppose to have two polygons p1 and p2, where p2 is completely inside p1
p1 = [(0, 10), (10, 10), (10, 0), (0, 0)]
p2 = [(2, 6), (6, 6), (6, 2), (2, 2)]
degree_of_contact = 0
xyarrays = [p1,p2]
p1_degree_of_contact = 0
for x,y in xyarrays[0]:
if point_inside_polygon(x,y,xyarrays[1]):
p1_degree_of_contact += 1
p2_degree_of_contact = 0
for x,y in xyarrays[1]:
if point_inside_polygon(x,y,xyarrays[0]):
p2_degree_of_contact += 1
degree_of_contact = p1_degree_of_contact + p2_degree_of_contact
where point_inside_polygon is to deciding if a point is inside (True, False otherwise) a polygon,
where poly is a list of pairs (x,y) containing the coordinates of the polygon's vertices. The algorithm is called the "Ray Casting Method
i wish to combine in an elegant way (line coding save) both loops in one.

The following should work:
degree_of_contact = 0
for tmp1, tmp2 in [(p1, p2), (p2, p1)]:
for x,y in tmp1:
if point_inside_polygon(x, y, tmp2):
degree_of_contact += 1

degree_of_contact = sum(point_inside_polygon(x, y, i) for i, j in ((p1, p2), (p2, p1)) for x, y in j)

Related

nested list with multiple conditions

Trying to create a list of tuples like so:
m=[-1,0,1]
[(self._x+x,self._y) for x in m for y in m]
But I want to exclude the tuple when both x and y are equal to 0. I've tried:
[(self._x+x,self._y) for x in m for y in m if x!=0 and y!=0]
but it doesn't work.
Thanks.
m = [-1, 0, 1]
# so you want all combinations x and y out of m
# but only if x and y are not both 0 at the same time?
[ (x, y) for x in m for y in m if not (x == 0 and y == 0) ]
## => [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
Your code's problem are the self. - which occurs only within class definitions.
self._x + x is x from the for loop plus a certain self._x value, whatever that is. self._y is not y.
What you want with this actually? you don't use y from the second for loop at all in your code.

Determining neighbours of cell as diamond shape in python

I have a matrix variable in size where 1 indicates the cell such as:
Cells = [[0,0,0,0,0],
[0,0,0,0,0],
[0,0,1,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
]
I need to find neigbours in a parametric sized diamond shape. Not a box as answer given in here or not a fixed sized 1 diamond, answer given here. For example, N=2 I want to know the column, rows for below:
Mask = [[0,0,1,0,0],
[0,1,1,1,0],
[1,1,0,1,1],
[0,1,1,1,0],
[0,0,1,0,0],
]
The function should receive x and y for the requested column and row, (for above I will input 2,2) and N (input 2) the size of diamond. The function should return list of tuples (x,y) for the given diamond size.
I struggled at defining the shape as a function of x, y and k in for loops. I need to know both numpy (if there is anything that helps) and non-numpy solution.
For an iterative approach where you just construct the diamond:
def get_neighbors(center, n=1):
ret = []
for dx in range(-n, n + 1):
ydiff = n - abs(dx)
for dy in range(-ydiff, ydiff + 1):
ret.append((center[0] + dx, center[1] + dy))
return ret
Result of get_neighbors((2, 2), 2):
[(0, 2), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (4, 2)]
Or, for a recursive approach:
dirs = [(1, 0), (0, 1), (-1, 0), (0, -1)]
def add_tuples(a, b):
return tuple([x + y for (x, y) in zip(a, b)])
def get_neighbors(center, n=1, seen=set()):
seen.add(center)
if n <= 0:
return seen
for dir in dirs:
newpos = add_tuples(center, dir)
if newpos in seen:
continue
get_neighbors(newpos, n - 1, seen)
return seen
I would start by taking out a "sub-matrix" that is the smallest square that can contain your result cells. This is the part that numpy should be able to help with.
Then define a function that calculates the manhattan distance between two cells (abs(x - x_p) + abs(y - y_p)) and iterate through the cells of your sub-matrix and return the values with a manhattan distance of less than N from your origin.
Make mask with rotation
Convolute cell and mask
Fix the result
import numpy as np
from scipy.ndimage import rotate, convolve
import matplotlib.pyplot as plt
def diamond_filter(radius):
s = radius * 2 + 1
x = np.ones((s, s), dtype=int)
x[radius, radius] = 0
return rotate(x, angle=45)
def make_diamonds(x, radius):
filter = diamond_filter(radius)
out = convolve(x, filter)
out[out > 1] = 1
out -= x
out[out < 0] = 0
return out
def plot(x):
plt.imshow(x)
plt.show()
plt.close()
def main():
cell = np.random.choice([0, 1], size=(200, 200), p=[0.95, 0.05])
plot(diamond_filter(2))
plot(cell)
result = make_diamonds(cell, 2)
plot(result)
if __name__ == '__main__':
main()

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

how to get my for loop to compute the distance between coordinates in list

Im writing a program to calculate distances for each element of a list between latitude and longitude from a file, for instance if my points list has five points p1,p2,p3,p4,
and p5, I want the program to find the distance between points p1 and
p2, p1 and p3, p1 and p4, and p1 and p5. Then compute the distance
between p2 and p3, p2 and p4, p2 and p5 and so on.but cant get the output to calculate the distance between all points in my list.
input from file is
62.24186067241206,110.85699280829596
32.59293412296685,170.1144522172567
57.96358548631895,65.88075339171547
24.001352068102108,1.3473208526774272
-64.06840683422311,153.52144681056024
infile=open('test_part2.txt','r')
lines=infile.readlines()
infile.close()
def get_distance(p1,p2):
x1=p1[0]
y1=p1[1]
x2=p2[0]
y2=p2[1]
d=(x1-x2)**2+(y1-y2)**2
d=d**0.5
return d
print ('Pairwise distance between points:')
points=[]
for line in lines:
line = line.strip()
tokens=line.split(",")
lat=float(tokens[0].strip())
lon=float(tokens[1].strip())
point=[]
point.append(lat)
point.append(lon)
points.append(point)
for i in range(0,len(points)):
d=get_distance(point,points[i])
print(d)
expected output is
66.26088847230339
45.17926239576636
115.99441689212239
133.32118853696534
107.27690301949622
168.9856796040263
98.07518883014596
72.92459951226348
150.24213221549
175.82163417554528
You are almost there, you just need to go through the points in two loops. I am assuming we don't have a performance issue here. Also, assuming the points are the way you have described earlier.
62.24186067241206,110.85699280829596
32.59293412296685,170.1144522172567
Updated your code
infile = open('test_part2.txt', 'r')
lines = infile.readlines()
infile.close()
def get_distance(p1, p2):
x1 = p1[0]
y1 = p1[1]
x2 = p2[0]
y2 = p2[1]
d = (x1 - x2) ** 2 + (y1 - y2) ** 2
d = d ** 0.5
return d
print('Pairwise distance between points:')
points = []
for line in lines:
line = line.strip()
tokens = line.split(",")
lat = float(tokens[0].strip())
lon = float(tokens[1].strip())
point = [lat, lon]
points.append(point)
for i in range(0, len(points)):
for j in range(i+1, len(points)):
d = get_distance(points[j], points[i])
print(d)
The itertools module provides a combinations function which looks ideal for this, assuming your data is a list of tuple pairs, for example:
import itertools as it
#
if __name__ == "__main__":
points =[(0,0), (4,0), (4,3), (1,1)]
temp = list(it.combinations(points, 2))
for pair in temp:
print(f"{pair} distance = {get_distance(pair[0], pair[1])}")
Gives this output:
(0, 0), (4, 0) = 4.0
(0, 0), (4, 3) = 5.0
(0, 0), (1, 1) = 1.4142135623730951
(4, 0), (4, 3) = 3.0
(4, 0), (1, 1) = 3.1622776601683795
(4, 3), (1, 1) = 3.605551275463989
Edit if you can't use itertools, this might be a workaround:
count = 0
combos = []
while count < len(points):
temp = [(points[count], x) for x in points[count+1:]]
combos.extend(temp)
count += 1
for x in combos:
print x
The list comprehension is not too hard to break down into for loops if that's what your school requires. Slicing is more or less a must, however.

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

Categories

Resources