/*-
* 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.utils;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.factory.DimensionMismatchException;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractSurface;
import org.citygml4j.model.gml.geometry.primitives.Exterior;
import org.citygml4j.model.gml.geometry.primitives.Interior;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/**
* Utility class dedicated to create CityGML4j datastructures.
*
* @author Matthias Betz
*
*/
public final class CityGmlUtils {
private CityGmlUtils() {
// util class
}
public static org.citygml4j.model.gml.geometry.primitives.Polygon createGmlPolygon(GMLGeometryFactory factory,
Polygon cdPoly, ParserConfiguration config) {
if (cdPoly.getExteriorRing() == null) {
return null;
}
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = new org.citygml4j.model.gml.geometry.primitives.Polygon();
try {
// exterior ring
LinearRing extLr = cdPoly.getExteriorRing();
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new Exterior(gmlLr));
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) {
gmlLr = createGmlRing(factory, config, lr);
gmlPoly.addInterior(new Interior(gmlLr));
}
gmlPoly.setId(cdPoly.getGmlId().getGmlString());
return gmlPoly;
} catch (DimensionMismatchException e) {
// cannot happen as every vertex has 3 coordinates
return null;
}
}
public static org.citygml4j.model.gml.geometry.primitives.LinearRing createGmlRing(GMLGeometryFactory factory,
ParserConfiguration config, LinearRing lr) throws DimensionMismatchException {
ProjCoordinate p1 = new ProjCoordinate();
ProjCoordinate p2 = new ProjCoordinate();
List ringValues = new ArrayList<>();
BasicCoordinateTransform trans = config.getOriginalTransform();
for (Vertex v : lr.getVertices()) {
double x = v.getX();
double y = v.getY();
double z = v.getZ();
if (trans != null) {
p1.x = x;
p1.y = y;
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z * config.getFromMetres();
}
ringValues.add(x);
ringValues.add(y);
ringValues.add(z);
}
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
gmlLr.setId(lr.getGmlId().getGmlString());
return gmlLr;
}
public static Solid createSolid(Geometry geom, GMLGeometryFactory factory, ParserConfiguration config) {
if (geom.getType() != GeometryType.SOLID) {
throw new IllegalArgumentException("Only solids are allowed");
}
List surfaceMember = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaceMember.add(new SurfaceProperty(gmlPoly));
}
} else {
// add reference to polygon
surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
}
}
if (surfaceMember.isEmpty()) {
return null;
}
CompositeSurface comp = new CompositeSurface();
comp.setSurfaceMember(surfaceMember);
Solid solid = new Solid();
solid.setExterior(new SurfaceProperty(comp));
solid.setId(geom.getGmlId().getGmlString());
return solid;
}
public static MultiSurface createMultiSurface(Geometry geom, GMLGeometryFactory factory,
ParserConfiguration config) {
if (geom.getType() != GeometryType.MULTI_SURFACE) {
throw new IllegalArgumentException("This can only handle MultiSurfaces");
}
List surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
// is not part of a boundary surface
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
}
} else {
// add reference to polygon
CompositeSurface cs = new CompositeSurface();
cs.addSurfaceMember(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
surfaces.add(cs);
}
}
if (surfaces.isEmpty()) {
return null;
}
MultiSurface ms = new MultiSurface(surfaces);
ms.setId(geom.getGmlId().getGmlString());
return ms;
}
public static MultiSurface createMultiSurface(List polygons, GMLGeometryFactory factory,
ParserConfiguration config) {
List surfaces = new ArrayList<>();
for (Polygon cdPoly : polygons) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
}
}
if (surfaces.isEmpty()) {
return null;
}
return new MultiSurface(surfaces);
}
public static CompositeSurface createCompositeSurface(Geometry geom, GMLGeometryFactory factory,
ParserConfiguration config) {
List surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
}
}
if (surfaces.isEmpty()) {
return null;
}
return new CompositeSurface(surfaces);
}
}