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.
Related
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.
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();
}
I am currently using OpenCV to create a system which detects whether vehicles are in certain zones. So far, I've got to the point where a Rect is drawn around each vehicle. My next step is to find the central points of these rectangles and see whether that falls within a particular zone.
I realise that the best way of doing this is probably to find the coordinates of the Rect's four corners and then take an average x and average y-coordinate to find the coordinates for the central point. However, I'm not sure how to do this. Is there some function which lets me access OpenCV's Rect coordinates directly?
Edit to original: As was pointed out, we cannot use '+' operator directly on tl() and br().
Use this instead to get the center of a rectangle:
Point p1 = new Point(100, 100);
Point p2 = new Point(600, 800);
Rect myrect = new Rect(p1, p2);
System.out.println(String.format("Rectangle: %s", myrect));
Point centroid = new Point(myrect.x + 0.5*(myrect.width), myrect.y + 0.5*(myrect.height));
System.out.println(String.format("centroid: %s", centroid));
This prints:
Rectangle: {100, 100, 500x700}
centroid: {350.0, 450.0}
Old answer:
[Use rect's methods:
tl ()
br ()
to get the top left and bottom right points, respectively.]
If you did want to use tl, br methods you can do:
Point anotherCentroid = new Point(0.5 * (myrect.br().x + myrect.tl().x), 0.5 * (myrect.br().y + myrect.tl().y));
i want to trace the trajectory between differents points
for the test i creat points and try to link between these points
this is my code
OpenStreetMapLayer osm = new OpenStreetMapLayer();
map.addLayer(vectorLayer);
List<Point>points= new ArrayList<Point>();
Point point = new Point(44.272872,4.27826);
Point point2 = new Point(-55.272873,5.3873837);
Point point3 = new Point(5.272873,54.3873837);
points.add(point);
points.add(point2);
points.add(point3);
Point[] coord=new Point[points.size()];
points.toArray(coord);
polyline.setPoints(coord);
vectorLayer.addComponent(polyline);
Style defaultstyle = new Style();
/* Set stroke color to green, otherwise like default style */
defaultstyle.extendCoreStyle("default");
defaultstyle.setStrokeColor("#0000ff");
defaultstyle.setStrokeWidth(3);
defaultstyle.setFillColor("#adfffc");
defaultstyle.setFillOpacity(0.4);
// Make borders of selected graphs bigger
Style selectStyle = new Style();
selectStyle.setStrokeWidth(5);
StyleMap stylemap = new StyleMap(defaultstyle, defaultstyle, null);
// make selectStyle inherit attributes not explicitly set
stylemap.setExtendDefault(true);
vectorLayer.setStyleMap(stylemap);
but when i execute my code i get just a point i've asked they told me this point is the point of cordinate(0,0)
this is the screen catch of the set of points without ZOOM (the blue point)
http://img4.hostingpics.net/pics/810776sss.png
and this is the MAX ZOOM
http://img4.hostingpics.net/pics/122823ert.png
i want to know if it is a probleme of scale or what?
thanks in advance
You are using https://en.wikipedia.org/wiki/EPSG:4326 coords but OSM is using https://wiki.openstreetmap.org/wiki/EPSG:3857. The first one is in abs(180,90) where the second one is in in abs(6356752,6378137). so your points are basically at the center in spherical mercator and zooming very close will give your result. you have to convert your data e.g. using geotools
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)