/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.data.mapinfo.mif.geometry;
import com.vividsolutions.jts.geom.*;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.data.mapinfo.mif.MIFUtils;
import org.geotoolkit.util.NamesExt;
import org.opengis.util.GenericName;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import org.apache.sis.feature.DefaultAttributeType;
import org.apache.sis.feature.DefaultFeatureType;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.opengis.feature.AttributeType;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
/**
* Build features representing MIF Collection geometries.
*
* @author Alexis Manin (Geomatys)
* Date : 27/02/13
*/
public class MIFCollectionBuilder extends MIFGeometryBuilder {
public static final GenericName NAME = NamesExt.create("COLLECTION");
public static final GenericName GEOM_NAME = NamesExt.create("GEOMETRY");
public static final FeatureType EMPTY_TYPE = new DefaultFeatureType(Collections.singletonMap("name", "abstract"), true, null);
private CoordinateReferenceSystem collectionCRS = null;
@Override
public void buildGeometry(Scanner scanner, Feature toFill, MathTransform toApply) throws DataStoreException {
int numGeom = 0;
try {
numGeom = scanner.nextInt();
} catch (Exception e) {
throw new DataStoreException("Number of geometries in Collection is not specified", e);
}
for(int geomCount=0 ; geomCount < numGeom ; geomCount++ ) {
while(scanner.hasNextLine()) {
final MIFUtils.GeometryType enumType = MIFUtils.getGeometryType(scanner.findInLine("\\w+"));
if (enumType != null) {
final FeatureType type = enumType.getBinding(collectionCRS, EMPTY_TYPE);
final Feature currentFeature = type.newInstance();
enumType.readGeometry(scanner, toFill, toApply);
((Collection)toFill.getPropertyValue(GEOM_NAME.toString())).add(currentFeature);
break;
}
}
}
}
@Override
public FeatureType buildType(CoordinateReferenceSystem crs, FeatureType parent) {
collectionCRS = crs;
final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
ftb.setName(NAME);
ftb.setSuperTypes(parent);
ftb.addAssociation(EMPTY_TYPE).setName(NAME).setMinimumOccurs(1).setMaximumOccurs(3);
return ftb.build();
}
@Override
public String toMIFSyntax(Feature feature) throws DataStoreException {
super.toMIFSyntax(feature);
StringBuilder builder = new StringBuilder(NAME.tip().toString()).append(' ');
Object value = MIFUtils.getPropertySafe(feature, GEOM_NAME.toString());
if (value instanceof Feature) {
featureToMIFCollection((Feature) value, builder);
} else if (value instanceof GeometryCollection) {
jtsToMIFCollection((GeometryCollection) value, builder);
} else if ((value = MIFUtils.getGeometryValue(feature)) instanceof GeometryCollection) {
jtsToMIFCollection((GeometryCollection) value, builder);
} else {
throw new DataStoreException("Incompatible geometry type.");
}
return builder.toString();
}
private void jtsToMIFCollection(GeometryCollection source, StringBuilder builder) throws DataStoreException {
final ArrayList<Polygon> polygons = new ArrayList<>();
final ArrayList<LineString> lines = new ArrayList<>();
final ArrayList<Point> points = new ArrayList<>();
sortGeometries(source, polygons, lines, points);
int count = 0;
ArrayList<String> geomsStr = new ArrayList<>();
if(polygons.size() > 0) {
count++;
final MultiPolygon multiPolygon = GEOMETRY_FACTORY.createMultiPolygon(polygons.toArray(new Polygon[polygons.size()]));
final FeatureType type = MIFUtils.GeometryType.REGION.getBinding(collectionCRS, null);
final Feature feature = type.newInstance();
feature.setPropertyValue(MIFUtils.findGeometryProperty(feature.getType()).getName().tip().toString(), multiPolygon);
geomsStr.add(MIFUtils.GeometryType.REGION.toMIFSyntax(feature));
}
if(lines.size() > 0) {
count++;
final MultiLineString multiLine = GEOMETRY_FACTORY.createMultiLineString(lines.toArray(new LineString[lines.size()]));
final FeatureType type = MIFUtils.GeometryType.PLINE.getBinding(collectionCRS, null);
final Feature feature = type.newInstance();
feature.setPropertyValue(MIFUtils.findGeometryProperty(feature.getType()).getName().tip().toString(), multiLine);
geomsStr.add(MIFUtils.GeometryType.PLINE.toMIFSyntax(feature));
}
if(points.size() > 0) {
count++;
final MultiPoint multiPoint = GEOMETRY_FACTORY.createMultiPoint(points.toArray(new Point[points.size()]));
final FeatureType type = MIFUtils.GeometryType.PLINE.getBinding(collectionCRS, null);
final Feature feature = type.newInstance();
feature.setPropertyValue(MIFUtils.findGeometryProperty(feature.getType()).getName().tip().toString(), multiPoint);
geomsStr.add(MIFUtils.GeometryType.PLINE.toMIFSyntax(feature));
}
builder.append(count).append('\n');
for(String mifMulti : geomsStr) {
builder.append(mifMulti).append('\n');
}
}
/**
* MIF defines geometry collection as :
* 0 or 1 region,
* 0 or 1 polyline,
* 0 or 1 multipoint.
* So, we have to parse source geometries and group them per type.
*
* @param source The collection of JTS geometries to create MIF collection with.
* @param polygons list to store region.
* @param lines list to store polyline.
* @param points list to store multipoint.
*/
private void sortGeometries(GeometryCollection source, List<Polygon> polygons, List<LineString> lines, List<Point> points) {
for(int i = 0 ; i < source.getNumGeometries() ; i++) {
final Geometry geom = source.getGeometryN(i);
if(geom instanceof Polygon) {
polygons.add((Polygon) geom);
} else if(geom instanceof LineString) {
lines.add((LineString) geom);
} else if(geom instanceof Point) {
points.add((Point) geom);
} else if(geom instanceof GeometryCollection) {
sortGeometries((GeometryCollection) geom, polygons, lines, points);
}
}
}
private void featureToMIFCollection(Feature source, StringBuilder builder) {
}
@Override
public Class getGeometryBinding() {
return Feature.class;
}
@Override
public Class[] getPossibleBindings() {
return new Class[]{Feature.class, GeometryCollection.class};
}
@Override
public GenericName getName() {
return NAME;
}
@Override
protected List<AttributeType> getAttributes() {
final AttributeType attType = new DefaultAttributeType(Collections.singletonMap("name", NAME), Feature.class, 1, 3, null);
return Collections.singletonList(attType);
}
}