I have polygon shape and I want to convert it to MultiLineString. Note that usually the direction is different: From points, coords, lines etc. using GeometryFactory build polygon. I started to thinking about GeometryTransformer but it's hard to understand the documentation there... So I have this:
import com.vividsolutions.jts.geom.*;
...
GeometryFactory gFactory = new GeometryFactory();
GeometryTransformer gTransform = new GeometryTransformer();
Polygon polygon = gFactory.createPolygon(someLinearRing, null);
MultiLineString mlString = polygon.TODO?
How to continue in the TODO?
The method Polygon.getBoundary() computes the boundaries of the polygon. If the polygon has not holes (also only one boundary), a object of type LinearRing is returned.
If the polygons has holes - also more than one boundary - a object of type MultiLineString is returned.
Use the methode Polygon.getNumInteriorRing() to check if the polygon has holes and than build a multilinestring is necessary:
GeometryFactory gFactory = new GeometryFactory();
if (polygon.getNumInteriorRing() == 0){
// polygon has not holes, so extract the exterior ring
// and build a multilinestring
return gFactory.createMultiLineString(polygon.getExteriorRing());
}
else{
// Polygon has holes, also several boundaries.
// Simply run getBoundary(), it will return a multilinestring
return polygon.getBoundary();
}
Related
I have this little piece of code:
DelaunayTriangulationBuilder builder = new DelaunayTriangulationBuilder();
builder.setSites(geometry);
builder.setTolerance(0.0000001);
Geometry triangulation = builder.getTriangles(new GeometryFactory());
It will tessellate a Geometry to create a list of triangles. I want to use this result in a 3d application, but in order to optimize the storage space I would like to have it in the following structure:
An ordered list of unique vertices (of the outter edges)
A list of vertex indices (cw or ccw) that represent each of the triangles
I have a hard time finding an efficient way to do that using the JTS DelaunayTriangulationBuilder class.
Any help would be appreciated, thank you!
I think that rather than a Geometry you want to work with a QuadEdgeSubdivision. Then you can have code like:
QuadEdgeSubdivision quadEdgeSubdivision = builder.getSubdivision();
#SuppressWarnings("unchecked")
Collection<QuadEdge> primaryEdges = quadEdgeSubdivision.getPrimaryEdges(false);
for (QuadEdge edge : primaryEdges) {
if (quadEdgeSubdivision.isFrameEdge(edge)){
// this is an outer edge
}
// Edges have vertexes and are part of a triangle
Vertex[] v = new Vertex[3];
v[0] = edge.orig();
v[1] = edge.dest();
v[2] = edge.oNext().dest();
// or you can get a LineString
LineSegment lineSegment = edges[i].toLineSegment();
...
}
You can see this sort of thing in action in the GeoTools Contour process that I wrote about a couple of years ago.
I want to do some geometric calculations in Java and found that Spatial4j should suit my needs.
I want to be able to compute stuff like whether two polygons overlap or what their bounding box is.
My thinking is that I need to create a polygon from a series of points.
To that end I have tested with this code:
Point point1 = shapeFactory.pointXY(0, 0);
Point point2 = shapeFactory.pointXY(5, 1);
Point point3 = shapeFactory.pointXY(3, 3);
Point point4 = shapeFactory.pointXY(0, 1);
List<Point> points = new ArrayList<>();
points.addAll(Arrays.asList(point1, point2, point3, point4));
So, I have my points now. How do I go about making a polygon (or for that matter any shape) from these points ?
I would think that shapeFactory.polygon() would create me a polygon but that throws me an UnsupportedOperationException. Any help ?
Alright, it seems that Spatial4j does not connect the points, so it is not a filled shape. Instead I relied on the Spatial4j implementation of JTS and that did the trick. (Spatial4j's polygon is not implemented).
JtsSpatialContextFactory jtsSpatialContextFactory = new JtsSpatialContextFactory();
JtsSpatialContext jtsSpatialContext = jtsSpatialContextFactory.newSpatialContext();
JtsShapeFactory jtsShapeFactory = jtsSpatialContext.getShapeFactory();
ShapeFactory.PolygonBuilder polygonBuilder = jtsShapeFactory.polygon();
// note due to it being a builder one needs to chain the points.
Shape shape1 = polygonBuilder.pointXY(4, 0).pointXY(3, 3).pointXY(1, 4).pointXY(0, 0).pointXY(4, 0).build();
Now doing for example shape.getArea() returns the surface area.
One can also create a Geometry from a Shape by doing jtsShapeFactory.getGeometryFrom(shape), which then returns a Geometry.
Note: Watch out with doing polygonBuilder.pointXY() even after calling build(). It will still append these points to whatever was chained to the builder before the build.
I am trying to add a functionnality which would let me see if a point is inside a polygon.
Here's the code snippet to see if the point is inside my polygon
int x = 265;
int y = 300;
List<Point> points = new ArrayList<Point>();
points.add(new Point(233,155));
points.add(new Point(347,269));
points.add(new Point(136,251));
points.add(new Point(250,366));
Polygon polygon = new Polygon();//java.awt.Polygon
for(Point point : points) {
polygon.addPoint(point.x, point.y);
}
return polygon.contains(x,y);
The code seems to work if my point is closer to the upper-left side of the polygon, however when the point is on the bottom-right side, the method contains will return false.
Graph of my polygon and the point in question : https://www.desmos.com/calculator/tnglrdpivn
Any idea why this happens ?
The key here is in the ordering of your points. Though plotted all at once on a graph, they look like they form a nice looking polygon, if you play connect-the-dots with them in the order you add them to the polygon, they form a very weird shape, and the point is really not contained in the polygon.
If you reverse the order of your last two points, the connect-the-dots polygon is properly formed, and then the point is contained in the polygon.
If I have a linestring in JTS (or some sort of open polyline generally) with its direction defined by it start point, is there some smart way to tell at intersections with a closed polygon whether the linestring is 'entering' the polygon or exiting it, either:
In JRS ( I cant find a way in docs), only the coordinates where the line and closed shape intersect with intersection
Some general clever way. I currently have done it by testing a point a very small distance, along linestring on either side of polygon edge and testing which was 'in', and which was 'out'. This could conceivably return an incorrect result if the polygonhad a (unlikely) REALLY sharp internal edge.
Check if the startpoint of a segment of the linestring is inside the polygon or outside to figure out if it is entering or exiting the polygon. Simple code example:
// some demo polygon + line
Polygon polygon = new GeometryFactory().createPolygon(new Coordinate[]{new Coordinate(1,1), new Coordinate(6,1), new Coordinate(6,6), new Coordinate(1,6), new Coordinate(1,1)});
LineString line = new GeometryFactory().createLineString(new Coordinate[]{new Coordinate(0, 0), new Coordinate(5,5), new Coordinate(10,5)});
// check for intersection in the first place
if(line.intersects(polygon)){
System.out.println("line intersects polygon!");
// iterate over all segments of the linestring and check for intersections
for(int i = 1; i < line.getNumPoints(); i++){
// create line for current segment
LineString currentSegment = new GeometryFactory().createLineString(new Coordinate[]{line.getCoordinates()[i-1], line.getCoordinates()[i]});
// check if line is intersecting with ring
if(currentSegment.intersects(polygon)){
// segment is entering the ring if startpoint is outside the ring
if(!polygon.contains(currentSegment.getStartPoint())){
System.out.println("This segment is entering the polygon -> ");
System.out.println(currentSegment.toText());
// startpoint is inside the ring
}
if (polygon.contains(currentSegment.getStartPoint())) {
System.out.println("This segment is exiting the polygon -> ");
System.out.println(currentSegment.toText());
}
}
}
} else {
System.out.println("line is not intersecting the polygon!");
}
This code does not cover all possibilities. E.g. if single segments are intersecting the polygon multiple times (entering + exiting) this is not covered in this example. In this case just count the number of intersections and create the according number of linestrings between the intersection points.
Answering my own question - for anyone who has similar problem.
I ended up writing a bit of code based on number of intersections (since I had these already via JTS). Ideas stemmed on stuff from crossing number algorithm and odd-even rule.
The 'rules' ( I do not think there are exceptions, probably wrong) are:
An enter intersection must be followed by an exit, and vice versa.
If you start in the closed polygon, the first intersection point is an exit.
If you do not start in the polygon, the first intersection is an enter.
As pseudocode, something like this:
Get intersection_points between polyline and closed polygon // using JTS.intersect()
Sort intersection_points along chainage of polyline
if polyline start_point in polygon // using JTS.contains()
first intersect_point is an EXIT, next is an ENTER, EXIT, ENTER and so on alternating along chainage.
else //start point not in polygon
first intersect_point is an ENTER, next is an EXIT, ENTER, EXIT and so on along chainage.
Haven't looked at source for JTS intersect and contains methods so might be some doubling in what I am doing and some optimisation there.
I am using the following code to find a point of coordinates exists in the code or not:
mMap.setOnMapClickListener(new OnMapClickListener()
{
public void onMapClick(LatLng point)
{
boolean checkPoly = true;
Point2D[] points = new Point2D[ myPoints.size()];
for ( int i = 0; i < myPoints.size(); i ++)
{
LatLng pt = myPoints.get(i);
points[i] = new Point2D(pt.latitude, pt.longitude);
}
Polygon2D polygon2d = new SimplePolygon2D(points);
double a = point.latitude;
double b = point.longitude;
Point2D myPt = new Point2D(a,b);
checkPoly = polygon2d.contains(myPt);
Log.i("CHECK", String.valueOf(checkPoly));
if (checkPoly)
{
setMarker(point);
}
else
Toast.makeText(NewSearch.this,"The Location is outside of the Area", Toast.LENGTH_LONG).show();
}
I am using the JavaGeom 0.11.1 library for finding polygon point. However this code was working exactly fine. Note that myPoints array is an ArrayList<LatLng> of all vertices of the polygons drawn on map. However something happened and now it's working for opposite that is outside of map; if i change !checkPoly then it works fine.
Does anyone know what is wrong?
I looked at the source for the polygon boundary definition. It's using the usual convention for "inside," which requires the vertices to be given in CCW order around the "inside" space. It's likely your boundary is given in CW order, which makes the "inside" what most people would call the outside.
In other words, what you think is a polygon is really a hole in the infinite polygon that covers the whole x-y universe.
So reverse the order of boundary vertices and things should start working as you intend.
ADDITION
If you can't reverse the order of vertices, there is a different polygon membership test that doesn't rely on point order. If you are testing membership of the point (x,y), this algorithm assumes that the point (infinity, y) is outside the polygon and then decides whether (x,y) is on the opposide side. The implementation here in C is due to WR Franklin. It would be easy to port this to Java. I've used it several times with excellent results.
I have been using Google android-maps-utils library and you can make use of the PolyUtil class, particularly at this method:
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic)