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));
Related
I am using this example and try to add a point cloud visualization to it.
Essentially my code is modified code from the linked example:
PointTrackerTwoPass<GrayU8> tracker = FactoryPointTrackerTwoPass.klt(configKlt,
new ConfigGeneralDetector(600, 3, 1), GrayU8.class, GrayS16.class);
visualOdometry = FactoryVisualOdometry.depthDepthPnP(-1, 120, 2, 150, 100, true, sparseDepth, tracker,
GrayU8.class, GrayU16.class);
<...>
visualOdometry.process(grayScaleImage, depth));
Se3_F64 leftToWorld = visualOdometry.getCameraToWorld();
AccessPointTracks3D access = (AccessPointTracks3D) visualOdometry;
int N = access.getAllTracks().size();
for (int i = 0; i < N; i++) {
if (access.isInlier(i)) {
Point3D_F64 inlierWorld = new Point3D_F64();
Point3D_F64 inlierCamera = access.getTrackLocation(i);
georegression.transform.se.SePointOps_F64.transform(leftToWorld, inlierCamera, inlierWorld);
if (tree.add(new My3DPoint(inlierWorld.x, inlierWorld.y, inlierWorld.z)))
totalElementsInTree++;
it produces a point cloud, but it does not resemble my scene closely. Here is a top-to-bottom view of the cloud achieved by rotation of a kinect-camera around it's up-vector. Pictured is a corner of a room. As you see, instead of two straight walls connected in a right angle the code above produces series of arcs or curves. The effect gets even more pronounced if I set the first parameter of FactoryVisualOdometry.depthDepthPnP to a positive integer.
I would like to understand one thing , below I saw that a collision between two rectangles works .
create method:
//nave
spaceShip = new Image(new TextureRegion(new Texture(Gdx.files.internal("rocket.png")),98,154));
spaceShip.setOrigin(spaceShip.getWidth()/2, spaceShip.getHeight()/2);
spaceShip.setBounds(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
spaceShip.setZIndex(3);
//meteora
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")),128,128));
meteora.setOrigin(meteora.getWidth()/2,meteora.getHeight()/2);
meteora.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
meteora.setBounds(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
meteora.setZIndex(3);
Render method:
rect1 = new Rectangle(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
rect2 = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
if(Intersector.overlaps(rect1,rect2)){
System.out.println("collision");
}
Now , my question is :
as I can see collisions with dynamic objects .
Let me explain, there will be different now created in a random time .
So how can I tell if a collision occurs with one of these objects and understand what it is .
Rectangle has no method .setName , I wanted to use this to figure out which object my ship touched .
Can anyone recommend a solution ?
Thank You
EDIT
add Image object
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")), 128, 128));
meteora.setOrigin(meteora.getWidth() / 2, meteora.getHeight() / 2);
meteora.setPosition(Gdx.graphics.getWidth() / 2, 100);
meteora.setZIndex(3);
Rectangle rect = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
rectangles.add(rect);
I am not entirely sure what the question is, but in answer to what I think you are getting at:
Typically you would want to add all the new randomly created rectangles to a collection of rectangles, then you can iterate through this collection to check for collisions:
List<Rectangle> rectangles = new ArrayList<Rectangle>(); // a field in your class
// inside the method to create random rectangles
Rectangle tmp = new Rectangle(1,2,3,4);
rectangles.add(tmp);
// inside the method to check for collisions
for(Rectangle rect : rectangles) {
if(Intersector.overlaps(rect, shipRect) {
System.out.println("collision");
}
}
Note that your rect1 for your ship's bounds should be saved as a field (shipRect in this example) as well so that you can refer back to it at any time
So Im new to JME3 and I have a few problems understanding the BetterCharacterControl.
When I try to apply a BetterCharacterControl to a box it always "expands" from the upper part of the box instead of the center. (A picture explains that better:)
I cant find any functions to change the location it gets applied at, I already tried to create a subclass in which I changed the RigidBody to the BoxCollisionShape directly but that seems to somehow screw up the isOnGround Method. Also if I want to use slopes later it would be nice to have the capsule shape.
Box box2 = new Box(10, 15, 10);
player = new Geometry("Player", box2);
player.setLocalTranslation(new Vector3f(0, 20, 0));
Material mat = new Material(assetManager,
"Common/MatDefs/Light/Lighting.j3md");
mat.setBoolean("UseMaterialColors", true);
mat.setColor("Ambient", ColorRGBA.Blue);
mat.setColor("Diffuse", ColorRGBA.Blue);
player.setMaterial(mat);
playerC = new BetterCharacterControl(12, 30, 0);
playerC.setJumpForce(new Vector3f(0, 700, 0));
player.addControl(playerC);
rootNode.attachChild(player);
bulletAppState.getPhysicsSpace().add(playerC);
On a different note, it seems like I i have to apply a huge vector for the jump force for it to do anything (I didnt change any gravity values)
Im glad for any help
i had this same problem. The way I resolved it is not usual. I coded a class and did inherit from BetterCharacterControl overwriting getShape() method as follows:
protected CollisionShape getShape() {
//TODO: cleanup size mess..
CapsuleCollisionShape capsuleCollisionShape = new CapsuleCollisionShape(getFinalRadius(), (getFinalHeight() - (2 * getFinalRadius())));
CompoundCollisionShape compoundCollisionShape = new CompoundCollisionShape();
//Vector3f addLocation = new Vector3f(0, (getFinalHeight() / 2.0f), 0); REMOVED LINE
Vector3f addLocation = new Vector3f(0, 0, 0); //NEW LINE
compoundCollisionShape.addChildShape(capsuleCollisionShape, addLocation);
return compoundCollisionShape;
}
This works because the original code is a composite created in such a way so that the child node is offset by the value: (getFinalHeight () / 2.0f). The new line adds not realize this shift, leaving the object in the center position of the box set. However, this way of solving the problem, it can create problems when actually a composite mesh is used in the final object.
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))
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.