/* * GeoTools - OpenSource mapping toolkit * http://geotools.org * (C) 2005-2006, GeoTools Project Managment Committee (PMC) * * 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.geotools.data.edigeo; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.data.DataSourceException; import org.geotools.data.edigeo.EdigeoFeatureReader.Visitor; import org.opengis.feature.IllegalAttributeException; /** * * @author mcoudert * * * * @source $URL$ */ public class EdigeoVEC { private File vecFile = null; // Edigeo VEC extension file private static final String VECExtension = "vec"; // Field separator private static final String DS = ":"; private static final String VS = ";"; // Geo Primitives private static final String nodeDesc = "PNO"; private static final String faceDesc = "PFE"; private static final String arcDesc = "PAR"; // Descriptor header private static final String objIdDesc = "RIDSA"; private static final String lnkDesc = "FTPCP"; private static final String typDesc = "RTYSA"; private static final String nbNodeDesc = "PTCSN"; private static final String nbAttDesc = "ATCSN"; private static final String idAttDesc = "ATPCP"; private static final String valAttrDesc = "ATVS"; private static final String coordDesc = "CORCC"; private static final String POINT = "POINT"; private static final String LINESTRING = "LINESTRING"; private static final String POLYGON = "POLYGON"; private static final String MULTIPOLYGON = "MULTIPOLYGON"; protected static String geoType = null; private int nbObjs = 0; private int nbarc = 0; private int nbPoint = 0; protected boolean topo = false; private Logger logger = Logger.getLogger("org.geotools.data.edigeo"); /** * <p> * This constructor opens an existing THF file * </p> * * @param path Full pathName of the thf file, can be specified without the * .thf extension * * @throws IOException If the specified thf file could not be opened */ public EdigeoVEC(String path) throws IOException { super(); vecFile = EdigeoFileFactory.setFile(path, VECExtension, true); } /** * * @param obj */ public void readVECFile(String obj, Visitor visitor) throws IOException, IllegalAttributeException { EdigeoParser vecParser = new EdigeoParser(vecFile); String idObj = null; String buffer = ""; String att = ""; String value = ""; if (obj.equals("PARCELLE_id")) { topo = true; } geoType = EdigeoDataStore.scdObj.get(obj).get("type").toUpperCase(); if (logger.isLoggable(Level.INFO)) { logger.info("Creating Edigeo Datastore, please wait, it may take a few minutes..."); } while (vecParser.readLine()) { if (vecParser.line.contains(VS + obj) && buffer.contains(objIdDesc)) { // we've got a feature HashMap<String, String> atts = new HashMap<String, String>(); idObj = getValue(buffer, objIdDesc); List<Coordinate[]> geoms = getRelation(idObj); nbObjs++; while (vecParser.readLine()) { if (vecParser.line.contains(nbAttDesc)) { int nbatt = Integer.parseInt(vecParser.getValue(nbAttDesc)); for (int i = 0; i < nbatt; i++) { // String charsetBuffer = ""; while (vecParser.readLine()) { if (vecParser.line.contains(idAttDesc)) { att = vecParser.getValue(idAttDesc); att = att.substring(att.lastIndexOf(";") + 1); continue; } if (vecParser.line.contains(valAttrDesc)) { // if (false && charsetBuffer.equals("TEXT 06:8859-1")) { // CharsetDecoder dec = Charset.forName("ISO-8859-1").newDecoder(); // dec.onMalformedInput(CodingErrorAction.REPORT); // dec.onUnmappableCharacter(CodingErrorAction.REPORT); // CharBuffer cb = dec.decode(ByteBuffer.wrap(vecParser.getValue("ATVS").getBytes())); // value = cb.toString(); // value = new String(vecParser.getValue("ATVS").getBytes("ISO-8859-1")); // } else { // value = vecParser.getValue("ATVS"); // } value = vecParser.getValue(valAttrDesc); value = getPrecodedValue(att, value); atts.put(att, value); break; } // charsetBuffer = vecParser.line; } } break; } } // Create the feature Object[] values = null; int nbAtt; // with attributes if exist if (!EdigeoDataStore.ftAtt.isEmpty()) { int cpt = 0; nbAtt = EdigeoDataStore.ftAtt.size(); values = new Object[nbAtt + 1]; Iterator<String> it = EdigeoDataStore.ftAtt.keySet().iterator(); while (it.hasNext()) { String key = it.next(); if (atts.containsKey(key)) { values[cpt] = atts.get(key); } else { values[cpt] = null; } cpt++; } } else { values = new Object[1]; nbAtt = 0; } Geometry geom = null; if (!geoms.isEmpty()) { geom = createGeometry(geoms, idObj); values[nbAtt] = geom; visitor.visit(values, idObj); } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Unable to find geometry relation for FID#" + idObj); } } } buffer = vecParser.line; } vecParser.close(); } /** * * @param id * @throws java.io.FileNotFoundException */ protected List<Coordinate[]> getRelation(String id) throws IOException { EdigeoParser parser = new EdigeoParser(vecFile); String lnk = ""; String buffern1 = ""; String otherLnk = ""; List<Coordinate[]> geoms = new LinkedList<Coordinate[]>(); while (parser.readLine()) { // Parse all link description for element defined by its id if (parser.line.contains(VS + id) || buffern1.contains(VS + id)) { if (buffern1.contains(lnkDesc) && parser.line.contains(lnkDesc)) { if (buffern1.contains(VS + id)) { lnk = new String(parser.line); } else { lnk = new String(buffern1); } // try to look for other link description (lnkDesc) while (parser.readLine()) { if (parser.line.contains(lnkDesc)) { otherLnk = getValue(parser.line,lnkDesc); List<Coordinate[]> test = getType(otherLnk.substring(otherLnk.lastIndexOf(VS) + 1)); geoms.addAll(test); } else break; } lnk = getValue(lnk, lnkDesc); List<Coordinate[]> list = getType(lnk.substring(lnk.lastIndexOf(VS) + 1)); if (!list.isEmpty()) { if (!topo) { geoms.addAll(list); break; } else { geoms.addAll(list); } } } } buffern1 = new String(parser.line); } parser.close(); return geoms; } /** * Gets value of the specified descriptor * * @param target Descriptor * @return String */ public String getValue(String line, String target) { int index = line.indexOf(target); int nbchar = Integer.parseInt(line.substring(index + 5, index + 7)); // Avoid index out of range exception if (index + nbchar + 8 > line.length()) { return line.substring(index + 8, line.length()); } String value = line.substring(index + 8, index + nbchar + 8); return value; } /** * * @param id * @param FID * @return List<Coordinate[]> * @throws java.io.IOException */ protected List<Coordinate[]> getType(String id) throws IOException { EdigeoParser parser = new EdigeoParser(vecFile); String buffern1 = ""; String type = ""; List<Coordinate[]> geoms = new LinkedList<Coordinate[]>(); while (parser.readLine()) { if (parser.line.contains(DS + id)) { type = getValue(buffern1, typDesc); if (type.equals(faceDesc)) { geoms = getRelation(id); break; } else if (type.equals(arcDesc)) { geoms.add(getCoordinates(parser, false)); nbarc++; } else if (type.equals(nodeDesc)) { geoms.add(getCoordinates(parser, true)); nbPoint++; } break; } buffern1 = new String(parser.line); } parser.close(); return geoms; } /** * * @param parser * @param isNode * @return Coordinate[] */ private Coordinate[] getCoordinates(EdigeoParser parser, boolean isNode) { Coordinate[] coords = null; while (parser.readLine()) { if (isNode) { if (parser.line.contains(coordDesc)) { coords = new Coordinate[1]; String xy = getXY(parser.line); coords[0] = parseCoordinate(xy); break; } } else { if (parser.line.contains(nbNodeDesc)) { int size = Integer.parseInt(getValue(parser.line, nbNodeDesc)); coords = new Coordinate[size]; for (int i = 0; i < size; i++) { parser.readLine(); if (parser.line.contains(coordDesc)) { String xy = getXY(parser.line); coords[i] = parseCoordinate(xy); } } break; } } } return coords; } /** * * @param coord * @return Coordinate */ protected Coordinate parseCoordinate(String coord) { double x = Double.parseDouble(coord.substring(0, coord.indexOf(" "))); double y = Double.parseDouble(coord.substring(coord.indexOf(" "))); Coordinate coordinate = new Coordinate(x, y); return coordinate; } /** * * @param line * @return */ protected String getXY(String line) { String coord = ""; coord = getValue(line, coordDesc); return coord.replace("+", "").replaceAll(";", " "); } /** * Get precoded attribute values * @param value * @return */ private String getPrecodedValue(String attribut, String value) { if (EdigeoDataStore.ftAtt.get(attribut).get("precoded").equals("true")) { value = EdigeoDataStore.ftAtt.get(attribut).get(value); } return value; } /** * Creates geometry from a list of Coordinate array. * @param geo * @param FID * @return * @throws org.geotools.data.DataSourceException */ protected Geometry createGeometry(List<Coordinate[]> coords, String FID) throws DataSourceException { GeometryFactory geomFact = new GeometryFactory(); Geometry geom = null; LinearRing shell = null; LinearRing[] holes = null; Polygon[] polys = null; if (geoType.equals(POINT)) { geom = (Geometry) geomFact.createPoint(coords.get(0)[0]); } else if (geoType.equals(LINESTRING)) { geom = (Geometry) geomFact.createLineString(coords.get(0)); } else if (geoType.equals(POLYGON) && !topo) { // Edigeo polygon objects are handled as polygon with holes shell = geomFact.createLinearRing(coords.get(0)); if (coords.size()>1) { // handle polygons with holes holes = new LinearRing[coords.size() - 1]; for (int i = 1; i < coords.size(); i++) { holes[i - 1] = geomFact.createLinearRing(coords.get(i)); } } geom = (Geometry) geomFact.createPolygon(shell, holes); } else if (geoType.equals(POLYGON) && topo) { // Constructs polygon for Edigeo topologic object (ie PARCELLE_id) List<Coordinate[]> polygonCoords = getPolygonCoordinates(coords); shell = geomFact.createLinearRing(polygonCoords.get(0)); holes = new LinearRing[polygonCoords.size() - 1]; for (int i = 1; i < polygonCoords.size(); i++) { holes[i - 1] = geomFact.createLinearRing(polygonCoords.get(i)); } geom = (Geometry) geomFact.createPolygon(shell, holes); } else if (geoType.equals(MULTIPOLYGON)) { // Constructs multipolygon for Edigeo object (ie SECTION_id) polys = new Polygon[coords.size()]; Iterator<Coordinate[]> it = coords.iterator(); int cpt = 0; while (it.hasNext()) { shell = geomFact.createLinearRing(it.next()); polys[cpt] = geomFact.createPolygon(shell, holes); cpt++; } geom = geomFact.createMultiPolygon(polys); } else { if (logger.isLoggable(Level.SEVERE)) { logger.severe("Can't handle the type " + geoType + " for fid#" + FID); } throw new DataSourceException("Can't handle the type " + geoType + " for fid#" + FID); } return geom; } /** * * @param coordList * @param FID * @return */ private List<Coordinate[]> getPolygonCoordinates(List<Coordinate[]> coordList) { List<Coordinate[]> polygonCoordList = new LinkedList<Coordinate[]>(); while (coordList.size() > 0) { polygonCoordList.add(getRingCoordinates(coordList)); } return polygonCoordList; } /** * * @param listCoord * @return */ private Coordinate[] getRingCoordinates(List<Coordinate[]> listCoord) { int bufferSize = 0; Iterator<Coordinate[]> it = listCoord.iterator(); Vector<Coordinate> aggCoords = new Vector<Coordinate>(Arrays.asList(it.next())); it.remove(); it = null; while (listCoord.size() > 0) { Iterator<Coordinate[]> iter = listCoord.iterator(); while (iter.hasNext()) { Coordinate[] currentCoordArray = iter.next(); if (aggCoords.get(aggCoords.size() - 1).equals(currentCoordArray[0])) { for (int i = 1; i < currentCoordArray.length; i++) { aggCoords.add(currentCoordArray[i]); } iter.remove(); } else if (aggCoords.get(aggCoords.size() - 1).equals(currentCoordArray[currentCoordArray.length - 1])) { for (int i = currentCoordArray.length - 2; i >= 0; i--) { aggCoords.add(currentCoordArray[i]); } iter.remove(); } } iter = null; if (bufferSize == listCoord.size() && bufferSize != 0) { break; } bufferSize = listCoord.size(); } return aggCoords.toArray(new Coordinate[aggCoords.size()]); } }