How to get equidistant points from a linestring (geographical coordinates) - bash

I want to resample geographical coordinates based on a specific number of values, let's say, 1663 for the following case:
-78.0599088 -11.89402416
-78.04317744 -11.88622134
-78.0267798 -11.87700462
-78.010353 -11.8692050399999
-77.9953194 -11.86129017
-77.96128788 -11.8449840599999
-77.92870572 -11.82838707
-77.89554864 -11.8117820699999
-77.86357524 -11.79488952
-77.83013412 -11.77942518
-77.7978615599999 -11.76223743
-77.765589 -11.7456140699999
-77.73216732 -11.72927727
-77.6996085599999 -11.7117892799999
-77.6673594 -11.6965884599999
-77.63510052 -11.6819618399999
-77.6045808 -11.6618759099999
-77.57262108 -11.6432262
-77.5406624399999 -11.62628883
-77.5072638 -11.6099197199999
-77.4753066 -11.5923951899999
-77.4427813199999 -11.57658786
-77.4093902399999 -11.5599159
-77.38064244 -11.5446833099999
However, the tricky part here is to keep the first and last positions and to use open-source software tools (such as GDAL, AWK, GMT or other bash shell command line tools, that would be great).
As example I am looking for something similar to the "Equidistant points (fixed number)" option of XTools Pro: https://help.xtools.pro/pro/12.2/en/XTools_Pro_Components/Feature_conversions/Convert_Features_to_Points.htm
Here an expected output, a line of distance X from which 7 points (node or vertex) were created considering the first and last positions:
Any support is appreciated.

The following answer assumes that your coordinates are on a sphere and not on an ellipsoid.
Your input contains a set of points on the great-circle between two points p and q with coordinates in longitude and latitude to be:
p = {φp,λp} = {-78.0599088, -11.89402416}
q = {φq,λq} = {-77.38064244, -11.5446833099999}
Call np the unit vector of p and nq the unit vector of q, then its coordinates are:
np = {cos(φp) cos(λp),cos(φp) sin(λp),sin(φp)}
nq = {cos(φq) cos(λq),cos(φq) sin(λq),sin(φq)}
Call α then angle between np and nq
α = arccos(np·nq)
If you now want to have n points equidistantly spaced between p and q, you have to separate them over an angle Δα = α/(n-1).
The coordinates over these points are then:
ni = np cos(i Δα) + nr sin(i Δα)
nr = Normalized[nq - (nq·np) np] = (nq - cos(α) np) / sin(α)
for i ∈ [0,n-1]. The above is understood as a simple rotation over iΔα of np in the np-nr plane (np·nr = 0)
These coordinates can then be transformed back to longitude and latitude, giving you all the intermediate points.
remark: This is for equidistant points on a sphere and not an ellipsoid such as WGS 84
remark: The above will fail for antipodal points.
A very good formulary is Ed William's Aviation Formulary

Python did the trick:
from shapely.geometry import LineString
import csv
with open('input_xy.txt') as fin:
reader = csv.reader(fin)
xy_floats = map(lambda x: (float(x[0]), float(x[1])), list(reader))
line = LineString(xy_floats)
num_points = 9 # includes first and last
new_points = [line.interpolate(i/float(num_points - 1), normalized=True) for i in range(num_points)]
with open('output_xy.txt', 'w') as fout:
writer = csv.writer(fout)
writer.writerows([ [point.x, point.y] for point in new_points])
Hope this helps someone else.

Related

Find tangent points in a circle from a point

Circle center : Cx,Cy
Circle radius : a
Point from which we need to draw a tangent line : Px,Py
I need the formula to find the two tangents (t1x, t1y) and (t2x,t2y) given all the above.
Edit: Is there any simpler solution using vector algebra or something, rather than finding the equation of two lines and then solving equation of two straight lines to find the two tangents separately? Also this question is not off-topic because I need to write a code to find this optimally
Here is one way using trigonometry. If you understand trig, this method is easy to understand, though it may not give the exact correct answer when one is possible, due to the lack of exactness in trig functions.
The points C = (Cx, Cy) and P = (Px, Py) are given, as well as the radius a. The radius is shown twice in my diagram, as a1 and a2. You can easily calculate the distance b between points P and C, and you can see that segment b forms the hypotenuse of two right triangles with side a. The angle theta (also shown twice in my diagram) is between the hypotenuse and adjacent side a so it can be calculated with an arccosine. The direction angle of the vector from point C to point P is also easily found by an arctangent. The direction angles of the tangency points are the sum and difference of the original direction angle and the calculated triangle angle. Finally, we can use those direction angles and the distance a to find the coordinates of those tangency points.
Here is code in Python 3.
# Example values
(Px, Py) = (5, 2)
(Cx, Cy) = (1, 1)
a = 2
from math import sqrt, acos, atan2, sin, cos
b = sqrt((Px - Cx)**2 + (Py - Cy)**2) # hypot() also works here
th = acos(a / b) # angle theta
d = atan2(Py - Cy, Px - Cx) # direction angle of point P from C
d1 = d + th # direction angle of point T1 from C
d2 = d - th # direction angle of point T2 from C
T1x = Cx + a * cos(d1)
T1y = Cy + a * sin(d1)
T2x = Cx + a * cos(d2)
T2y = Cy + a * sin(d2)
There are obvious ways to combine those calculations and make them a little more optimized, but I'll leave that to you. It is also possible to use the angle addition and subtraction formulas of trigonometry with a few other identities to completely remove the trig functions from the calculations. However, the result is more complicated and difficult to understand. Without testing I do not know which approach is more "optimized" but that depends on your purposes anyway. Let me know if you need this other approach, but the other answers here give you other approaches anyway.
Note that if a > b then acos(a / b) will throw an exception, but this means that point P is inside the circle and there is no tangency point. If a == b then point P is on the circle and there is only one tangency point, namely point P itself. My code is for the case a < b. I'll leave it to you to code the other cases and to decide the needed precision to decide if a and b are equal.
Here's another way using complex numbers.
If a is the direction (a complex number of length 1) of the tangent point on the circle from the centre c, and d is the (real) length along the tangent to get to p, then (because the direction of the tangent is I*a)
p = c + r*a + d*I*a
rearranging
(r+I*d)*a = p-c
But a has length 1 so taking the length we get
|r+I*d| = |p-c|
We know everything but d, so we can solve for d:
d = +- sqrt( |p-c|*|p-c| - r*r)
and then find the a's and the points on the circle, one of each for each value of d above:
a = (p-c)/(r+I*d)
q = c + r*a
Hmm not really an algorithm question (people tend to mistake algorithm and equation) If you want to write a code then do (you did not specify language nor what prevents you from doing this which is the reason of close votes)... Without this info your OP is just asking for math equation which is indeed off-topic here and by answering this I risk (right-full) down-votes too (but this is/was asked a lot here with much less info and 4 reopen votes against 1 close put my decision weight on reopen and answering this anyway).
You can exploit the fact that you are in 2D as in 2D perpendicular vectors to vector a(x,y) are computed like this:
c = (-y, x)
d = ( y,-x)
c = -d
so you swap x,y and negate one (which one determines if the perpendicular vector is CW or CCW). It is really a rotation formula but as we rotate by 90deg the cos,sin are just +1 and -1.
Now normal n to any circumference point on circle lies in the line going through that point and circles center. So putting all this together your tangents are:
// normal
nx = Px-Cx
ny = Py-Cy
// tangent 1
tx = -ny
ty = +nx
// tangent 2
tx = +ny
ty = -nx
If you want unit vectors than just divide by radius a (not sure why you do not call it r like the rest of the math world) so:
// normal
nx = (Px-Cx)/a
ny = (Py-Cy)/a
// tangent 1
tx = -ny
ty = +nx
// tangent 2
tx = +ny
ty = -nx
Let's go through derivation process:
As you can see, if the interior of the square is < 0 it's because the point is interior to the circumferemce. When the point is outside of the circumference there are two solutions, depending on the sign of the square.
The rest is easy. Take atan(solution) and be carefull here with the signs, you may better do some checks.
Use (2) and then undo (1) transformations and that's all.
c# implementation of dmuir's answer:
static void FindTangents(Vector2 point, Vector2 circle, float r, out Line l1, out Line l2)
{
var p = new Complex(point.x, point.y);
var c = new Complex(circle.x, circle.y);
var cp = p - c;
var d = Math.Sqrt(cp.Real * cp.Real + cp.Imaginary * cp.Imaginary - r * r);
var q = GetQ(r, cp, d, c);
var q2 = GetQ(r, cp, -d, c);
l1 = new Line(point, new Vector2((float) q.Real, (float) q.Imaginary));
l2 = new Line(point, new Vector2((float) q2.Real, (float) q2.Imaginary));
}
static Complex GetQ(float r, Complex cp, double d, Complex c)
{
return c + r * (cp / (r + Complex.ImaginaryOne * d));
}
Move the circle to the origin, rotate to bring the point on X and downscale by R to obtain a unit circle.
Now tangency is achieved when the origin (0, 0), the (reduced) given point (d, 0) and an arbitrary point on the unit circle (cos t, sin t) form a right triangle.
cos t (cos t - d) + sin t sin t = 1 - d cos t = 0
From this, you draw
cos t = 1 / d
and
sin t = ±√(1-1/d²).
To get the tangency points in the initial geometry, upscale, unrotate and untranslate. (These are simple linear algebra operations.) Notice that there is no need to perform the direct transform explicitly. All you need is d, ratio of the distance center-point over the radius.

How to judge the contour is line or curve by opencv?

This image have two contours. I can find both with opencv findcontour function. What I want to know is how to judge which contour is line and which contour is curve ? Can anybody please tell how to do it?
Start by assuming you have a line, and apply some basic algebra.
First find the slope of the line and the y-intercept. The slope of a line is defined as the change in y divided by the change in x. So given two points (x0,y0), (x1,y1):
slope = (y0-y1) / (x0-x1)
The y-intercept is found using the slope-intercept equation (y=mx+b) and solving for b:
y = mx + b
b = y - mx
So
y_intercept = y0 - slope * x0
Once you have the slope and the y-intercept, you just need to loop through the points of your contour and see if all of the points fall on the same line. If they do, you have a line; if they don't, you have a curve.
Since I don't know what language you're working with, here is the whole process in pseudocode:
// First assume you have a line - find the slope and y-intercept
slope = (point[0].y - point[1].y) / (point[0].x - point[1].x);
y_intercept = point[0].y - (slope * point[0].x);
// Using slope-intercept (y = mx + b), see if the other points are on the same line
for (n = 0 to numPoints)
{
if ((slope * point[n].x + y_intercept) != point[n].y)
{
// You've found a point that's not on the line - as soon as you
// find a point that's not on the line, you know that the contour
// is not a straight line
}
}
Note that you'll be dealing with floating-point numbers here, so you'll have to take that into account in the if condition - you can't directly compare floating point numbers for equality, so you'll need to round them to some acceptable degree of accuracy. I left that out to keep the pseudocode simple.
Late answer but for the record:
Compare distance between first and last points against contour length.
If they are close then contour is line-like, otherwise it's a curve.

Given 2 of 3 vertices that define a tetrahedron and all 3 angles between them, find 3rd vertex

Suppose one of a tetrahedron's four vertices is at the origin and the other three are at the end of vectors u, v, and w. If vectors u and v are known, and the angles between u and v, v and w, and w and u are also known, it seems there is a closed form solution for w: the intersection of the two cones formed by rotating a vector at the u and w angle about the u axis, and by rotating a vector at the v and w angle about the v axis.
Although I haven't been able to come up with a closed form solution in a couple days, I'm hoping it is due to my lack of experience with 3d geometry and that someone with more experience might have a helpful suggestion.
I had the same problem, and found MBo's answer very useful. But I think we can say a bit more about the value of w, because we're free to pick the coordinate system to work in. In particular, if we choose the x-axis to be in the direction of u, and the xy-plane to contain the vector v, then MBo's system of equations becomes:
wx = cos(uw)
vx*wx + vy*wy = cos(vw)
||w|| = 1
and this coordinate system gives
vx = cos(uv), vy = sin(uv)
so immediately we get that
_____________________
( cos(vw) - cos(uv) * cos(uw) + / 2 )
w = ( cos(uw), ----------------------------- , - / 1 - cos (uw) - wy*wy )
( sin(uv) \/ )
The +- on the square root gives the two possible solutions, unless of course 1 - cos^2(uw) - wy^2 <= 0. The division by sin(uv) also highlights a degenerate case when u and v are linearly dependent (point in the same direction).
Another check we can make is that if the vectors u and v are orthogonal, it's known that wy = cos(vw) (see https://math.stackexchange.com/questions/726782/find-a-3d-vector-given-the-angles-of-the-axes-and-a-magnitude). This is what falls out of the expression above (because cos(uv) = 0 and sin(uv) = 1).
There are not enough data to calculate vertice w position. But it is possible to find unit vector w (if it exists). Just use scalar product properties and solve equation system
(I've used (vx,vy,vz) as components of unit (normalized) vector v)
vx*wx+vy*wy+vz*wz=Cos(v,w angle)
ux*wx+uy*wy+uz*wz=Cos(u,w angle)
wx^2+wy^2+wz^2=1 //unit vector
This system can give us: no solutions (cones don't overlap); one solution (cones touching); two solutions (two rays as cones' surfaces intersection)

Algorithm: Calculate pseudo-random point inside an ellipse

For a simple particle system I'm making, I need to, given an ellipse with width and height, calculate a random point X, Y which lies in that ellipse.
Now I'm not the best at maths, so I wanted to ask here if anybody could point me in the right direction.
Maybe the right way is to choose a random float in the range of the width, take it for X and from it calculate the Y value?
Generate a random point inside a circle of radius 1. This can be done by taking a random angle phi in the interval [0, 2*pi) and a random value rho in the interval [0, 1) and compute
x = sqrt(rho) * cos(phi)
y = sqrt(rho) * sin(phi)
The square root in the formula ensures a uniform distribution inside the circle.
Scale x and y to the dimensions of the ellipse
x = x * width/2.0
y = y * height/2.0
Use rejection sampling: choose a random point in the rectangle around the ellipse. Test whether the point is inside the ellipse by checking the sign of (x-x0)^2/a^2+(y-y0)^2/b^2-1. Repeat if the point is not inside. (This assumes that the ellipse is aligned with the coordinate axes. A similar solution works in the general case but is more complicated, of course.)
It is possible to generate points within an ellipse without using rejection sampling too by carefully considering its definition in polar form. From wikipedia the polar form of an ellipse is given by
Intuitively speaking, we should sample polar angle θ more often where the radius is larger. Put more mathematically, our PDF for the random variable θ should be p(θ) dθ = dA / A, where dA is the area of a single segment at angle θ with width dθ. Using the equation for polar angle area dA = 1/2 r2 dθ and the area of an ellipse being π a b, then the PDF becomes
To randomly sample from this PDF, one direct method is the inverse CDF technique. This requires calculating the cumulative density function (CDF) and then inverting this function. Using Wolfram Alpha to get the indefinite integral, then inverting it gives inverse CDF of
where u runs between 0 and 1. So to sample a random angle θ, you just generate a uniform random number u between 0 and 1, and substitute it into this equation for the inverse CDF.
To get the random radius, the same technique that works for a circle can be used (see for example Generate a random point within a circle (uniformly)).
Here is some sample Python code which implements this algorithm:
import numpy
import matplotlib.pyplot as plt
import random
# Returns theta in [-pi/2, 3pi/2]
def generate_theta(a, b):
u = random.random() / 4.0
theta = numpy.arctan(b/a * numpy.tan(2*numpy.pi*u))
v = random.random()
if v < 0.25:
return theta
elif v < 0.5:
return numpy.pi - theta
elif v < 0.75:
return numpy.pi + theta
else:
return -theta
def radius(a, b, theta):
return a * b / numpy.sqrt((b*numpy.cos(theta))**2 + (a*numpy.sin(theta))**2)
def random_point(a, b):
random_theta = generate_theta(a, b)
max_radius = radius(a, b, random_theta)
random_radius = max_radius * numpy.sqrt(random.random())
return numpy.array([
random_radius * numpy.cos(random_theta),
random_radius * numpy.sin(random_theta)
])
a = 2
b = 1
points = numpy.array([random_point(a, b) for _ in range(2000)])
plt.scatter(points[:,0], points[:,1])
plt.show()
I know this is an old question, but I think none of the existing answers are good enough.
I was looking for a solution for exactly the same problem and got directed here by Google, found all the existing answers are not what I wanted, so I implemented my own solution entirely by myself, using information found here: https://en.wikipedia.org/wiki/Ellipse
So any point on the ellipse must satisfy that equation, how to make a point inside the ellipse?
Just scale a and b with two random numbers between 0 and 1.
I will post my code here, I just want to help.
import math
import matplotlib.pyplot as plt
import random
from matplotlib.patches import Ellipse
a = 4
b = a*math.tan(math.radians((random.random()+0.5)/2*45))
def random_point(a, b):
d = math.radians(random.random()*360)
return (a * math.cos(d) * random.random(), b * math.sin(d) * random.random())
points = [random_point(a, b) for i in range(360)]
x, y = zip(*points)
fig = plt.figure(frameon=False)
ax = fig.add_subplot(111)
ax.set_axis_off()
ax.add_patch(Ellipse((0, 0), 2*a, 2*b, edgecolor='k', fc='None', lw=2))
ax.scatter(x, y)
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
plt.axis('scaled')
plt.box(False)
ax = plt.gca()
ax.set_xlim([-a, a])
ax.set_ylim([-b, b])
plt.set_cmap('rainbow')
plt.show()

Does anyone know how to do an "inverse" trilinear interpolation?

Trilinear interpolation approximates the value of a point (x, y, z) inside a cube using the values at the cube vertices. I´m trying to do an "inverse" trilinear interpolation. Knowing the values at the cube vertices and the value attached to a point how can I find (x, y, z)? Any help would be highly appreciated. Thank you!
You are solving for 3 unknowns given 1 piece of data, and as you are using a linear interpolation your answer will typically be a plane (2 free variables). Depending on the cube there may be no solutions or a 3D solution space.
I would do the following. Let v be the initial value. For each "edge" of the 12 edges (pair of adjacent vertices) of the cube look to see if 1 vertex is >=v and the other <=v - call this an edge that crosses v.
If no edges cross v, then there are no possible solutions.
Otherwise, for each edge that crosses v, if both vertices for the edge equal v, then the whole edge is a solution. Otherwise, linearly interpolate on the edge to find the point that has a value of v. So suppose the edge is (x1, y1, z1)->v1 <= v <= (x2, y2, z2)->v2.
s = (v-v1)/(v2-v1)
(x,y,z) = (s*(x2-x1)+x1, (s*(y2-y1)+y1, s*(z2-z1)+z1)
This will give you all edge points that are equal to v. This is a solution, but possibly you want an internal solution - be aware that if there is an internal solution there will always be an edge solution.
If you want an internal solution then just take any point linearly between the edge solutions - as you are linearly interpolating then the result will also be v.
I'm not sure you can for all cases. For example using tri-linear filtering for colours where each colour (C) at each point is identical means that wherever you interpolate to you will still get the colour C returned. In this situation ANY x,y,z could be valid. As such it would be impossible to say for definite what the initial interpolation values were.
I'm sure for some cases you can reverse the maths but, i imagine, there are far too many cases where this is impossible to do without knowing more of the input information.
Good luck, I hope someone will prove me wrong :)
The wikipedia page for trilinear interpolation has link to a NASA page which allegedly describes the inversing process - have you had a look at that?
The problem as you're describing it somewhat ill-defined.
What you're asking for basically translates to this: I have a 3D function and I know its values in 8 known points. I'd like to know what is the point in which the function received value V.
The trouble is that in most likelihood there is an infinite number of such points which make a set of surfaces, lines or points, depending on the data.
One way to find this set is to use an iso-surfacing algorithm like Marching cubes.
Let's start with 2d: think of a bilinear hill over a square km,
with heights say 0 10 20 30 at the 4 corners
and a horizontal plane cutting the hill at height z.
Draw a line from the 0 corner to the 30 corner (whether adjacent or diagonal).
The plane must cut this line, for any z,
so all points x,y,z fall on this one line, right ? Hmm.
OK, there are many solutions -- any z plane cuts the hill in a contour curve.
Say we want solutions to be spread out over the whole hill,
i.e. minimize two things at once:
vertical distance z - bilin(x,y),
distance from x,y to some point in the square.
Scipy.optimize.leastsq is one way of doing this, sample code below;
trilinear is similar.
(Optimizing any two things at once requires an arbitrary tradeoff or weighting:
food vs. money, work vs. play ...
Cf. Bounded rationality
)
""" find x,y so bilin(x,y) ~ z and x,y near the middle """
from __future__ import division
import numpy as np
from scipy.optimize import leastsq
zmax = 30
corners = [ 0, 10, 20, zmax ]
midweight = 10
def bilin( x, y ):
""" bilinear interpolate
in: corners at 0 0 0 1 1 0 1 1 in that order (binary)
see wikipedia Bilinear_interpolation ff.
"""
z00,z01,z10,z11 = corners # 0 .. 1
return (z00 * (1-x) * (1-y)
+ z01 * (1-x) * y
+ z10 * x * (1-y)
+ z11 * x * y)
vecs = np.array([ (x, y) for x in (.25, .5, .75) for y in (.25, .5, .75) ])
def nearvec( x, vecs ):
""" -> (min, nearest vec) """
t = (np.inf,)
for v in vecs:
n = np.linalg.norm( x - v )
if n < t[0]: t = (n, v)
return t
def lsqmin( xy ): # z, corners
x,y = xy
near = nearvec( np.array(xy), vecs )[0] * midweight
return (z - bilin( x, y ), near )
# i.e. find x,y so both bilin(x,y) ~ z and x,y near a point in vecs
#...............................................................................
if __name__ == "__main__":
import sys
ftol = .1
maxfev = 10
exec "\n".join( sys.argv[1:] ) # ftol= ...
x0 = np.array(( .5, .5 ))
sumdiff = 0
for z in range(zmax+1):
xetc = leastsq( lsqmin, x0, ftol=ftol, maxfev=maxfev, full_output=1 )
# (x, {cov_x, infodict, mesg}, ier)
x,y = xetc[0] # may be < 0 or > 1
diff = bilin( x, y ) - z
sumdiff += abs(diff)
print "%.2g %8.2g %5.2g %5.2g" % (z, diff, x, y)
print "ftol %.2g maxfev %d midweight %.2g => av diff %.2g" % (
ftol, maxfev, midweight, sumdiff/zmax)

Resources