Merging two polygons in Java - java

Is there a clean Java method for merging the points of two given overlapping polygons into one polygon?

What you want is a Convex Hull Algorithm it will take a set of points and return a minimal set of points that encloses the original points. This can be done in n.log n time.

The Area class supports addition of closed polygons.

Convex Hull is different from adding. Adding means making a polygon that looks like the two polygons overlapped which is not necessarily convex.

You can use JTS (Java Topology Suite) for that.
Create your Polygon objects
Use the union method which will return a Set of all points from both polygons
Simple code example:
Given Polygon 1 (as WKT): POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))
Given Polygon 2 (as WKT): POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))
// create polygons
Polygon p1 = new GeometryFactory().createPolygon(new Coordinate[]{new Coordinate(0, 0), new Coordinate(0,10), new Coordinate(10,10), new Coordinate(10,0), new Coordinate(0,0)});
Polygon p2 = new GeometryFactory().createPolygon(new Coordinate[]{new Coordinate(5,5), new Coordinate(15,5), new Coordinate(15,15), new Coordinate(5,15), new Coordinate(5,5)});
// calculate union
Geometry union = p1.union(p2);
// print as WKT
System.out.println(union.toText());
The result is a new polygon:
POLYGON ((0 0, 0 10, 5 10, 5 15, 15 15, 15 5, 10 5, 10 0, 0 0))

Using the algorithm #Charles Keepax provided, you can do something like this:
public static Polygon mergePolygons(Polygon a, Polygon b) {
// create arrays for border of each polygon
Point[] a_pts = new Point[a.npoints];
Point[] b_pts = new Point[b.npoints];
// fill them in an array of Points instead of separate coords.
Arrays.setAll(a_pts, i -> new Point(a.xpoints[i], a.ypoints[i]));
Arrays.setAll(b_pts, i -> new Point(b.xpoints[i], b.ypoints[i]));
// first merge 2 arrays into 1
Point[] all_pts = (Point[]) mergeArrays(a_pts, b_pts);
// apply Convex Hull on resulting array
convexHull(all_pts, all_pts.length);
// separate x and y coordinates back
int[] x_pts = new int[all_pts.length];
int[] y_pts = new int[all_pts.length];
Arrays.setAll(x_pts, i -> all_pts[i].x);
Arrays.setAll(y_pts, i -> all_pts[i].y);
// return polygon object using those coordinates
return new Polygon(x_pts, y_pts, all_pts.length);
}
But of course solution by #Lars is more practical, this is how you could do it in a naive way.

Related

Java JTS Polygon contains Another Polgyon

I am trying to use JTS to tell if one Polygon contains another Polygon.
I have resources here. How do I utilize the syntax? this is giving me errors. The next step is to apply contains. If anyone has experience with JTS, it would be helpful.
https://gis.stackexchange.com/questions/368520/jts-geometry-contains-not-detecting-point-of-an-inner-polygon-on-edge-of-outer
https://gis.stackexchange.com/questions/262751/how-to-determine-if-one-polygon-is-contained-in-another
https://locationtech.github.io/jts/javadoc/org/locationtech/jts/geom/Polygon.html
Polygon item1 = ((0 0, 1000 0, 1000 1000, 0 1000, 0 0))
Polygon item2 = ((500 500, 1000 500, 600 600, 500 600, 500 500))
You cannot create a polygon just like that. JTS is a rather heavy framework, so you need to go the full route.
Everything starts with GeometryFactorydocs. It is responsible for creating all geometries, it is necessary because it takes into account a few things like PrecisionModel for example.
You need to understand the hierarchy of geometries, Polygon is described by a line - LineRig or LineString (the difference is out of the scope for this question).
You need to realize that every line consists of points, which can be described either by Point or Coordinate. So if you want to create a Polygon
The code would look like this:
GeometryFactory factory = new GeometryFactory(); //default
Coordinate[] coordinates1 = {
new CoordinateXY(0,0),
new CoordinateXY(1000,0),
new CoordinateXY(1000, 1000),
new CoordinateXY(0, 1000),
new CoordinateXY(0, 0)
};
Coordinate[] coordinates2 = {
new CoordinateXY(500,500),
new CoordinateXY(1000,500),
new CoordinateXY(600, 600),
new CoordinateXY(500, 600),
new CoordinateXY(500, 500)
};
LinearRing linearRing1 = factory.createLinearRing(coordinates1);
LinearRing linearRing2 = factory.createLinearRing(coordinates2);
Polygon polygon1 = factory.createPolygon(linearRing1);
Polygon polygon2 = factory.createPolygon(linearRing2);
assertTrue(polygon1.contains(polygon2));

Finding x amount of points in a three dimensional line? (from 2 3d point objects) in Java

So i am using the Java Point3D object. I am wondering the best way to get X amount of points between two 3d points in space.
Point3D a = new Point3D(0, 0, 0);
Point3D b = new Point3D(1, 4, 9);
int count = 30 //Used to set how many points to represent the line
//This would return a list of points that represent the line
Point3D[] pointsBetween(a, b, count);
Would this be best achieved with vectors? I am also running this pretty heavily, so i am looking for the most efficient way to calculate this. Thanks!
Turns out it was vectors, Simply get a vector from point a to point b, then add in that direction (add divided by the amount of steps or count)

Keep a square at the corner of a rotated square in Java

I'm making a zamboni driving game and im doing collision detection. I'm trying to make it by checking if a corner of the zamboni is inside a wall. I draw a rectangle at the corner location by using LWJGL. At the moment, I have the corner located at the center of the zamboni, but I want it to be at the top left corner of it. I can make this, but when I rotate the zamboni, the corner thing does not go to the location of the actual corner of the zamboni, but instead it stays at the same position as when the zamboni is not rotated.
Here's my code:
cornerLocation.x = position.x + (float) Math.cos(Math.toRadians(angle + 90));
cornerLocation.y = position.y + (float) Math.sin(Math.toRadians(angle + 90));
position is a vector where i store the location of the zamboni. The origin of it is at the center so the top-left corner of the zamboni is basically at position-size/2.
How can I make it so it is always at the actual corner the the zamboni, even when I rotate it?
You need two set of coordinates:
Zamboni corners points.
Rectangle points for collision detection.
The Rectangle points can be calculated from zamboni corners. For this:
You must to get the "min-x" and the "min-y" of them:
Point topLeftRect = new Point(Math.min(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.min(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Point bottomRightRect = new Point(Math.max(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.max(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Rectangle collisionDetectionRectangle =new Rectangle(topLeftRect,bottomRightRect);
Detection collisions rectangle size is usually greater than the Zamboni Size.
What happens with rotation?
Steps (one of many possibles ways)
the 2d points {x,y} -> goes to 3d: {x, y, 1}
float[][] zamboniCorner1Point3d = {{zamboniCorner1.x,zamboniCorner1.y,1}};
...
float[][] zamboniCorner4Point3d = {{zamboniCorner4.x,zamboniCorner4.y,1}};
1.- You need to move zamboni's center to (0,0) and you drop the zamboni corners with center:
You can used this 3-d matrix (1):
float[][] translationMatrix1 = {{1, 0,-zamboniCenter.x},{0, 1,-zamboniCenter.y},{0, 0, 1}};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3d,translationMatrix1);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3d,translationMatrix1);
Point' -> Point * Matrix1
2.- You need to rotate all cordinates (center of zamboni doesn't change, it's {{0,0,1})
You can used this 3-d matrix (2):
float[][] rotationMatrix2 = {Math.cos(rotationAngle), Math.sin(rotationAngle), 0 }, {-Math.sin(rotationAngle), Math.cos(rotationAngle), 0}, {0, 0, 1 }};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,rotationMatrix2);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3dNew,rotationMatrix2);
Point' -> Point * Matrix2
3.- You need to move zamboni's center (from the {0,0,1}) to original position (in the same place at first {{zamboniCenter.x,zamboniCenter.y,1}}) and drop the corners with center.
You can used a 3-d matrix(3):
float[][] translationMatrix3 = {{1, 0, zamboniCenter.x},{0, 1, zamboniCenter.y},{0, 0, 1}};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,translationMatrix3);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,translationMatrix3);
Point' -> Point * Matrix3
4.- Set the new values.
zamboniCorner1.x = zamboniCorner1Point3dNew[0];
zamboniCorner1.y = zamboniCorner1Point3dNew[1];
...
zamboniCorner4.x = zamboniCorner4Point3dNew[0];
zamboniCorner4.y = zamboniCorner4Point3dNew[1];
5.- Then, obtain: min-x, min-y, max-x and max-y of the new zamboni corners, there's your new collision detection rect.
top-lef: (min-x,min-y) bottom-right:(max-x,max-y).
Point topLeftRect = new Point(Math.min(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.min(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Point bottomRightRect = new Point(Math.max(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.max(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Rectangle collisionDetectionRectangle =new Rectangle(topLeftRect,bottomRightRect);
The steps 1, 2 and 3; can be computed together:
float[][] matrix = Matrix.cross(Matrix.cross(translationMatrix1,rotationMatrix2),translationMatrix3);
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3d,matrix);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3d,matrix);
Point' -> Point * (Matrix-1 * Matrix-2 * Matrix-3)

What is the translation of this code to OpenCV Java?

This code is OpenCV c++:
lines = cvHoughCircles(frame2, storage, CV_HOUGH_GRADIENT, 1, 50, 300, 60, 10, 600);
for (int i = 0; i < lines.total(); i++) {
//Would like the code to go here
CvPoint2D32f point = new CvPoint2D32f(cvGetSeqElem(lines, i));
cvCircle(src, cvPoint((int)point.x(), (int)point.y()), 3, CvScalar.WHITE, -1, 8, 0);
Point p = new Point((int)point.x(), (int)point.y());
points.add(p);
}
What is the correspondent in the new Java Api? I cannot get CvPoint2D32f, cvGetSeqElem and CV_AA. I found that existed in JavaCV but cannot find them in OpenCV Java api.
Thanks
EDIT:
I've changed my code and now I have:
MatOfPoint3 circles = new MatOfPoint3();
Imgproc.HoughCircles(image, circles, Imgproc.CV_HOUGH_GRADIENT,2, image.rows()/4,200,100,0,0);
for(Point3 circle : circles.toArray()){
Point center = new Point(circle.x, circle.y);
int radius = (int) Math.round(circle.z);
Core.circle(image, center, radius, new Scalar(0,255,0), 6, 8, 0);
}
However I got an error at for(Point3 circle : circles.toArray()):
Exception in thread "main" java.lang.UnsupportedOperationException: Mat data type is not compatible: 21
at org.opencv.core.Mat.get(Mat.java:2581)
at org.opencv.core.MatOfPoint3.toArray(MatOfPoint3.java:64)
at org.opencv.core.MatOfPoint3.toList(MatOfPoint3.java:76)
at main.java.DetectFaceDemo.run(HelloOpenCV.java:60)
at main.java.HelloOpenCV.main(HelloOpenCV.java:83)
Any thoughts on this? Thanks
EDIT 2:
The solution to last edit problem resides in
MatOfPoint3 circles = new MatOfPoint3();
It must be
MatOfPoint3f circles = new MatOfPoint3f();
Use Class Point3. Template class for 3D points specified by its coordinates x, y and z. An instance of the class is interchangeable with the C structure CvPoint2D32f. Similarly to Point_, the coordinates of 3D points can be converted to another type. The vector arithmetic and comparison operations are also supported.

Java polygons and Area

Ok so I have a number of polygons (outlined in white in the image).
In an attempt to add all the polygons together so that I get one polygon, which is the outer bounds of all of them, I have converted each Polygon (java class) to an Area(java class) and then added the areas together with the add(Area a) method provided by the Area class.
From there I converted the area back to a polygon and drew it as a filled Polygon (the purple area in the image).
This however is not what I was expecting. Can anyone think of a was where I can do this correctly, or at least just add the triangle area to my polygon?
When I just draw all the separate polygons with a fill I get what I want (drawn) but I need a Polygon representation of it.
I can recommend to use JTS. Just create your geometries you want to combine and use the union method. Afterwards you can use the new geometry and paint it using your previous code. Simple code example for union:
// build polygon p1
Polygon p1 = new GeometryFactory().createPolygon(new Coordinate[]{new Coordinate(0,0), new Coordinate(0,10), new Coordinate(10,10), new Coordinate(10,0), new Coordinate(0,0)});
// build polygon p2
Polygon p2 = new GeometryFactory().createPolygon(new Coordinate[]{new Coordinate(0,0), new Coordinate(0,30), new Coordinate(5,30), new Coordinate(5,0), new Coordinate(0,0)});
// calculate polygon3 as the union of p1 and p2
Polygon p3 = (Polygon) p1.union(p2);
// print simple WKT
System.out.println(p3.toText());
Output in this case is (like expected):
POLYGON ((0 0, 0 10, 0 30, 5 30, 5 10, 10 10, 10 0, 5 0, 0 0))

Categories

Resources