/* * 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.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.data.mapinfo.ProjectionUtils; import org.geotoolkit.data.mapinfo.mif.style.Pen; import org.geotoolkit.util.NamesExt; import org.opengis.util.GenericName; import org.opengis.referencing.operation.MathTransform; import java.util.ArrayList; import java.util.Collections; import java.util.InputMismatchException; import java.util.List; import java.util.Scanner; import java.util.logging.Level; import java.util.regex.Pattern; import org.apache.sis.feature.DefaultAttributeType; import org.geotoolkit.data.mapinfo.mif.MIFUtils; import org.opengis.feature.AttributeType; import org.opengis.feature.Feature; import static org.geotoolkit.data.mapinfo.mif.style.Pen.PEN; /** * Util class to build a feature from Multi line object of a MIF file. * * @author Alexis Manin (Geomatys) * Date : 26/02/13 */ public class MIFPolyLineBuilder extends MIFGeometryBuilder { public static final GenericName NAME = NamesExt.create("PLINE"); public static final GenericName SMOOTH_NAME = NamesExt.create("SMOOTH"); private static final AttributeType SMOOTH = new DefaultAttributeType(Collections.singletonMap("name", SMOOTH_NAME), Boolean.class, 1, 1, null); /** * {@inheritDoc} * * * * @param scanner the Scanner to use for geometry parsing (should be placed on the beginning of the geometry). * @param toFill * @param toApply * @return * @throws DataStoreException */ @Override public void buildGeometry(Scanner scanner, Feature toFill, MathTransform toApply) throws DataStoreException { int numLines = 1; try { Pattern multiple = Pattern.compile("multiple", Pattern.CASE_INSENSITIVE); if(scanner.hasNext(multiple)) { scanner.next(); numLines = Integer.decode(scanner.next("\\d+")); } final LineString[] lineTab = new LineString[numLines]; for(int lineCount = 0 ; lineCount < numLines ; lineCount++) { // We put a x2 factor as we work in 2 dimensions. final int numCoord = Integer.decode(scanner.next("\\d+"))*2; final double[] linePts = new double[numCoord]; for(int coordCount = 0 ; coordCount < numCoord; coordCount++) { linePts[coordCount] = Double.parseDouble(scanner.next(ProjectionUtils.DOUBLE_PATTERN)); } final CoordinateSequence seq; if(toApply != null) { try { double[] afterT = new double[numCoord]; toApply.transform(linePts, 0, afterT, 0, numCoord/2); seq = new PackedCoordinateSequence.Double(afterT, 2); } catch (Exception e) { throw new DataStoreException("Unable to transform geometry", e); } } else { seq = new PackedCoordinateSequence.Double(linePts, 2); } lineTab[lineCount] = GEOMETRY_FACTORY.createLineString(seq); } toFill.setPropertyValue(MIFUtils.findGeometryProperty(toFill.getType()).getName().tip().toString(), GEOMETRY_FACTORY.createMultiLineString(lineTab)); } catch (InputMismatchException ex) { throw new DataStoreException("Line is not properly defined : not enough points found.", ex); } if(scanner.hasNext(Pen.PEN_PATTERN) && toFill.getType().getProperties(true).contains(PEN)) { String args = scanner.next()+scanner.nextLine(); String[] argsTab = args.substring(args.indexOf('(')+1, args.length()-1) .replaceAll("[^\\d^,]+", "") .split(","); if (argsTab.length < 3) { LOGGER.log(Level.WARNING, "A PEN tag have been found, but can't be read (bad syntax ?). Ignore style."); } else { final int width = Integer.decode(argsTab[0]); final int pattern = Integer.decode(argsTab[1]); final int color = Integer.decode(argsTab[2]); Pen pen = new Pen(width, pattern, color); toFill.setPropertyValue(Pen.NAME.toString(),pen); } } if(scanner.hasNext(Pattern.compile(SMOOTH_NAME.tip().toString(), Pattern.CASE_INSENSITIVE))) { toFill.setPropertyValue(SMOOTH_NAME.toString(),Boolean.TRUE); } } /** * {@inheritDoc} */ @Override public String toMIFSyntax(Feature geometry) throws DataStoreException { super.toMIFSyntax(geometry); StringBuilder builder = new StringBuilder(NAME.tip().toString()); MultiLineString polyLine = null; Object value = MIFUtils.getGeometryValue(geometry); if(value instanceof LineString) { polyLine = GEOMETRY_FACTORY.createMultiLineString(new LineString[]{(LineString)value}); } else { polyLine = (MultiLineString) value; if(polyLine.getNumGeometries() > 1) { builder.append("MULTIPLE ").append(polyLine.getNumGeometries()); } } builder.append('\n'); for(int i = 0 ; i < polyLine.getNumGeometries() ; i++) { LineString line = (LineString) polyLine.getGeometryN(i); builder.append(line.getNumPoints()).append('\n'); for(Coordinate pt : line.getCoordinates()) { builder.append(pt.x).append(' ').append(pt.y).append('\n'); } } final Object pen = MIFUtils.getPropertySafe(geometry, Pen.NAME.toString()); if (pen instanceof Pen) { builder.append(pen).append('\n'); } final Object smooth = MIFUtils.getPropertySafe(geometry, SMOOTH_NAME.toString()); if (Boolean.TRUE.equals(smooth)) { builder.append(SMOOTH_NAME.tip().toString()).append('\n'); } return builder.toString(); } @Override public Class getGeometryBinding() { return MultiLineString.class; } @Override public Class[] getPossibleBindings() { return new Class[]{LineString.class, MultiLineString.class}; } @Override public GenericName getName() { return NAME; } @Override protected List<AttributeType> getAttributes() { final List<AttributeType> descList = new ArrayList<AttributeType>(2); descList.add(PEN); descList.add(SMOOTH); return descList; } }