Intersection of Parabolas for Voronoi Diagram - python

This is my first question on Stack Overflow, so if I have formatted something incorrectly or not added the correct information, please let me know and I will fix it when I can.
I'm trying to implement Fortune's Algorithm for creating a Voronoi Diagram in Roblox. Roblox uses a more limited version of Lua, so I can't just import modules or copy-paste most code. Fortune's Algorithm uses parabolas to find the points required to make the edges around each site and I found an equation in Fortunes Algorithm: An intuitive explanation that generates a parabola where every point on the parabola is equidistant from the focus and the directrix.
​I know how to find the intersection of two parabolas when they are in standard form, but I have been unable to get the above equation into standard form. I've tried (on paper) putting it on both sides of the equals sign, setting it equal to zero, then expanding the polynomials using wolframAlpha's polynomial expander, producing
[(-X^2 * fx) + (X^2 * f'y) + (2 * dy * fx * X) - (2 * dy * f'x * X) + (2 * f'x * fy * X) - (2 * fx * f'y * X) + (dy^2 * fy) - (dy^2 * f'y) - (dy * fy^2) + (dy * f'y^2) - (fy * f'y^2) + (f'y * fy^2) + (dy * f'x^2) - (f'x^2 * fy) - (dy * fx^2) + (f'y * fx^2)] / [2(dy^2) - (dy * fy) - (dy * f'x) + (fy * f'y))]
where X is a variable, fx and fy are the x and y coordinates of the first focus, f'x and f'y are the x and y coordinates of the second focus, and dy is the y coordinate of the directrix. I am unsure of where to go from here.
I asked this on Stack Overflow in the hopes of finding someone who has implemented it before, but I may also ask it on a more math-related website as I just need the formula that gives the intercept(s). Having said this, if anyone has a code answer to this, Python would be preferred as I am most familiar with it.
Unrelated to the main question, does anyone know if there is a way to format the equation in Stack Overflow that is more easy to look at than a single line, and if so, how?

Related

Solving this system of nonlinear equations with Python

Problem.
Consider the following problem: An experiment consists of three receivers, i,j and k, with known coordinates (xi,yi,zi), (xj,yi... in 3D space. A stationary transmitter, with unknown coordinates (x,y,z), emits a signal with known velocity v. The time of arrival of this signal at each receiver is recorded, giving ti,tj,tk. The signal emission time, t, is unknown.
Using only the coordinates of the receivers and the signal arrival times, I wish to determine the location of the transmitter.
In general, to solve for the coordinates of such a transmitter in N-dimensional space, N+1 receivers are required. Hence, in this case, a single, unique solution is unobtainable. A small number of finite solutions should be obtainable via numerical methods, however.
We may write the following system of equations to model the problem:
Sqrt[(x-xi)^2 + (y-yi)^2 + (z-zi)^2] + s(tj-ti) = Sqrt[(x-xj)^2 + (y-yj)^2 + (z-zj)^2]
Sqrt[(x-xj)^2 + (y-yj)^2 + (z-zj)^2] + s(tk-tj) = Sqrt[(x-xk)^2 + (y-yk)^2 + (z-zk)^2]
Sqrt[(x-xi)^2 + (y-yi)^2 + (z-zi)^2] + s(tk-ti) = Sqrt[(x-xk)^2 + (y-yk)^2 + (z-zk)^2]
Each equation gives a hyperboloid. Under ideal conditions, these three hyperboloids will intersect at precisely two points— one being the "true" solution, and the other being a reflection of that solution about the plane defined by the three receivers. In practice, given sufficiently accurate measurements, numerical solvers should be able to approximate these points of intersection.
My goal is to determine both solutions. Although it is impossible to determine which is the "true" transmitter location, for my purposes this will be sufficient.
Implementation.
I wish to implement a solution in Python. I'm not terribly familiar with NumPy or SciPy, however I've done a fair bit of work in SymPy, so I began there.
SymPy offers a variety of solvers, most of which focus on obtaining solutions symbolically. Not surprisingly, solve() and the like failed to find a solution, even under simulated "ideal" conditions (picking a random point, calculating the time taken for a signal originating from that point to arrive at each receiver, and feeding this to the algorithm).
SymPy also offers a numerical solver, nsolve(). I gave this a go, using the approach given below, however (not surpisingly) I got the error ZeroDivisionError: Matrix is numerically singular.
f = sym.Eq(sym.sqrt((x - x_i)**2 + (y - y_i)**2 + (z - z_i)**2) - sym.sqrt((x - x_j)**2 + (y - y_j)**2 + (z - z_j)**2), D_ij)
g = sym.Eq(sym.sqrt((x - x_i)**2 + (y - y_i)**2 + (z - z_i)**2) - sym.sqrt((x - x_k)**2 + (y - y_k)**2 + (z - z_k)**2), D_ik)
h = sym.Eq(sym.sqrt((x - x_j)**2 + (y - y_j)**2 + (z - z_j)**2) - sym.sqrt((x - x_k)**2 + (y - y_k)**2 + (z - z_k)**2), D_jk)
print("Soln. ", sym.nsolve((f,g,h),(x,y,z), (1,1,1)))
As I understand it, nsolve() relies on "matrix" techniques. A singular matrix is one which may not be inverted (or, equivalently, which has determinant zero), hence SymPy is unable to solve the system in question.
My understanding of matrices and nonlinear system solving techniques is a bit lacking, however my understanding is that a singular matrix occurs when there are infinitely many solutions, no solutions, or more than one solution. Given that I know there to be exactly two solutions, I believe this is the issue.
What Python solvers are available can be used so solve a nonlinear system with multiple solutions? Or, alternatively, is there a way to modify this such that it is digestible by SymPy?
Browsing the Numpy and SciPy docs, it seems that their solvers are effectively identical to what SymPy offers.
The (crude) test code mentioned below:
from random import randrange
import math
# SIMPLE CODE FOR SIMULATING A SIGNAL
# Set range
N=10
P=100
# Pick nodes to be at random locations
x_1 = randrange(N); y_1 = randrange(N); z_1 = randrange(N)
x_2 = randrange(N); y_2 = randrange(N); z_2 = randrange(N)
x_3 = randrange(N); y_3 = randrange(N); z_3 = randrange(N)
# Pick source to be at random location
x = randrange(P); y = randrange(P); z = randrange(P)
# Set velocity
c = 299792 # km/ns
# Generate simulated source
t_1 = math.sqrt( (x - x_1)**2 + (y - y_1)**2 + (z - z_1)**2 ) / c
t_2 = math.sqrt( (x - x_2)**2 + (y - y_2)**2 + (z - z_2)**2 ) / c
t_3 = math.sqrt( (x - x_3)**2 + (y - y_3)**2 + (z - z_3)**2 ) / c
# Normalize times to remove information about 'true' emission time
earliest = min(t_1, t_2, t_3)
t_1 = t_1 - earliest; t_2 = t2 - earliest; t_3 = t_3 = earliest

Scipy Optimization Solution for Multivariable equation

I have a formula here to calculate the volume.
def VolCalc(H,L,R,V):
return L * ((math.acos((R - H)/R) * R**2) - ((R - H)* math.sqrt((2 * R * H) - H**2))) # Volume
However, I have been given the value of the volume (V) and from this the height (H) must be calculated. The value of Radius (R) and Length (L) is known.
This requires a numerical approximation solution and need to know which Scipy optimisation tool must be used. I've looked myself and struggling to find the correct one.
I appreciate any help with this matter.
I believe you are looking for scipy.optimize.minimize.
And setup this up as a minimisation problem where you are looking to find the minimum of a scalar function:
def target(H):
return abs(V - (L * ((math.acos((R - H)/R) * R**2) - ((R - H)* math.sqrt((2 * R * H) - H**2)))))
where you need to define the values of V, R and L.

Evaluating a function with a well-defined value at x,y=0

I am trying to write a program that uses an array in further calculations. I initialize a grid of equally spaced points with NumPy and assign a value at each point as per the code snippet provided below. The function I am trying to describe with this array gives me a division by 0 error at x=y and it generally blows up around it. I know that the real part of said function is bounded by band_D/(2*math.pi)
at x=y and I tried manually assigning this value on the diagonal, but it seems that points around it are still ill-behaved and so I am not getting any right values. Is there a way to remedy this? This is how the function looks like with matplotlib
gamma=5
band_D=100
Dt=1e-3
x = np.arange(0,1/gamma,Dt)
y = np.arange(0,1/gamma,Dt)
xx,yy= np.meshgrid(x,y)
N=x.shape[0]
di = np.diag_indices(N)
time_fourier=(1j/2*math.pi)*(1-np.exp(1j*band_D*(xx-yy)))/(xx-yy)
time_fourier[di]=band_D/(2*math.pi)
You have a classic 0 / 0 problem. It's not really Numpy's job to figure out to apply De L'Hospital and solve this for you... I see, as other have commented, that you had the right idea with trying to set the limit value at the diagonal (where x approx y), but by the time you'd hit that line, the warning had already been emitted (just a warning, BTW, not an exception).
For a quick fix (but a bit of a fudge), in this case, you can try to add a small value to the difference:
xy = xx - yy + 1e-100
num = (1j / 2*np.pi) * (1 - np.exp(1j * band_D * xy))
time_fourier = num / xy
This also reveals that there is something wrong with your limit calculation... (time_fourier[0,0] approx 157.0796..., not 15.91549...).
and not band_D / (2*math.pi).
For a correct calculation:
def f(xy):
mask = xy != 0
limit = band_D * np.pi/2
return np.where(mask, np.divide((1j/2 * np.pi) * (1 - np.exp(1j * band_D * xy)), xy, where=mask), limit)
time_fourier = f(xx - yy)
You are dividing by x-y, that will definitely throw an error when x = y. The function being well behaved here means that the Taylor series doesn't diverge. But python doesn't know or care about that, it just calculates one step at a time until it reaches division by 0.
You had the right idea by defining a different function when x = y (ie, the mathematically true answer) but your way of applying it doesn't work because the correction is AFTER the division by 0, so it never gets read. This, however, should work
def make_time_fourier(x, y):
if np.isclose(x, y):
return band_D/(2*math.pi)
else:
return (1j/2*math.pi)*(1-np.exp(1j*band_D*(x-y)))/(x-y)
time_fourier = np.vectorize(make_time_fourier)(xx, yy)
print(time_fourier)
You can use np.divide with where option.
import math
gamma=5
band_D=100
Dt=1e-3
x = np.arange(0,1/gamma,Dt)
y = np.arange(0,1/gamma,Dt)
xx,yy = np.meshgrid(x,y)
N = x.shape[0]
di = np.diag_indices(N)
time_fourier = (1j / 2 * np.pi) * (1 - np.exp(1j * band_D * (xx - yy)))
time_fourier = np.divide(time_fourier,
(xx - yy),
where=(xx - yy) != 0)
time_fourier[di] = band_D / (2 * np.pi)
You can reformulate your function so that the division is inside the (numpy) sinc function, which handles it correctly.
To save typing I'll use D for band_D and use a variable
z = D*(xx-yy)/2
Then
T = (1j/2*pi)*(1-np.exp(1j*band_D*(xx-yy)))/(xx-yy)
= (2/D)*(1j/2*pi)*( 1 - cos( 2*z) - 1j*sin( 2*z))/z
= (1j/D*pi)* (2*sin(z)*sin(z) - 2j*sin(z)*cos(z))/z
= (2j/D*pi) * sin(z)/z * (sin(z) - 1j*cos(z))
= (2j/D*pi) * sinc( z/pi) * (sin(z) - 1j*cos(z))
numpy defines
sinc(x) to be sin(pi*x)/(pi*x)
I can't run python do you should chrck my calculations
The steps are
Substitute the definition of z and expand the complex exp
Apply the double angle formulae for sin and cos
Factor out sin(z)
Substitute the definition of sinc

Drawing a circle with Pyautogui from top to bottom

I would like to create a half circle from top to bottom with my mouse, using Pyautogui. Currently I am using a script that works from right to left or left to right. But I can't manage to make the script to work from top to bottom. Here is the current script,
import pyautogui
import math
R = 40
(x,y) = pyautogui.size()
(X,Y) = pyautogui.position(580,311)
pyautogui.moveTo(X+R,Y)
pyautogui.mouseDown();
for i in range(180):
if i%6==0:
pyautogui.moveTo(X+R*math.cos(math.radians(i)),Y+R*math.sin(math.radians(i)))
pyautogui.mouseUp()
So right now it goes to the location, adds the radius then starts drawing the circle. I would like it to add the radius on top and start drawing down. I know how to add the radius on top, but drawing downwards is the struggle. So if anyone can help that would be great!
Thanks,
GetRektOrElse
Hello there GetRektOrElse,
I would like to start this answer by apologising for my horrible code styling, I am primarily a mathematician and I am not very familiar with styling.
I have taken a different approach to solving this problem to yourself by using the equation of a circle in cartesian coordinates: (x ** 2 - a) + (y ** 2 - b) = r ** 2 where point (a, b) is the centre of the circle and r is the radius of the circle. By rearranging this equation you can find a formula for x in terms of y: sqrt((r ** 2) - ((y - b) ** 2)) + a. By iterating through integer values of y this equation can be used to find the relevant value for x on each pixel row from which you are able to draw you circle.
I believe that this approach is slightly more intuitive than the one which you have used and is more versatile for other transformations which one might want to do in the future.
import pyautogui
import math
r = 36
centrex = 2778
centrey = 505
y = centrey - r
x = math.sqrt((r ** 2) - ((y - centrey) ** 2)) + centrex
oldx = x
oldy = y
for i in range(r):
pyautogui.moveTo(x, y)
x = math.sqrt((r ** 2) - ((y - centrey) ** 2)) + centrex
pyautogui.dragTo(x, y)
tempx = centrex - math.sqrt((r ** 2) - ((y - centrey) ** 2))
tempoldx = centrex - math.sqrt((r ** 2) - ((oldy - centrey) ** 2))
pyautogui.moveTo(tempoldx, oldy)
pyautogui.dragTo(tempx, y)
pyautogui.dragTo(x, y) # comment this line if you want to disable fill
oldx = x
oldy = y
y = y + 1
Again I would like to apologise for how disgusting I'm sure this code is however it performs the function that you desire in the way I described above. If you have any questions please feel free to ask and thank you for asking such an interesting question!
Hope you are staying well,
bobbattalion
Change;
pyautogui.moveTo(X+R,Y)
To;
pyautogui.moveTo(X,Y+R)
Also if you want it to start top to bottom, use a negative figure for your radius.

Python - Vincenty's inverse formula not converging (Finding distance between points on Earth)

I'm attempting to implement Vincenty's inverse problem as described on wiki HERE
The problem is that lambda is simply not converging. The value stays the same if I try to iterate over the sequence of formulas, and I'm really not sure why. Perhaps I've just stared myself blind on an obvious problem.
It should be noted that I'm new to Python and still learning the language, so I'm not sure if it's misuse of the language that might cause the problem, or if I do have some mistakes in some of the calculations that I perform. I just can't seem to find any mistakes in the formulas.
Basically, I've written in the code in as close of a format as I could to the wiki article, and the result is this:
import math
# Length of radius at equator of the ellipsoid
a = 6378137.0
# Flattening of the ellipsoid
f = 1/298.257223563
# Length of radius at the poles of the ellipsoid
b = (1 - f) * a
# Latitude points
la1, la2 = 10, 60
# Longitude points
lo1, lo2 = 5, 150
# For the inverse problem, we calculate U1, U2 and L.
# We set the initial value of lamb = L
u1 = math.atan( (1 - f) * math.tan(la1) )
u2 = math.atan( (1 - f) * math.tan(la2) )
L = (lo2 - lo1) * 0.0174532925
lamb = L
while True:
sinArc = math.sqrt( math.pow(math.cos(u2) * math.sin(lamb),2) + math.pow(math.cos(u1) * math.sin(u2) - math.sin(u1) * math.cos(u2) * math.cos(lamb),2) )
cosArc = math.sin(u1) * math.sin(u2) + math.cos(u1) * math.cos(u2) * math.cos(lamb)
arc = math.atan2(sinArc, cosArc)
sinAzimuth = ( math.cos(u1) * math.cos(u2) * math.sin(lamb) ) // ( sinArc )
cosAzimuthSqr = 1 - math.pow(sinAzimuth, 2)
cosProduct = cosArc - ((2 * math.sin(u1) * math.sin(u2) ) // (cosAzimuthSqr))
C = (f//16) * cosAzimuthSqr * (4 + f * (4 - 3 * cosAzimuthSqr))
lamb = L + (1 - C) * f * sinAzimuth * ( arc + C * sinArc * ( cosProduct + C * cosArc * (-1 + 2 * math.pow(cosProduct, 2))))
print(lamb)
As mentioned the problem is that the value "lamb" (lambda) will not become smaller. I've even tried to compare my code to other implementations, but they looked just about the same.
What am I doing wrong here? :-)
Thank you all!
First, you should convert you latitudes in radians too (you already do this for your longitudes):
u1 = math.atan( (1 - f) * math.tan(math.radians(la1)) )
u2 = math.atan( (1 - f) * math.tan(math.radians(la2)) )
L = math.radians((lo2 - lo1)) # better than * 0.0174532925
Once you do this and get rid of // (int divisions) and replace them by / (float divisions), lambda stops repeating the same value through your iterations and starts following this path (based on your example coordinates):
2.5325205864224847
2.5325167509030906
2.532516759118641
2.532516759101044
2.5325167591010813
2.5325167591010813
2.5325167591010813
As you seem to expect a convergence precision of 10^(−12), it seems to make the point.
You can now exit the loop (lambda having converged) and keep going until you compute the desired geodesic distance s.
Note: you can test your final value s here.
Even if it is correctly implemented, Vincenty's algorithm will fail to
converge for some points. (This problem was noted by Vincenty.)
I give an algorithm which is guaranteed to
converge in Algorithms for geodesics; there's a python
implementation available here. Finally, you can find more
information on the problem at the Wikipedia page,
Geodesics on an ellipsoid. (The talk page has examples
of pairs of points for which Vincenty, as implemented by the NGS,
fails to converge.)

Categories

Resources