Geopandas: How to relate the length of a linestring to the linestring point used to find distance to polygon - geopandas

I’m trying to find the length of the linestring between the starting point of the linestring and the point which are used to find the nearest distance to a polygon.
So I used the following code to get the minimum distance between the linestring and some polygons.
gdf['MinDistToTrack'] = gdf.geometry.apply(lambda l: min(rail_or.distance(l)))
and I would also like to get the distance from the start of the linestring to the point used by the above code.
Now I get dataframe containing the polygons with a value 'MinDistToTrack' (which I have now) but also with a value ‘Length_Of_Linestring_Up_To_Location_Of_Polygon’.
So, let’s say that from the start of the linestring to the polygon there are 22 meters following the path of the linestring, then this is the value I would like to save together with the 'MinDistToTrack'
Polygon ID : 1
'MinDistToTrack' : 1m
'LengthOfLinestringUpToLocationOfPolygon' : 22m
Is this possible or do I need to split the linestring up into small elements and then look at all elements and the length of all the preceding elements in relation to the linestring elements which is nearest to the polygon?
Picture showing the problem

You may use the following concepts from shapely:
The nearest_points() function in shapely.ops calculates the nearest points in a pair of geometries.
shapely.ops.nearest_points(geom1, geom2)
Returns a tuple of the nearest points in the input geometries. The points are returned in the same order as the input geometries.
https://shapely.readthedocs.io/en/stable/manual.html#shapely.ops.nearest_points
from shapely.ops import nearest_points
P = Polygon([(0, 0), (1, 0), (0.5, 1), (0, 0)])
Lin = Linestring([(0, 2), (1, 2), (1, 3), (0, 3)])
nps = [o.wkt for o in nearest_points(P, Lin)]
##nps = ['POINT (0.5 1)', 'POINT (0.5 2)']
np_lin = = nps[1]
You can then use the point np_lin and Project it on the Lin to get the distance using
d = Lin.project(np_lin)
d will be the distance along Lin to the point np_lin i.e. nearest to the corresponding Point of P.

Related

shapely nearest_points between two polygons returns expected result for simple polygons, unexpected result for complex polygons

I am using nearest_points from shapely to retrieve the nearest points between two polygons.
I get the expected result for two simple polygons:
However for more complex polygons, the points are not the expected nearest points between the polygons.
Note: I added ax.set_aspect('equal') so that the nearest points line woild have to be at a right angle (right?)
What is wrong with my code or my polygons (or me)?
from shapely.geometry import Point, Polygon, LineString, MultiPolygon
from shapely.ops import nearest_points
import matplotlib.pyplot as plt
import shapely.wkt as wkt
#Set of 2 Polyogons A where the nearest points don's seem right
poly1=wkt.loads('POLYGON((-0.136319755454978 51.460464712623626, -0.1363352511419218 51.46042713866513, -0.1363348393705439 51.460425, -0.1365967582352347 51.460425, -0.1363077932125138 51.4605825392028, -0.136237298707157 51.46052697162038, -0.136319755454978 51.460464712623626))')
poly2=wkt.loads('POLYGON ((-0.1371553266140889 51.46046700960882, -0.1371516327997412 51.46046599134276, -0.1371478585043985 51.46046533117243, -0.1371440383598866 51.46046503515535, -0.1371402074187299 51.460465106007696, -0.1371364008325196 51.460465543079344, -0.137132653529373 51.46046634235985, -0.1371289998934435 51.46046749651525, -0.1371254734494216 51.46046899495536, -0.1371221065549237 51.46047082393093, -0.1366012836405492 51.460786954965236, -0.1365402944168757 51.46074798846902, -0.1370125055334012 51.46045400071198, -0.1371553266140889 51.46046700960882))')
#Set of 2 polygons B where the nearest points seem right
#poly1 = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
#poly2 = Polygon([(10, 0),(13,5),(14,2)])
p1, p2 = nearest_points(poly1, poly2)
fig,ax= plt.subplots()
ax.set_aspect('equal')
x1,y1=poly1.exterior.xy
x2,y2=poly2.exterior.xy
#Plot Polgygons
plt.plot(x1,y1)
plt.plot(x2,y2)
#Plot LineString connecting the nearest points
plt.plot([p1.x, p2.x],[p1.y,p2.y], color='green')
fig.show()

Obtaining a triangle pair that have a shared edge from triangle set obtained from Delaunay Triangulation

I want to obtain triangles which are from triangle set obtained from Delaunay Triangulation. I wrote the following code. How can I obtain triangles which have a shred edge with each other (please see the image)? According to this image, I want to obtain triangle1 and 2 from triangle set obtained from Delaunay Triangulation.
rng default;
P = rand([32 2]);
DT = delaunayTriangulation(P);
triplot(DT)
Short answer: neighbors(DT).
Example:
rng default
P = rand([12 2]);
DT = delaunayTriangulation(P);
IC = incenter(DT);
% visualize incl. ID in the center
figure
triplot(DT)
hold on
text(IC(:,1), IC(:,2), num2str([1:size(IC,1)]'))
% find all neighboring triangles
neighbors(DT)
% for the first triangle
neighbors(DT, 1)

How to offset polygon edges?

I have a list of point2D that makes a closed polygon. Now I want to create another set of 2D points by offsetting the polygon given an option inside or outside and an offset value. How can I do it?
For every polygon vertex calculate outer bisector vector as sum of normalized normals na and nb of two neighbor edges), then normalize it
bis = na + nb
bis = bis / Length(bis)
Then find needed length of bisector to provide offset distance as
l = d / Sqrt((1 + dotproduct(na,nb))/2)
(derived from l=d/cos(fi/2) and half-angle cosine formula)
And get offset polygon vertex (use minus for inner offset!):
P' = P + l * bis
Added: python implementation here
You need to work with dircetion to be able to define what is outside/inside. Better is to work with to the left/right of the arrow (vector).
In my example the offset is to the right of the vector, now you need to calculate all intersections of the red lines to define the new start-end points of the lines.
Example: P0 = (5,2) & P1 = (2, 1.7)
V1 = -3, -0.3. Rotating clock wise 90deg gives us vector -0.3, 3 (a,b) -> (b, -a)
Divide the vector by 3 (thats about the distance in the drawing) gives us (-0.1, 1)
ofsetting point P0 by the vector gives P0' (5,2) - v(-0.1,1) = (4.9, 3)

How to find the "interior boundary" / "interior convex hull" for a list of 3D points?

I need some help with writing this algorithm.
For a given set of lines in space, I am trying to find the accessible volume when the origin (reference point) is 0.5,0.5,0.5. Currently, I do the following:
For each line, calculate the distance to the origin (0.5,0.5,0.5). Then, gather all these perpendicular distance points on all the lines into a list.
Now, I would like to calculate the "interior" (neither the boundary nor the convhull), because I want to evaluate the accessible volume for a ball centered at (0.5,0.5,0.5).
For example I would like to compute with my algorithm the green (internal line) in this simple example:
The configuration:
The closest points from the origin (0.5,0.5,0.5) to the lines
Only the points for whom I want the "internal boundary" be computed. Meaning the shape that bounds all the point either outside of the interior or on its boundary.
Here is the code for which I want something else rather than convhull:
close all
N=30;
S1 = cell(1, N);
for k = 1:N, S1{k} = rand(1, 3); end
S2 = cell(1, N);
for k = 1:N, S2{k} = rand(1, 3); end
M1 = cat(3, S1{:});
M2 = cat(3, S2{:});
M = permute(cat(1, M1, M2), [1, 3, 2]);
figure
plot3(M(:, :, 1), M(:, :, 2), M(:, :, 3))
hold on
[x,y,z] = sphere;
x=x/100;y=y/100;z=z/100;
plot3(x+0.5,y+0.5,z+0.5)
figure
hold on
NearestIntersectionPoints = cell(1,N);
for k = 1:N
tmp1 = M(1,k,:); tmp2 = M(2,k,:);
v1=tmp1(1,:); v2=tmp2(1,:);
[d, intersection] = point_to_line([0.5,0.5,0.5], v1, v2);
[x,y,z] = sphere;
x=x/500;y=y/500;z=z/500;
plot3(x+intersection(1),y+intersection(2),z+intersection(3))
NearestIntersectionPoints{k} = intersection;
end
MHull = cat(3,NearestIntersectionPoints{:});
X=MHull(:,1,:); Y=MHull(:,2,:); Z=MHull(:,3,:);
X=X(:); Y=Y(:); Z=Z(:);
k = boundary(X,Y,Z);
hold on
plot3(X(k),Y(k),Z(k), 'r-*')
function [d,intersection] = point_to_line(pt, v1, v2)
a = v1 - v2;
b = pt - v2;
d = norm(cross(a,b)) / norm(a);
theta = asin(norm(cross(a,b))/(norm(a)*norm(b)));
intersection = v2 + a * cos(theta);
end
I would do it like this:
tetrahedronize your pointcloud
so create a mesh consisting of tetrahedrons where no tetrahedron intersect any other or contain any point in it. I do it like this:
structures
you need list of points,triangles and tetrahedrons. Each triangle need one counter which will tell you if it is used once or twice.
create first tetrahedron
by 4 nested loops through all points and check if formed tetrahedron does not contain any point inside. If not stop as you found your first tetrahedron. This is O(n^5) but as there are a lot of valid tetrahedrons it will never reach such high runtime... Now just add this tetrahedron to triangle and tetrahedron lists.
find next tetrahedron
now loop through all triangles that has been used once. for each form tetrahedron by using those 3 points used by it and find 4th point the same way as in #2. Valid tetrahedron must not contain any points in it and also must not intersect any existing tetrahedron in the list.
To ensure whole volume will be filled without holes you need to prioritize the process by preferring tetrahedrons with more triangles already in list. So first search 4 triangles if no found than 3 etc ...
For each found valid tetrahedron add it to the lists and look again until no valid tetrahedron can be formed ... The whole process is around O(n^2) so be careful with too many points in pointcloud. Also having normals for triangles stored can speed the tests a lot ...
outer boundary
outer boundary consist of triangles in list which have been used just once
interior boundary
interior gap tetrahedrons should be larger than all the others. So check their size against average size and if bigger they are most likely a gap. So group them together to lists. Each gap have only large tetrahedrons and all of them must share at least one face (triangle). Now just count the triangle usage for each group alone and all the triangles used just once will form your gap/hole/interior boundary/mesh.
If your point density is uniform you can adapt this:
Finding holes in 2d point sets?
And create a voxel map of point density... voxels with no density are either gap or outer space. This can be used for faster and better selection of interior tetrahedrons.
If I understand well your question, you want the largest volume inside another volume, without points in common between the two volumes.
The outer volume is built from a subset of the set of points. The obvious solution is to build the inner volume with the rest of points.
A volume from a set of points can be made in several ways. If the volume is not convex, then you need some more info (e.g. minimum angle between faces) because you get starred polytopo or cuasi-convex, or some other shape.
For convex volume I recomend the 3D Delaunay construction, with tetrahedra. The boundary is defined by the faces of "tets" that are not shared with other "tets".
Remove from the full set of points those belonging to the boundary: Each tet in boundary has a fourth point that does not lie on the boundary.
The inner volume is another Delaunay construction. Perhaps you only need the fourth points from the previous boundary-tets.

Points enclosed by a custom defined Hypercube

I have a N-dimensional vector, X and 'n' equidistant points along each dimension and a parameter 'delta'. I need a way to find the total of n^N vectors enclosed by the Hypercube defined with the vector X at the center and each side of Hypercube being of size 2*delta.
For example:
Consider a case of N=3, so we have a Cube of size (2*delta) enclosing the point X.
------------\
|\--------|--\
| | X | |
----------- |
\ |_2*del___\|
Along each dimension I have 'n' points. So, I have a total of n^3 vectors around X. I need to find all the vectors. Is there any standard algorithm/method for the same? If you have done anything similar, please suggest.
If the problem is not clear, let me know.
This is what I was looking at: Considering one dimension, length of a side is 2*delta and I have n divisions. So, each sub-division is of size (2*delta/n). So I just move to the origin that is (x-delta) (since x is the mid point of the side) and obtain the 'n' points by {(x-delta) + 1*(2*delta/n),(x-delta) + 2*(2*delta/n)....+ (x-delta) + 1*(n*delta/n) } . I do this for all the N-dimensions and then take a permutation of the co-ordinates. That way I have all the points.
(I would like to close this)
If i understand your problem correctly, you have an axis-aligned hypercube centred around a point X, and you have subdivided the interior of this hypercube into a regular lattice where the lattice points and spacing are in the coordinate system of the hypercube. All you have to do is let X = 0, find the vectors to each of the lattice points, and then go back and translate them by X.
Edit: let me add an example
let x = (5,5,5), delta = 1 and n = 3
then, moving x to the origin, your lattice points are (-1, -1, -1), (0, -1, -1), (1, -1, -1) and so on for a total of 27. translating back, we have (4, 4, 4), (5, 4, 4), (6, 4, 4) and so on.
Ok, I didn't fully understand your question. There are total of 2^(N-1)*N "lines" about a point in an N-dimensional hypercube.
If you just want to create n points on lines which look like the axis, but translated at a distance of delta from the origin, here's some (poorly written, for clarity) MATLAB code:
n = 10;
delta = 10;
N = 3;
step = (2*delta)/(n-1);
P = zeros(n,N,N);
X = [20 30 25];
for line_dim = 1:N
for point = 1:n
for point_dim = 1:N
if(point_dim ~= line_dim)
P(point,point_dim,line_dim) = X(point_dim)-delta;
else
P(point,point_dim,line_dim) = X(point_dim)-delta+step*(point-1);
end
end
end
end
The code's for a cube, but it should work for any N. All I've done is:
Draw those n equidistant points on the axes.
Translate the axes by (X-delta)
Display:
% Display stuff
PP = reshape(permute(P,[1 3 2]),[n*N N]);
plot3(X(1),X(2),X(3),'r*',PP(:,1),PP(:,2),PP(:,3),'.')
axis([0 Inf 0 Inf 0 Inf]);
grid on;

Resources