Is (JTS) linestring is entering or exiting a polygon - java

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.

Related

Random x,y coordinate within an irregular polygon given a list of x,y-points, without being on such a corner-point nor edge

I'm trying to tackle the following use-case:
Input: A list of x,y-coordinates that will form an irregular polygon (they are guaranteed valid and lines will not intersect; it can however be concaved). Input-format is irrelevant, so I'm currently using two loose int-arrays for x and y respectively.
Output: A random x,y-coordinate within this polygon, which is NOT directly on top of a corner nor edge.
Using the following code, I have been able to tackle the random x,y-coordinate within the polygon:
// Currying Function with two int-arrays as parameters and double-pair return-type
X->Y->{
// Create a Path2D object
java.awt.geom.Path2D path = new java.awt.geom.Path2D.Double();
// Start at the first coordinate given
path.moveTo(X[0], Y[0]);
// Loop over the remaining coordinates:
for(int i=1; i<X.length; i++)
// And draw lines from corner to corner
path.lineTo(X[i], Y[i]);
// After the loop, close the path to finish the polygon
path.closePath();
// Create a Rectangle that encapsulates the entire Path2D-polygon
java.awt.Rectangle rect = s.getBounds();
// The resulting x,y-coordinate, starting uninitialized
double x,y;
// Do-while the Path2D polygon does not contain the random x,y-coordinate:
do{
// Select a random x,y-coordinate within the Rectangle
x = rect.getX() + Math.random()*rect.getWidht();
y = rect.getY() + Math.random()*rect.getHeight();
}while(!path.contains(x,y));
// After which we return this random x,y-coordinate as result:
return new double[]{x,y};
}
This all works as intended. Now I want to make sure that the random x,y-coordinate is not one of the input x,y-coordinates (this is pretty easily) AND is not on an edge/line of the Path2D. This second part I'm not sure how to tackle, and a quick google search wasn't given any useful information, hence this question.
NOTE: I know the chances that the random point is exactly on top of an edge/corner are astronomical small and could probably be ignored, but this is for a challenge, hence the need to implement it regardless.
After the tip of #Andreas in the comments to use a Line2D, I've modified the do-while to:
// The resulting x,y-coordinate, starting uninitialized
double x,y;
// Flag to indicate whether the random x,y-coordinate is on a corner or edge, starting truthy
boolean flag;
// Do-while the Path2D polygon does not contain the random x,y-coordinate:
do{
// Select a random x,y-coordinate within the Rectangle
x = rect.getX() + Math.random()*rect.getWidht();
y = rect.getY() + Math.random()*rect.getHeight();
// Set the flag to false:
flag = false;
// Loop over the pair of x,y-coordinates of the input:
for(int j=0; j<X.length; )
// Create a Line2D using the current pair of x,y-coordinates:
if(new java.awt.geom.Line2D.Double(X[j],Y[j++], X[j],Y[j])
// And if it contains the random x,y-coordinate:
.contains(x,y))
// Change the flag to true
flag = true;
}while(!path.contains(x,y) || flag);

How to create Polygon from Point (Spatial4j)

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.

Removing element from ArrayList Java Processing Boid example

Got this BOID application going in Processing with some steering algorithms.
The boids are stored
in two separate ArrayLists for each colour.
The red boid (predator) has a
pursue function:
class Creature {
int prey = 1;
PVector pursue(ArrayList boids) {
PVector steer = new PVector();
if (prey < boids.size()) {
Creature boid = (Creature) boids.get(prey);
steer = PVector.sub(boid.location, location);
steer.mult(maxpursue);
}
return steer;
}
This function gets the red boids to stand on top of the targeted white boid.
The problem is getting this white boid to disappear when all the red boids are on top of it. (Like shown in the image above)
I can add a new boid or predator with the following, but i cannot remove?:
void mousePressed() {
if (mouseButton == LEFT){
Creature predator = new Creature(mouseX, mouseY, 2);
planet.boids.add(predator);
} else if (mouseButton == RIGHT) {
Creature boid = new Creature(mouseX, mouseY, 1);
planet.boids.add(boid);
planet.boids.remove(boid); // This line does not work?
}
}
The code you posted doesn't make a ton of sense. You want to remove an existing Boid, so why on earth are you creating a new one and then immediately removing it?
You haven't posted an MCVE, so I can only answer in a general sense, but here's what you need to do:
Step 1: Refactor your code so that it makes more sense. Comment every single line if you have to, just to be sure you know exactly what the code is doing. But you shouldn't be doing things like adding a new Boid and then removing it in the very next line. Break your problem down into smaller steps, and make sure each step works perfectly by itself before trying to mix it with other funtionality.
Step 2: Create a function that takes a single white Boid and the List of red Boids, and returns true if that white Boid should be removed. Test this function by itself using hard-coded values in a standalone example sketch.
Step 3: Iterate over your white Boids and call the function you created in step 2 for each one. If the function returns true, then remove that white Boid. You might want to use an Iterator for this step.
If you get stuck on one of those steps, then post an MCVE along with a specific question, and we'll go from there. It's hard to answer general "how do I do this" type questions, but it's much easier to answer specific "I tried X, expected Y, but got Z instead" type questions- especially if we have an MCVE we can actually run on our own machines instead of some disconnected snippets.

JTS: How to convert polygon into MultiLineString

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();
}

Alogritm to find overlap between 2 sections

I have 2 sections, each section contains of 2 Points and each point has X and Y.
What is the best way to find the overlap between these 2 sections? (only on the X relevant here)
public class section
{
double leftPoint;
double rightPoint;
}
Doesn't the rectangle class has methods for this?
If you create two rectangle's (sized and positioned just like those "sections") you can compare them using intersection() what will return an Rectangle of the overlapping area.
Here is example code to show you how to do it. I assume the two sections are (a_from, a_to) and (b_from, b_to) and set the resulting section to be (res_from, res_to). Also I only intersect the intervals on the x-axis as this seems to be what you want. The idea is that the results starts from the later of the two beginnings and ends at the earlier of the two ends.
Point a_from, a_to;
Point b_from, b_to;
Point res_from = new Point();
Point res_to = new Point();
res_from.SetX(Math.max(a_from.getX(), b_from.getX()));
res_to.SetX(Math.min(a_to.getX(), b_to.getX()));
Note that if res_to.x < res_from.x There is no intersection at all.
Also here I assume a_from.x <= a_to.x and b_from.x <= b_to.x which may not always be true. If it is not you have to calculate res_from.x as Math.max(Math.min(a_from.getX(), a_to.getX()), Math.min(b_from.getX(), b_to.getX()))

Categories