I am new to GIS area and I need to validate a geometry in WKT format in java, to check whether a simple polygon is a closed loop, i.e the start and end points of the vertices should be the same. I am currently using jGeometry class of oracle spatial(com.oracle.sdoapi), get the first and last vertices and comparing them. also, i am using getType() method to check whether it is a simple polygon or not. The following is the piece of code that am using:
WKT wkt = new WKT();
JGeometry geometry = wkt.toJGeometry(wkt.getBytes());
double[] d1 = geometry.getFirstPoint();
double[] d2 = geometry.getLastPoint();
if(!jGeometry.getType() == jGeometry.GTYPE_POLYGON){
//error message for other geometries
}
Is there any simple way of doing this or is there any API available? I dont want to reinvent the wheel, if it is already done and simple to use. Thanks!
The Java Topology Suite contains a WKTReader class that will suit your purposes. See http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/io/WKTReader.html. You can use WKTReader to parse the WKT, and look for ParseExceptions, which indicate an invalid WKT.
If the WKT parses, you can then use the instanceof operator or WKTReader.getGeometryType() to determine the type of parsed Geometry class, and see if it's one of the Geometry types (Polygon or Multipolygon) with closed shells like Polygon or Multipolygon.
Related
I am trying to convert the Apache Sedona examples code from scala to java, and I am stucked in the line 128 of the SQL example, which says:
assert(boundary.take(1)(0).get(0)==geometryFactory.createPolygon(coordinates))
I am trying to understand it but I am not familiar to the scala syntax. Can somebody help me obtaining a java equivalent command?
boundary.take(1) gets an array of Rows from Spark DataFrame.
The following code works for me:
GeometryFactory geomFactory = new GeometryFactory();
Point expectedGeom = geomFactory.createPoint(new Coordinate(-88.331492, 32.324142));
Geometry actualGeom = spatialDf.javaRDD().take(1).get(0).<Geometry>getAs(0);
assert(actualGeom.equals(expectedGeom));
Note that you cannot compare a polygon with a geometry using == although you think they are the same polygon. This is because they technically have different types Polygon vs Geometry. Please use equals method to compare them.
It's been a few days that I'm struggling with WKB strings. I need to be able to parse it in order to get the equivalent geometry and extract points coordinates (X,Y,Z). I can't use PostGIS functions.
The only java library that I found was the JTS Topology Suite, that i use as follow :
String wkb = "01ea030000020000009b4d3899fe95154153d97e8f43875941000000000000454003085bc23f9615411b4dc406578759410000000000004740"
byte[] aux = WKBReader.hexToBytes(wkb);
try {
Geometry geom = new WKBReader().read(aux);
} catch (ParseException e) {
e.printStackTrace();
System.err.println("Bad WKB string.");
}
But the it gives me the following error :
com.vividsolutions.jts.io.ParseException: Unknown WKB type 234
234 is the decimal value of the hexadecimal string 'ea'. It's like the JTS Library was only looking at the frist 2 bytes instead of looking at the 4 bytes 'ea03', that correspond to 1002 in little endian (so a LineStringZ).
My question is then : does the JTS Topology Suite handle LineStringZ ? If not, why points can have a Z value ? And how can I parse it correctly ?
Thanks you for reading !
JTs only supports 2D geometries, it does not support a Z value. Points only have X and Y in it.
JTS does support 3D geometries at least in reading and writing. Support may be rather 2.5D than a real 3D but Z values are still carried on in the operations. The problem is that there are two ways for presenting XYZ, XYM, and XYZM geometries in WKB. JTS support the PostGIS EWKB variant as can be seem from the comment in the source code file https://sourceforge.net/p/jts-topo-suite/code/HEAD/tree/trunk/jts/java/src/com/vividsolutions/jts/io/WKBWriter.java
This implementation also supports the Extended WKB
standard. Extended WKB allows writing 3-dimensional coordinates
and including the geometry SRID value.
The presence of 3D coordinates is signified
by setting the high bit of the wkbType word.
The presence of an SRID is signified
by setting the third bit of the wkbType word.
EWKB format is upward compatible with the original SFS WKB format.
Your WKB is of the OGC variant which is defined in the OGC document http://portal.opengeospatial.org/files/?artifact_id=25355
JTS don't understand the four-digit geometry type codes. This mail thread gives some more information https://lists.osgeo.org/pipermail/geos-devel/2013-December/006757.html.
JTS Topology suite supports 3D data but in EWKB format. ISO WKB is not supported. If just so happens that you are using postgis, it supports EWKB. ST_GeomFromEWKB <-> ST_AsEWKB
Also if you are writing your EWKB with WKBWriter, don't forget to specify output dimmensions :
WKBWriter wkbw = new WKBWriter(3);
https://trac.osgeo.org/geos/ticket/707
https://postgis.net/docs/reference.html
I have a List<Coordinate> which represents a route.
I want to simplify it using JTS.
I saw few method but I wasn't sure which one will fit my needs the best:
1) how can I convert my coordinate to geometry (line?)
TopologyPreservingSimplifier(Geometry inputGeom)
void setDistanceTolerance(double distanceTolerance)
Geometry getResultGeometry()
2)
DouglasPeuckerLineSimplifier(Coordinate[] pts)
void setDistanceTolerance(double distanceTolerance)
Coordinate[] simplify()
static Coordinate[] simplify(Coordinate[] pts, double distanceTolerance)
3) maybe this?
TopologyPreservingSimplifier.simplify(geom, threshold-in-degrees-that-depends-on-the-length);
To simplify a line you first have to have one. So first build your LineString using the createLineString(Coordinate[]) method of a GeometryFactory instance.
Then just use the DouglasPeuckerSimplifier (you don't need to preserve topology for just one line, the start and end points are all the topology there and they won't be changed). You will have to cast the result to a LineString again if you want to use it as such later on. And you will have to choose an appropriate tolerance.
LineString lss = (LineString) DouglasPeuckerSimplifier.simplify(ls, tolerance);
I have a string representation of a point in a given CRS (namely, EPSG:3035), such as "N10160E21266". I'd like to parse it using GeoTools to create a DirectPosition, or any another X/Y representation (in order to transform it from a CRS to another CRS; I have a MathTransform at hand).
Is there a parse method already implemented somewhere in GeoTools?
It's probably not difficult to create a custom one, but this may be error-prone and I'm not a GIS specialist (how to properly handle north/easting etc).
That is not a well known representation so there will be no standard parser. It shouldn't be too hard to write one that returns a DirectPosition or a JTS.Point.
The only geographic issue that you need to bear in mind is that epsg:3035 stores east as X and north as Y (which in this case is what you'd expect). You'll need to check the axis order of your target projection.
I am using the JTS Topology Suite to process some geometry in my application. As a starting point I instantiate a reader:
WKTReader reader = new WKTReader();
Then, using the reader I check for polygon records:
Geometry poly = reader.read(res.getString("GEOM"));
Geometry point = reader.read("Point(" + res.getString("LON")
+ " " + res.getString("LAT") + ")");
boolean inside = poly.contains(point);
The problem being that it takes too long to find my polygons this way. So I need another option for this process. Are there any alternatives to using WTKReader for this process? Thanks.
P.S: I am using a MYSQL DB.
First, you could try to use standard java serialization/deserialization for your polygon.
Next, storing LON and LAT as STRINGs is not very effective, probably you should try numeric types.
We could get you more help if you provide the results of profiling - what consumes most of the time. However I suspect that operations with DB are the slowest one, so you may try fetch all entries once at a time, add cacheing.
Another option is to store in DB the bounding box points for every GEOM, and fetch in SQL query only that points, that belong to bounding box, and perform exact 'contains' check on java side.