/*- * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * * This file is part of CityDoctor2. * * CityDoctor2 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, either version 3 of the License, or * (at your option) any later version. * * CityDoctor2 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. * * You should have received a copy of the GNU Lesser General Public License * along with CityDoctor2. If not, see . */ package de.hft.stuttgart.citydoctor2.mapper.citygml3; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.ProjCoordinate; import org.xmlobjects.gml.model.geometry.primitives.AbstractRing; import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty; import org.xmlobjects.gml.model.geometry.primitives.Polygon; import org.xmlobjects.gml.model.geometry.primitives.Ring; import org.xmlobjects.gml.visitor.GeometryWalker; import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.GmlId; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType; import de.hft.stuttgart.citydoctor2.datastructure.Vertex; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.utils.Localization; public class Citygml3GeometryMapper extends GeometryWalker { private static final Logger logger = LogManager.getLogger(Citygml3GeometryMapper.class); private List polygons = new ArrayList<>(); private LinearRing currentRing = null; private ParserConfiguration config; private ProjCoordinate p1 = new ProjCoordinate(); private ProjCoordinate p2 = new ProjCoordinate(); private Map vertexMap; public Citygml3GeometryMapper(ParserConfiguration config, Map vertices) { this.config = config; this.vertexMap = vertices; } @Override public void visit(Polygon polygon) { parsePolygon(polygon.getId(), polygon.getExterior(), polygon.getInterior()); if (polygon.getExterior() == null) { System.out.println("No exterior: " + polygon.getId()); } } private void parsePolygon(String id, AbstractRingProperty exterior, List interior) { if (exterior == null || exterior.getObject() == null) { if (logger.isWarnEnabled()) { logger.warn(Localization.getText("GeometryMapper.emptyPolygon")); } return; } ConcretePolygon cdPoly = new ConcretePolygon(); polygons.add(cdPoly); if (id != null) { cdPoly.setGmlId(new GmlId(id)); } currentRing = new LinearRing(LinearRingType.EXTERIOR); exterior.getObject().accept(this); cdPoly.setExteriorRing(currentRing); for (AbstractRingProperty interiorGmlRing : interior) { AbstractRing gmlRing = interiorGmlRing.getObject(); if (gmlRing == null) { continue; } currentRing = new LinearRing(LinearRingType.INTERIOR); gmlRing.accept(this); cdPoly.addInteriorRing(currentRing); } } @Override public void visit(org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlRing) { if (gmlRing.getSrsDimension() != null && gmlRing.getSrsDimension() != 3) { logger.warn("Cannot handle geometry with srsDimension not 3"); return; } if (gmlRing.getId() != null) { currentRing.setGmlId(new GmlId(gmlRing.getId())); } List coordinates = gmlRing.toCoordinateList3D(); handleCoordinateList(coordinates); } @Override public void visit(Ring ring) { if (ring.getSrsDimension() != null && ring.getSrsDimension() != 3) { logger.warn("Cannot handle geometry with srsDimension not 3"); return; } if (ring.getId() != null) { currentRing.setGmlId(new GmlId(ring.getId())); } List coordinates = ring.toCoordinateList3D(); handleCoordinateList(coordinates); } private void handleCoordinateList(List coordinates) { if (coordinates.size() % 3 != 0) { String id; if (currentRing.hasExistingGmlId()) { id = currentRing.getGmlId().getGmlString(); } else { id = ""; } logger.warn("The number of coordinates for linear ring {} do not result in fully 3D points", id); } for (int i = 0; i < coordinates.size(); i = i + 3) { double x = coordinates.get(i + 0); double y = coordinates.get(i + 1); double z = coordinates.get(i + 2); createVertex(x, y, z); } } private void createVertex(double x, double y, double z) { // transform into utm, if available BasicCoordinateTransform trans = config.getTargetTransform(); if (trans != null) { p1.setValue(x, y); trans.transform(p1, p2); x = p2.x; y = p2.y; z = z / config.getFromMetres(); } x = round(x, config.getNumberOfRoundingPlaces()); y = round(y, config.getNumberOfRoundingPlaces()); z = round(z, config.getNumberOfRoundingPlaces()); Vertex v = new Vertex(x, y, z); Vertex duplicate = vertexMap.get(v); if (duplicate == null) { vertexMap.put(v, v); } else { v = duplicate; } currentRing.addVertex(v); } private double round(double value, int places) { if (places < 0) { throw new IllegalArgumentException(); } BigDecimal bd = BigDecimal.valueOf(value); bd = bd.setScale(places, RoundingMode.HALF_UP); return bd.doubleValue(); } public List getPolygons() { return polygons; } }