2

I'm trying to make a program to get azimuth value from two points using this code:

import math
def azimuth(x1, x2, y1, y2):
 temp = (y2 - y1) / (x2 - x1)
 res = math.degrees(abs(math.atan(temp)))
 if x2 > x1 and y2 > y1: #Q1
 res = 90 - res
 elif x2 < x1 and y2 > y1: #Q2
 res = (90 - res) * -1
 elif x2 < x1 and y2 < y1: #Q3
 res = (90 + res) * -1
 elif x2 > x1 and y2 < y1: #Q4
 res += 90
 else:
 raise ValueError('No point difference.')
 return res

I've been able to get azimuth value with range (-180)-180. Next, I need to split it into two groups of azimuth value equaly based on range of value. The goal is to get two group which get the closest azimuth value.

The problem is that pairs of points on quadrant III ((-180)-(-90)) and quadrant IV (90-180) logically can be consider as close (e.g:(-179) and 179). About how to split it equally, I've been thinking of using sorted list of azimuth and using index idx = int(math.ceil((len(lst)-1)/2)) as the median to split the list. This is how I do it on code:

lst = [-60, -50, -40, -30, -20, -10, 10, 20, 30, 40, 50, 60]
def split_list(lst):
 lst.sort()
 idx = int(math.ceil((len(lst)-1)/2))
 left = []
 right = []
 for i in lst:
 if i < lst[idx]:
 left.append(i)
 else:
 right.append(i)
 print(left)
 print(right)
 return left, right
split_list(lst)

The code above will return list [-60, -50, -40, -30, -20, -10] and [10, 20, 30, 40, 50, 60] as the result.

Is there any idea of how to do this? With the current condition, I don't have any idea of how to make quadrant III and IV considered as close.

asked Mar 15, 2022 at 12:50
6
  • Do I understand correctly that you have a set of coordinates that you want to split into two sets with minimal radial distance among the coordinates? Should the number of elements in the sets be equal, or the sum of the residuals be minimal? Commented Mar 15, 2022 at 14:07
  • Yes, I have a set of coordinates that wanted to be split into two sets with minimal radial distance among the coordinates. The number of elements in the sets tried to be equal as possible. Commented Mar 16, 2022 at 3:20
  • Two observations: 1) isn't this what atan2 is for? 2) Is this question actually about the math at all? I don't think the code is relevant to the problem you describe, since you are only asking "how do I bin the values together?" which would be the same problem no matter how you actually got the values. Please read How to Ask and stackoverflow.com/help/minimal-reproducible-example, and try to ask the actual question you have. Commented Mar 16, 2022 at 4:17
  • "I need to split it into two groups of azimuth value equaly based on range of value." What does this actually mean? "Based on" how? Please show an example of the input azimuth values, how that input should be split, and explain the underlying logic. Make sure it's complex enough to illustrate why it isn't an easy problem, but no more complex than necessary. Commented Mar 16, 2022 at 4:18
  • I just done editing the question explaination. First of all, yes atan2 seem better to use for this case. The point of my question is about how to split it into two equally list, which every azimuth on the list can be consider as near. With using function split_list(list), it won't let the nearest pairs of points between QIII and QIV (e.g: (-179) and 179) became member of only one splited list. Commented Mar 16, 2022 at 5:45

2 Answers 2

1

You might be interested in math.atan2(y, x).

The point of atan2() is that the signs of both inputs are known to it, so it can compute the correct quadrant for the angle.

Which means that you can remove all the quadrant logic from your code, and basically replace the whole function with math.degrees(math.atan2(y2 - y1, x2 - x1)). It also avoids a division by 0 if x1 == x2.

If you have two azimuths, you can calculate the minimum rotation between both with:

def shortest_rotation(start_angle, end_angle):
 return (end_angle - start_angle + 180) % 360 - 180

You can split the list of azimuths depending on the sign of the output.

Just for fun, here's a small script to split azimuths left and right of split_at_azimuth, and display them on a polar plot:

def shortest_rotation(start_angle, end_angle):
 return (end_angle - start_angle + 180) % 360 - 180
azimuths = list(range(0, 370, 10))
split_at_azimuth = 60
left, right = [], []
for azimuth in azimuths:
 (left, right)[shortest_rotation(azimuth, split_at_azimuth) >= 0].append(azimuth)
import numpy as np
import matplotlib.pyplot as plt
t1 = [np.pi * a / 180 for a in right]
t2 = [np.pi * a / 180 for a in left]
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
ax.plot(t1, [1 for _ in t1], '+')
ax.plot(t2, [1 for _ in t2], '+')
ax.set_rmax(2)
ax.set_rticks([])
ax.grid(True)
ax.set_title("Left and right azimuth", va='bottom')
plt.show()

enter image description here

answered Mar 15, 2022 at 14:17
Sign up to request clarification or add additional context in comments.

Comments

0

Your problem can be reduced to finding a distance between two phase points. I say phase because phase is wrapped (in your case % 360). Thus, you need to compare the distance both ways: clockwise and counter-clockwise. The simplest might be:

dist = min(abs(A2-A1), abs(360+A1-A2)) # requiring A1 <= A2

If the clockwise distance is the smallest, then the first term in min() will be your solution. If counter-clockwise, then the second term in min() will be your solution. To do grouping, you'd then calculate the distances between desired points. Note that arrays don't need to be sorted for this to work, just that A1 <= A2.

answered Mar 15, 2022 at 14:06

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.