Friday, 27 November 2015

qgis - Comparing two shapefiles(layers) and display the differences in features in MapContent object in GeoTools


I am working with GeoTools libraries to implement GIS features. Here, I have two different shapefiles and I want to generate a new separate layer containing the differences between the two shape files. This new layer should show the extra features which are there in one of the two input shp files.


The image attached shows how it is done in QGIS


It generates a new layer showing the differences between polygon2.shp and polygon1.shp.



Are there any specific methods in the GeoTools libraries which can capture the differences if we provide the two layers of shapefiles?



Answer



As I said in the comments this is a fairly simple algorithm once you work out what the QGIS code is doing.



  1. Loop through the first feature collection

  2. Find any geometries in the second collection that intersect with the current feature

  3. Union those together (if there are more than one) and subtract (difference) that union from the first feature

  4. Save the results.


GeoTools actually makes this a fair bit easier than QGIS as you don't need to create your own indexes etc.



public static SimpleFeatureCollection difference(SimpleFeatureCollection collA, SimpleFeatureCollection collB) {
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(collA.getSchema());
List ret = new ArrayList<>();
try (SimpleFeatureIterator itr = collA.features()) {
while (itr.hasNext()) {
SimpleFeature f = itr.next();
Geometry geom = (Geometry) f.getDefaultGeometry();
Filter filter = ff.intersects(ff.property(collB.getSchema().getGeometryDescriptor().getLocalName()),
ff.literal(geom));
SimpleFeatureCollection sub = collB.subCollection(filter);

if (!sub.isEmpty()) {
// union the geometries that overlap
Geometry result = null;
try (SimpleFeatureIterator itr2 = sub.features()) {

while (itr2.hasNext()) {
SimpleFeature f2 = itr2.next();
Geometry geom2 = (Geometry) f2.getDefaultGeometry();
if (result == null) {
result = geom2;

} else {
result = result.union(geom2);
}
}
}
if (result.isValid() && geom.isValid()) {
// calc difference
Geometry g = geom.difference(result);
builder.addAll(f.getAttributes());
String geomName = collA.getSchema().getGeometryDescriptor().getLocalName();

builder.set(geomName, g);
SimpleFeature fout = builder.buildFeature(null);
ret.add(fout);
} else {
if (!result.isValid()) {
System.out.println("Invalid result");
System.out.println(result);
}
if (!geom.isValid()) {
System.out.println("Invalid geom");

System.out.println(geom);
}
}
} else {// no intersection
ret.add(f);
}
}
}
return DataUtilities.collection(ret);


}

Here I've differenced the Natural Earth countries and the lakes layer (Ignore India, it's an invalid polygon and I can't be bothered to fix it):


enter image description here


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...