/* * 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.Envelope; 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.Font; import org.geotoolkit.data.mapinfo.mif.style.LabelLine; 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.List; import java.util.Scanner; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.sis.feature.DefaultAttributeType; import org.apache.sis.feature.FeatureExt; import org.apache.sis.util.ArgumentChecks; 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.LabelLine.LABEL; import org.geotoolkit.geometry.jts.JTS; /** * A class which manage MIF text geometry. * * @author Alexis Manin (Geomatys) * Date : 26/02/13 */ public class MIFTextBuilder extends MIFRectangleBuilder { public static final GenericName NAME = NamesExt.create("ENVELOPE"); public static final GenericName TEXT_NAME = NamesExt.create("TEXT"); public static final GenericName SPACING_NAME = NamesExt.create("SPACING"); public static final GenericName JUSTIFY_NAME = NamesExt.create("JUSTIFY"); public static final GenericName ANGLE_NAME = NamesExt.create("ANGLE"); public static final AttributeType TEXT_DESCRIPTOR = new DefaultAttributeType(Collections.singletonMap("name", TEXT_NAME), String.class, 1, 1, null); public static final AttributeType FONT_DESCRIPTOR = new DefaultAttributeType(Collections.singletonMap("name", Font.NAME), String.class, 1, 1, null); public static final AttributeType SPACING_DESCRIPTOR = new DefaultAttributeType(Collections.singletonMap("name", SPACING_NAME), Float.class, 1, 1, 1f); public static final AttributeType JUSTIFY_DESCRIPTOR = new DefaultAttributeType(Collections.singletonMap("name", JUSTIFY_NAME), String.class, 1, 1, "Left"); public static final AttributeType ANGLE_DESCRIPTOR = new DefaultAttributeType(Collections.singletonMap("name", ANGLE_NAME), Double.class, 1, 1, null); public static final Pattern SPACING_PATTERN = Pattern.compile(SPACING_NAME.tip().toString()+"\\s*\\([^\\)]+\\)", Pattern.CASE_INSENSITIVE); public static final Pattern JUSTIFY_PATTERN = Pattern.compile(JUSTIFY_NAME.tip().toString(), Pattern.CASE_INSENSITIVE); public static final Pattern ANGLE_PATTERN = Pattern.compile(ANGLE_NAME.tip().toString()+"\\s*\\([^\\)]+\\)", Pattern.CASE_INSENSITIVE); /** * Build a feature describing a MIF point geometry. That assume that user gave a {@link Scanner} which is placed on * a TEXT tag. * * @param scanner The scanner to use for data reading (must be pointing on a mif POINT element). * @param toFill * @param toApply * @throws DataStoreException If there's a problem while parsing stream of the given Scanner. */ @Override public void buildGeometry(Scanner scanner, Feature toFill, MathTransform toApply) throws DataStoreException { try { String geomText = scanner.next("\\w+"); if (TEXT_NAME.tip().toString().equalsIgnoreCase(geomText)) { geomText = scanner.next("\\w+"); } toFill.setPropertyValue(TEXT_NAME.toString(),geomText); final double[] pts = new double[4]; for (int i = 0; i < pts.length; i++) { pts[i] = Double.parseDouble(scanner.next(ProjectionUtils.DOUBLE_PATTERN)); } final CoordinateSequence seq; if (toApply != null) { try { double[] afterT = new double[4]; toApply.transform(pts, 0, afterT, 0, 2); seq = new PackedCoordinateSequence.Double(afterT, 2); } catch (Exception e) { throw new DataStoreException("Unable to transform geometry", e); } } else { seq = new PackedCoordinateSequence.Double(pts, 2); } final Envelope env = new Envelope(seq.getCoordinate(0), seq.getCoordinate(1)); toFill.setPropertyValue(MIFUtils.findGeometryProperty(toFill.getType()).getName().tip().toString(), JTS.toGeometry(env)); } catch (Exception e) { throw new DataStoreException("Unable to build envelope from given data", e); } /** * Add a management for the text options. */ if (scanner.hasNext(Font.PATTERN)) { String args = scanner.next()+scanner.next(Font.PATTERN); String[] argsTab = args.substring(args.indexOf('(')+1, args.length()-1) .replaceAll("[^\\w^,]+", "") .split(","); if (argsTab.length < 3) { LOGGER.log(Level.WARNING, "A FONT clause have been found, but can't be read (bad syntax ?). Ignore it."); } else { final String fName = argsTab[0]; final int fStyle = Integer.decode(argsTab[1]); final int fColor = Integer.decode(argsTab[2]); Font font = new Font(fName, fStyle, fColor); if(argsTab.length > 3) { final int background = Integer.decode(argsTab[3]); font.setBackColorCode(background); } toFill.setPropertyValue(Font.NAME.toString(),font); } } if (scanner.hasNext(SPACING_PATTERN)) { String spacing = scanner.next(SPACING_PATTERN); Matcher match = ProjectionUtils.DOUBLE_PATTERN.matcher(spacing); if(match.find()) { toFill.setPropertyValue(SPACING_NAME.toString(),Double.parseDouble(match.group())); } } if (scanner.hasNext(JUSTIFY_PATTERN)) { String spacing = scanner.next(JUSTIFY_PATTERN); toFill.setPropertyValue(SPACING_NAME.toString(),scanner.next()); } if (scanner.hasNext(ANGLE_PATTERN)) { String spacing = scanner.next(ANGLE_PATTERN); Matcher match = ProjectionUtils.DOUBLE_PATTERN.matcher(spacing); if(match.find()) { toFill.setPropertyValue(ANGLE_NAME.toString(),Double.parseDouble(match.group())); } } if(scanner.hasNext(LabelLine.PATTERN)) { String label = scanner.next(LabelLine.PATTERN); String type = label.contains("?i(arrow)")? "arrow" : "simple"; Double x = null, y = null; Matcher match = ProjectionUtils.DOUBLE_PATTERN.matcher(label); if(match.find()) { x = Double.parseDouble(match.group()); } if(match.find()) { y = Double.parseDouble(match.group()); } LabelLine labelLine = new LabelLine(type, new Coordinate(x, y)); toFill.setPropertyValue(LabelLine.NAME.toString(),labelLine); } } @Override public String toMIFSyntax(Feature source) throws DataStoreException { ArgumentChecks.ensureNonNull("Source feature", source); if(!FeatureExt.hasAGeometry(source.getType())) { throw new DataStoreException("Input feature does not contain any geometry."); } final Object text = MIFUtils.getPropertySafe(source, TEXT_NAME.toString()); if (text == null) { throw new DataStoreException("Not enough information to build an arc (missing text)."); } StringBuilder builder = new StringBuilder(TEXT_NAME.tip().toString()).append(' '); builder.append(' ').append(text).append('\n'); appendMIFEnvelope(builder, MIFUtils.getGeometryValue(source)); builder.append('\n'); Object styleData = MIFUtils.getPropertySafe(source, Font.NAME.toString()); if (styleData instanceof Font) builder.append(styleData); styleData = MIFUtils.getPropertySafe(source, SPACING_NAME.toString()); if(styleData != null) { builder.append("SPACING (").append(styleData).append(")\n"); } styleData = MIFUtils.getPropertySafe(source, JUSTIFY_NAME.toString()); if(styleData != null) { builder.append("JUSTIFY (").append(styleData).append(")\n"); } styleData = MIFUtils.getPropertySafe(source, ANGLE_NAME.toString()); if(styleData != null) { builder.append("ANGLE ").append(styleData).append('\n'); } styleData = MIFUtils.getPropertySafe(source, LabelLine.NAME.toString()); if(styleData != null) { builder.append(styleData).append('\n'); } return builder.toString(); } @Override public GenericName getName() { return NAME; } @Override protected List<AttributeType> getAttributes() { final List<AttributeType> descList = new ArrayList<AttributeType>(5); descList.add(TEXT_DESCRIPTOR); descList.add(FONT_DESCRIPTOR); descList.add(SPACING_DESCRIPTOR); descList.add(ANGLE_DESCRIPTOR); descList.add(LABEL); return descList; } }