What is the difference between ST_Intersect on spherical geometries and geographies? - geospatial

I've run into a peculiar situation where I am trying to find any geospatial objects that lie (partially) in a polygon. When I apply the ST_Intersect function on two Geometries using the WGS84 SRID the intersection of a polygon and a point clearly North of the polygon returns FALSE as expected:
SELECT ST_Intersects(
ST_GeomFromText('POLYGON((-12 0,12 0,12 50.7,-12 50.7,-12 0))', 4326),
ST_GeomFromText('POINT(6.0 50.9)', 4326)
);
Now when I run this same query, but with two geographies instead of geometries the query returns TRUE:
SELECT ST_Intersects(
ST_GeogFromText('POLYGON((-12 0,12 0,12 50.7,-12 50.7,-12 0))'),
ST_GeogFromText('POINT(6 50.9)')
);
I expect that the geography version uses shortest great circle distance to create the polygon, while the geometry version creates the polygon on a flat plane and only then projects this on the WGS84 ellipse.
Can someone verify or debunk my suspicions?
I am running postgresql 9.6 with PostGis 2.4.4

Operations on geography data type are done over a sphere. Operations on geometry data type are done over a plane.
The shortest line joining two points on a plane is a straight line.
The shortest line joining two points on a sphere is an arc. This arc is called the great circle arc and is build by intersecting the sphere with a plan going through the 2 points and the center of the earth.
Consequently, the arc going through -12;50.7N and +12;50.7N with pass through a point near 0;51.3N. This holds true for lines but also for polygon boundaries.
This doc has some interesting graphics to understand the concepts behind the geography type

Related

Polygon triangulation with collinear points?

I have a polygon with collinear points. I want to triangulate the polygon while retaining all the collinear points, since I require those vertices on the generated meshes. Currently I tried to use poly2tri, but it doesn't support collinear points. Is there a polygon triangulation algorithm which support collinear points?
Try moving the points slightly, so they are not colinear. Doing the meshing and then moving the points back.
I tried running the meshing algorithm, then perturbing all the points it missed, then running it again.
It can be quite slow but it does work.
A simple polygon with collinear vertices presents a serious problem for the "ear splitting" triangulation. The best example to see this problem - sketch yourself a 5-point star. Pick any of the points as the convex vertex for a candidate ear.
The diagonal for this ear lies completely within the polygon, and doesn't form "X" intersections with any of the other edges, so by the criteria for a "valid diagonal", it should work. But, notice that once you slice off the ear, the remaining polygon is no longer a simple polygon - because it contains two vertices where the edges meet at a straight (180 deg.) angle. That alone disqualifies the new sub-polygon as "simple", and it will crash any attempt to continue triangulation on it using ear-splitting. I will post a separate question on how best to triangulate these ill-conditioned polys.

Given an irregular polygon's vertex list, how to create internal triangles to build a flat 3D mesh efficiently?

I'm using Unity, but the solution should be generic.
I will get user input from mouse clicks, which define the vertex list of a closed irregular polygon.
That vertices will define the outer edges of a flat 3D mesh.
To procedurally generate a mesh in Unity, I have to specify all the vertices and how they are connected to form triangles.
So, for convex polygons it's trivial, I'd just make triangles with vertices 1,2,3 then 1,3,4 etc. forming something like a Peacock tail.
But for concave polygons it's not so simple.
Is there an efficient algorithm to find the internal triangles?
You could make use of a constrained Delaunay triangulation (which is not trivial to implement!). Good library implementations are available within Triangle and CGAL, providing efficient O(n*log(n)) implementations.
If the vertex set is small, the ear-clipping algorithm is also a possibility, although it wont necessarily give you a Delaunay triangulation (it will typically produce sub-optimal triangles) and runs in O(n^2). It is pretty easy to implement yourself though.
Since the input vertices exist on a flat plane in 3d space, you could obtain a 2d problem by projecting onto the plane, computing the triangulation in 2d and then applying the same mesh topology to your 3d vertex set.
I've implemented the ear clipping algorithm as follows:
Iterate over the vertices until a convex vertex, v is found
Check whether any point on the polygon lies within the triangle (v-1,v,v+1). If there are, then you need to partition the polygon along the vertices v, and the point which is farthest away from the line (v-1, v+1). Recursively evaluate both partitions.
If the triangle around vertex v contains no other vertices, add the triangle to your output list and remove vertex v, repeat until done.
Notes:
This is inherently a 2D operation even when working on 3D faces. To consider the problem in 2D, simply ignore the vector coordinate of the face's normal which has the largest absolute value. (This is how you "project" the 3D face into 2D coordinates). For example, if the face had normal (0,1,0), you would ignore the y coordinate and work in the x,z plane.
To determine which vertices are convex, you first need to know the polygon's winding. You can determine this by finding the leftmost (smallest x coordinate) vertex in the polygon (break ties by finding the smallest y). Such a vertex is always convex, so the winding of this vertex gives you the winding of the polygon.
You determine winding and/or convexity with the signed triangle area equation. See: http://softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm. Depending on your polygon's winding, all convex triangles with either have positive area (counterclockwise winding), or negative area (clockwise winding).
The point-in-triangle formula is constructed from the signed-triangle-area formula. See: How to determine if a point is in a 2D triangle?.
In step 2 where you need to determine which vertex (v) is farthest away from the line, you can do so by forming the triangles (L0, v, L1), and checking which one has the largest area (absolute value, unless you're assuming a specific winding direction)
This algorithm is not well defined for self-intersecting polygons, and due to the nature of floating point precision, you will likely encounter such a case. Some safeguards can be implemented for stability: - A point should not be considered to be inside your triangle unless it is a concave point. (Such a case indicates self-intersection and you should not partition your set along this vertex). You may encounter a situation where a partition is entirely concave (i.e. it's wound differently to the original polygon's winding). This partition should be discarded.
Because the algorithm is cyclic and involves partitioning the sets, it is highly efficient to use a bidirectional link list structure with an array for storage. You can then partition the sets in 0(1), however the algorithm still has an average O(n^2) runtime. The best case running time is actually a set where you need to partition many times, as this rapidly reduces the number of comparisons.
There is a community script for triangulating concave polygons but I've not personally used it. The author claims it works on 3D points as well as 2D.
One hack I've used in the past if I want to constrain the problem to 2D is to use principal component analysis to find the 2 axes of greatest change in my 3D data and making these my "X" and "Y".

Convex hull of (longitude, latitude)-points on the surface of a sphere

Standard convex hull algorithms will not work with (longitude, latitude)-points, because standard algorithms assume you want the hull of a set of Cartesian points. Latitude-longitude points are not Cartesian, because longitude "wraps around" at the anti-meridian (+/- 180 degrees). I.e., two degrees east of longitude 179 is -179.
So if your set of points happens to straddle the anti-meridian, you will compute spurious hulls that stretch all the way around the world incorrectly.
Any suggestions for tricks I could apply with a standard convex hull algorithm to correct for this, or pointers to proper "geospherical" hull algorithms?
Now that I think on it, there are more interesting cases to consider than straddling the anti-merdian. Consider a "band" of points that encircle the earth -- its convex hull would have no east/west bounds. Or even further, what is the convex hull of {(0,0), (0, 90), (0, -90), (90, 0), (-90, 0), (180, 0)}? -- it would seem to contain the entire surface of the earth, so which points are on its perimeter?
Standard convex hull algorithms are not defeated by the wrapping-around of the coordinates on the surface of the Earth but by a more fundamental problem. The surface of a sphere (let's forget the not-quite-sphericity of the Earth) is not a Euclidean space so Euclidean geometry doesn't work, and convex hull routines which assume that the underlying space is Euclidean (show me one which doesn't, please) won't work.
The surface of the sphere conforms to the concepts of an elliptic geometry where lines are great circles and antipodal points are considered the same point. You've already started to experience the issues arising from trying to apply a Euclidean concept of convexity to an elliptic space.
One approach open to you would be to adopt the definitions of geodesic convexity and implement a geodesic convex hull routine. That looks quite hairy. And it may not produce results which conform to your (generally Euclidean) expectations. In many cases, for 3 arbitrary points, the convex hull turns out to be the entire surface of the sphere.
Another approach, one adopted by navigators and cartographers through the ages, would be to project part of the surface of the sphere (a part containing all your points) into Euclidean space (which is the subject of map projections and I won't bother you with references to the extensive literature thereon) and to figure out the convex hull of the projected points. Project the area you are interested in onto the plane and adjust the coordinates so that they do not wrap around; for example, if you were interested in France you might adjust all longitudes by adding 30deg so that the whole country was coordinated by +ve numbers.
While I'm writing, the idea proposed in #Li-aung Yip's answer, of using a 3D convex hull algorithm, strikes me as misguided. The 3D convex hull of the set of surface points will include points, edges and faces which lie inside the sphere. These literally do not exist on the 2D surface of the sphere and only change your difficulties from wrestling with the not-quite-right concept in 2D to quite-wrong in 3D. Further, I learned from the Wikipedia article I referenced that a closed hemisphere (ie one which includes its 'equator') is not convex in the geometry of the surface of the sphere.
Instead of considering your data as latitude-longitude data, could you instead consider it in 3D space and apply a 3D convex hull algorithm? You may be able to then find the 2D convex hull you desire by analysing the 3D convex hull.
This returns you to well-travelled algorithms for cartesian convex hulls (albeit in three dimensions) and has no issues with wrap around of the coordinates.
Alternately, there's this paper: Computing the Convex Hull of a Simple Polygon on the Sphere (1996) which seems to deal with some of the same issues that you're dealing with (coordinate wrap-around, etc.)
If all your points are within a hemisphere (that is, if you can find a cut plane through the center of the Earth that puts them all on one side), then you can do a central a.k.a. gnomic a.k.a. gnomonic projection from the center of the Earth to a plane parallel to the cut plane. Then all great circles become straight lines in the projection, and so a convex hull in the projection will map back to a correct convex hull on the Earth. You can see how wrong lat/lon points are by looking at the latitude lines in the "Gnomonic Projection" section here (notice that the longitude lines remain straight).
(Treating the Earth as a sphere still isn't quite right, but it's a good second approximation. I don't think points on a true least-distance path across a more realistic Earth (say WGS84) generally lie on a plane through the center. Maybe pretending they do gives you a better approximation than what you get with a sphere.)
FutureNerd:
You are absolutely correct. I had to solve the exact same problem as Maxy-B for my application. As a first iteration, I just treated (lng,lat) as (x,y) and ran a standard 2D algorithm. This worked fine as long as nobody looked too close, because all my data were in the contiguous U.S. As a second iteration, though, I used your approach and proved the concept.
The points MUST be in the same hemisphere. As it turns out, choosing this hemisphere is non-trivial (it's not just the points' center, as I had initially guessed.) To illustrate, consider the following four points: (0,0), (-60,0), (+60,0) along the equator, and (0,90) the north pole. However you choose to define "center", their center lies on the north pole by symmetry and all four points are in the Northern Hemisphere. However, consider replacing the fourth point with, say (-19, 64) iceland. Now their center is NOT on the north pole, but asymmetrically drawn toward iceland. However, all four points are still in the Northern Hemisphere. Further, the Northern Hemisphere, as uniquely defined by the North Pole, is the ONLY hemisphere they share. So calculating this "pole" becomes algorithmic, not algebraic.
See my repository for the Python code:
https://github.com/VictorDavis/GeoConvexHull
This question has been answered a while ago, but I would like to sum up the results of my research.
The spherical convex hull is basically defined only for non-antipodal points. Supposing all the points are on the same hemisphere, you can compute their convex hull in two main ways:
Project the points to a plane using gnomonic/central projection and apply a planar convex hull algorithm. See Lin-Lin Chen, T. C. Woo, "Computational Geometry on the Sphere With Application to Automated Machining" (1992). If the points are on a known hemisphere, you can hard-code on which plane to project the points unto.
Adapt planar convex hull algorithms to the sphere. See C. Grima and A. Marquez, "Computational Geometry on Surfaces: Performing Computational Geometry on the Cylinder, the Sphere, the Torus, and the Cone", Springer (2002). This reference seems to give a similar method to the abstract referenced by Li-aung Yip above.
For reference, in Python I am working on an implementation of my own, which currently works only for points on the Northern hemisphere.
See also this question on Math Overflow.
All edges of a spherical convex hull can be viewed/treated as great circles (seminally, all edges of a convex hull in euclidean space can be treated as lines (rather than a line segment)). Each one of these great circles cuts the sphere into two hemispheres. You could thus conceive each great circle as a constraint. A point that is within the convex hull will be on each of the hemispheres defined by each constraint.
Each edge of the original polygon is a candidate edge of the convex hull. To verify if it is indeed an edge of the convex hull, you'd simply need to verify if all nodes of the polygon are on the hemisphere defined by the great circle that goes through the two nodes of the edge in question. However, we'd still need to create new edges that surpass the concave nodes of the polygon.
But lets rather shortcut / brute-forces this:
Draw a great circle between every pair of nodes in the polygon. Do this in both directions (i.e. the great circle connecting A to B and the great circle connecting B to A). For a polygon with N nodes, you will thus end up with N^2 great circle. Each one of these great circles is a candidate constraint (i.e. a candidate edge of the convex polygon). Some of these great circles will overlap with the edges of the original polygon, but most won't. Now, remember again: each great circle is a constraint that constrains the sphere to one hemisphere. Now verify if all nodes of the original polygon satisfy the constraint (i.e. if all nodes are on the hemisphere defined by the great circle). If yes, then this great circle is an edge of the convex hull. If, however a single node of the original polygon does not satisfy the constraint, then it isn't and you can discard this great circle.
The beauty of this is that once you converted your latitudes and longitudes into cartesian vectors pointing onto the unit sphere, it really just requires dot products and cross products
- You find the great circle that passes through two points on a sphere by its cross product
- A point is on the hemisphere defined by a great circle if the dot product of the great circle and the point is greater (or equal) to 0.
So even for polygons with a large number of edges, this brute force method should work just fine.

polygon vertices - clockwise or counterclockwise

I came across this link http://www.mathopenref.com/coordpolygonarea2.html
It explains how to calculate the area of a polygon and helps to identify whether the polygon vertices we entered is clockwise or counter clockwise.
If area value is +ve, it is clockwise, if it is -nv then it is in counterclockwise.
My requirement is to identify only whether it is clockwise or counterclockwise. Is this rule will work correctly (though there are limitations as mentioned in the link). I have only regular polygons (not complicated, no self intersections) but the vertices are more.
I am not interested in the area value accuracy, just to know the ring rotation.
Any other thought on this.
For convex polygons:
Select two edges with a common vertex.
Lets say, edge1 is between vertex A and B. Edge2 is between vertex B and C.
Define to vectors: vect1: A----->B
vect2: B----->C
Cross product vect1 and vect2.
If the result is positive, the sequence A-->B-->C is Counter-clockwise.
If the result is negative, the sequence A-->B-->C is clockwise.
If you have only convex polygons (and all regular polygons are convex), and if your points are all organized consistently--either all counterclockwise or all clockwise--then you can determine which by just computing the (signed) area of one triangle determined by any three consecutive points. This is essentially computing the cross product of the two vectors along the two edges.

Detecting arbitrary shapes

Greetings,
We have a set of points which represent an intersection of a 3d body and a horizontal plane. We would like to detect the 2D shapes that represent the cross sections of the body. There can be one or more such shapes. We found articles that discuss how to operate on images using Hough Transform, but we may have thousands of such points, so converting to an image is very wasteful. Is there a simpler way to do this?
Thank you
In converting your 3D model to a set of points, you have thrown away the information required to find the intersection shapes. Walk the edge-face connectivity graph of your 3D model to find the edge-plane intersection points in order.
Assuming you have, or can construct, the 3d model topography (some number of vertices, edges between vertices, faces bound by edges):
Iterate through the edge list until you find one that intersects the test plane, add it to a list
Pick one of the faces that share this edge
Iterate through the other edges of that face to find the next intersection, add it to the list
Repeat for the other face that shares that edge until you arrive back at the starting edge
You've built an ordered list of edges that intersect the plane - it's trivial to linearly interpolate each edge to find the intersection points, in order, that form the intersection shape. Note that this process assumes that the face polygons are convex, which in your case they are.
If your volume is concave you'll have multiple discrete intersection shapes, and so you need to repeat this process until all edges have been examined.
There's some java code that does this here
The algorithm / code from the accepted answer does not work for complex special cases, when the plane intersects some vertices of a concave surface. In this case "walking" the edge-face connectivity graph greedily could close some of the polygons before time.
What happens is, that because the plane intersects a vertex, at one point when walking the graph there are two possibilities for the next edge, and it does matter which one is chosen.
A possible solution is to implement a graph traversal algorithm (for instance depth-first search), and choose the longest loop which contains the starting edge.
It looks like you wanted to combine intersection points back into connected figures using some detection or Hough Transform.
Much simpler and more robust way is to immediately get not just intersection points, but contours of 3D body, where the plane cuts it.
To construct contours on the body given by triangular mesh, define the value in each mesh vertex equal to signed distance from the plane (positive on one side of the plane and negative on the other side). The marching squares algorithm for isovalue=0 can be then applied to extract the segments of the contours:
This algorithm works well even when the plane passes through a vertex or an edge of the mesh.
To better understand what is the result of plane section, please take a look at this short video. Following the links there, one can find the implementation as well.

Resources