Commit b2d40f78 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev_citygml3' into 'dev'

CityGML 3.0. Support

See merge request !10
2 merge requests!11CityDoctor Release Version 3.16.0,!10CityGML 3.0. Support
Pipeline #10321 passed with stage
in 1 minute and 35 seconds
Showing with 2615 additions and 1966 deletions
+2615 -1966
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import java.io.Serial;
public class CityFurniture extends CityObject {
@Serial
private static final long serialVersionUID = 3325661061543962473L;
private org.citygml4j.core.model.cityfurniture.CityFurniture cgmlCityFurniture;
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public AbstractCityObject getGmlObject() {
return cgmlCityFurniture;
}
public void setGmlObject(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) {
cgmlCityFurniture = gmlCityFurniture;
}
@Override
public void unsetGmlGeometries() {
cgmlCityFurniture.setLod0MultiSurface(null);
cgmlCityFurniture.setLod2MultiSurface(null);
cgmlCityFurniture.setLod3MultiSurface(null);
cgmlCityFurniture.setLod1Solid(null);
cgmlCityFurniture.setLod2Solid(null);
cgmlCityFurniture.setLod3Solid(null);
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(null);
}
@Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) {
continue;
}
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
} else {
Solid solid = CityGmlUtils.createSolid(geom, factory, config);
setSolidAccordingToLod(geom, solid);
}
}
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
cgmlCityFurniture.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
cgmlCityFurniture.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
cgmlCityFurniture.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings");
}
}
private void setSolidAccordingToLod(Geometry geom, Solid solid) {
switch (geom.getLod()) {
case LOD1:
cgmlCityFurniture.setLod1Solid(new SolidProperty(solid));
break;
case LOD2:
cgmlCityFurniture.setLod2Solid(new SolidProperty(solid));
break;
case LOD3:
cgmlCityFurniture.setLod3Solid(new SolidProperty(solid));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
}
}
@Override
public FeatureType getFeatureType() {
return FeatureType.CITY_FURNITURE;
}
@Override
public Copyable createCopyInstance() {
return new CityFurniture();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
CityFurniture originalCF = (CityFurniture) original;
cgmlCityFurniture = originalCF.cgmlCityFurniture;
}
}
/*-
* 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
......@@ -18,184 +18,191 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Abstract class for general features such as Buildings, Water objects, ...
* <br>
* Contains the geometries
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public abstract class CityObject extends GmlElement {
@Serial
private static final long serialVersionUID = 651712070755024188L;
private final List<Geometry> geometryList = new ArrayList<>();
/**
* Recreates the CityGML4j geometry in this object. The CityGML4j geometry is
* deleted from the data structure as was mapped to the city doctor data
* structure. For writing CityGML files the geometry has to be restored. Also
* maps changes to geometry back to CityGML4j
*
* @param factory needed to create CityGML4j data structures
* @param config contains information whether a city doctor point was
* transformed to a different coordinate system. It would need to
* be transformed to the original coordinate system
*/
public abstract void reCreateGeometries(GeometryFactory factory, ParserConfiguration config);
/**
* Getter for the CityGML4j data object
*
* @return the CityGML4j data object
*/
public abstract AbstractCityObject getGmlObject();
/**
* Remove the CityGML4j geometries from the data structure to save memory.
*/
public abstract void unsetGmlGeometries();
public void addGeometry(Geometry geom) {
Objects.requireNonNull(geom);
geometryList.add(geom);
geom.setParent(this);
}
public List<Geometry> getGeometries() {
return geometryList;
}
public void removeGeometry(Lod lod) {
@Serial
private static final long serialVersionUID = 651712070755024188L;
private final List<Geometry> geometryList = new ArrayList<>();
private final List<GenericAttribute> genericAttributeList = new ArrayList<>();
/**
* Recreates the CityGML4j geometry in this object. The CityGML4j geometry is
* deleted from the data structure as was mapped to the city doctor data
* structure. For writing CityGML files the geometry has to be restored. Also
* maps changes to geometry back to CityGML4j
*
* @param factory needed to create CityGML4j data structures
* @param config contains information whether a city doctor point was
* transformed to a different coordinate system. It would need to
* be transformed to the original coordinate system
*/
public abstract void reCreateGeometries(GeometryFactory factory, ParserConfiguration config);
/**
* Getter for the CityGML4j data object
*
* @return the CityGML4j data object
*/
public abstract AbstractCityObject getGmlObject();
/**
* Remove the CityGML4j geometries from the data structure to save memory.
*/
public abstract void unsetGmlGeometries();
public void addGeometry(Geometry geom) {
Objects.requireNonNull(geom);
geometryList.add(geom);
geom.setParent(this);
}
public List<Geometry> getGeometries() {
return geometryList;
}
public void removeGeometry(Lod lod) {
geometryList.removeIf(geom -> geom.getLod() == lod);
}
public void removeGeometry(Lod lod, GeometryType type) {
}
public void removeGeometry(Lod lod, GeometryType type) {
geometryList.removeIf(geom -> geom.getLod() == lod && geom.getType() == type);
}
public Geometry getHighestLodGeometry() {
Geometry highestLodGeometry = null;
Lod highestLod = null;
for (Geometry geom : geometryList) {
if (highestLod == null || geom.getLod().isHigher(highestLod)) {
highestLodGeometry = geom;
highestLod = geom.getLod();
}
}
return highestLodGeometry;
}
public abstract FeatureType getFeatureType();
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (Geometry geom : geometryList) {
geom.accept(c);
}
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
for (Geometry geom : geometryList) {
geom.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Geometry geom : geometryList) {
geom.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsAnyError()) {
return true;
}
}
return false;
}
public Geometry getGeometry(GeometryType type, Lod lod) {
for (Geometry geom : geometryList) {
if (geom.getType() == type && geom.getLod() == lod) {
return geom;
}
}
return null;
}
@Override
public void prepareForChecking() {
for (Geometry geom : geometryList) {
geom.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
for (Geometry geom : geometryList) {
geom.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
for (Geometry geom : geometryList) {
handler.addInstance(geom);
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
CityObject originalCo = (CityObject) original;
for (Geometry geom : originalCo.geometryList) {
geometryList.add(handler.getCopyInstance(geom));
}
}
}
public Geometry getHighestLodGeometry() {
Geometry highestLodGeometry = null;
Lod highestLod = null;
for (Geometry geom : geometryList) {
if (highestLod == null || geom.getLod().isHigher(highestLod)) {
highestLodGeometry = geom;
highestLod = geom.getLod();
}
}
return highestLodGeometry;
}
public void addGenericAttribute(GenericAttribute genericAttribute) {
genericAttributeList.add(genericAttribute);
}
public List<GenericAttribute> getGenericAttributes() {
return genericAttributeList;
}
public abstract FeatureType getFeatureType();
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (Geometry geom : geometryList) {
geom.accept(c);
}
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
for (Geometry geom : geometryList) {
geom.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Geometry geom : geometryList) {
geom.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsAnyError()) {
return true;
}
}
return false;
}
public Geometry getGeometry(GeometryType type, Lod lod) {
for (Geometry geom : geometryList) {
if (geom.getType() == type && geom.getLod() == lod) {
return geom;
}
}
return null;
}
@Override
public void prepareForChecking() {
for (Geometry geom : geometryList) {
geom.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
for (Geometry geom : geometryList) {
geom.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
for (Geometry geom : geometryList) {
handler.addInstance(geom);
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
CityObject originalCo = (CityObject) original;
for (Geometry geom : originalCo.geometryList) {
geometryList.add(handler.getCopyInstance(geom));
}
}
}
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Riegel
*/
public final class CompositeCollection {
@Serial
private static final long serialVersionUID = -1867197873443341287L;
private GmlId gmlId;
private List<ConcretePolygon> compositeMembers = new ArrayList<>();
private List<CompositeCollection> childComposites = new ArrayList<>();
public void addCompositeMember(ConcretePolygon p) {
compositeMembers.add(p);
p.setPartOfComposite(this);
}
public void addAllChildComposites(List<CompositeCollection> children) {
childComposites.addAll(children);
}
public List<CompositeCollection> getChildComposites() {
return childComposites;
}
public List<ConcretePolygon> getCompositeMembers() {
List<ConcretePolygon> copy = new ArrayList<>(compositeMembers);
for (CompositeCollection c : childComposites) {
copy.addAll(c.getCompositeMembers());
}
return copy;
}
public List<ConcretePolygon> getNonRecursiveCompositeMembers() {
return compositeMembers;
}
public void setGmlId(GmlId gmlId) {
this.gmlId = gmlId;
}
public GmlId getGmlId() {
return gmlId;
}
}
......@@ -18,11 +18,6 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
......@@ -33,6 +28,11 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A polygon that actually contains the rings and points representing the
* geometry
......@@ -49,12 +49,11 @@ public class ConcretePolygon extends Polygon {
private List<LinearRing> innerRings;
private BoundarySurface partOfSurface;
private Installation partfOfInstallation;
private CompositeCollection partOfComposite = null;
private Geometry parent;
private LinkedPolygon linkedFromPolygon;
public ConcretePolygon() {
// TODO Auto-generated constructor stub
}
public ConcretePolygon() {}
/*
* (non-Javadoc)
......@@ -138,6 +137,18 @@ public class ConcretePolygon extends Polygon {
parent = geometry;
}
protected void setPartOfComposite(CompositeCollection comp) {
this.partOfComposite = comp;
}
public CompositeCollection getPartOfComposite() {
return partOfComposite;
}
public boolean isCompositeMember() {
return (partOfComposite != null);
}
/*
* (non-Javadoc)
*
......
/*-
* 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
......@@ -18,202 +18,201 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
/**
* Representing an edge between two consecutive points of a linear ring
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class Edge implements Serializable, Copyable {
@Serial
private static final long serialVersionUID = -504694863498128296L;
private final List<Polygon> adjacentPolygons = new ArrayList<>(2);
private final List<LinearRing> adjacentRings = new ArrayList<>(2);
private Vertex from;
private Vertex to;
// start with 1 for a new edge
private int numberOfHalfEdges = 1;
private int numberOfOppositeHalfEdges;
public Edge(Vertex from, Vertex to) {
this.from = from;
this.to = to;
}
private Edge() {
}
public Vertex getFrom() {
return from;
}
public Vertex getTo() {
return to;
}
public void addHalfEdge(Vertex v0, Vertex v1) {
if (v0 == null || v1 == null) {
return;
}
if (isPointOfEdge(v0, from) && isPointOfEdge(v1, to)) {
numberOfHalfEdges++;
return;
}
if (isPointOfEdge(v1, from) && isPointOfEdge(v0, to)) {
numberOfOppositeHalfEdges++;
return;
}
throw new IllegalStateException(
"The given vertices do not form this edge\n v0=" + v0 + ", v1=" + v1 + ", edge" + this);
}
private boolean isPointOfEdge(Vertex v0, Vertex edgePoint) {
@Serial
private static final long serialVersionUID = -504694863498128296L;
private final List<Polygon> adjacentPolygons = new ArrayList<>(2);
private final List<LinearRing> adjacentRings = new ArrayList<>(2);
private Vertex from;
private Vertex to;
// start with 1 for a new edge
private int numberOfHalfEdges = 1;
private int numberOfOppositeHalfEdges;
public Edge(Vertex from, Vertex to) {
this.from = from;
this.to = to;
}
private Edge() {
}
public Vertex getFrom() {
return from;
}
public Vertex getTo() {
return to;
}
public void addHalfEdge(Vertex v0, Vertex v1) {
if (v0 == null || v1 == null) {
return;
}
if (isPointOfEdge(v0, from) && isPointOfEdge(v1, to)) {
numberOfHalfEdges++;
return;
}
if (isPointOfEdge(v1, from) && isPointOfEdge(v0, to)) {
numberOfOppositeHalfEdges++;
return;
}
throw new IllegalStateException(
"The given vertices do not form this edge\n v0=" + v0 + ", v1=" + v1 + ", edge" + this);
}
private boolean isPointOfEdge(Vertex v0, Vertex edgePoint) {
return v0.equals(edgePoint);
}
public boolean formedByIgnoreDirection(Vertex v1, Vertex v2) {
return (v1 == from && v2 == to) || (v1 == to && v2 == from);
}
public boolean equalsIgnoreDirection(Edge other) {
return (other.from.equals(from) && other.to.equals(to)) || (other.from.equals(to) && other.to.equals(from));
}
public int getNumberOfHalfEdges() {
return numberOfHalfEdges;
}
public int getNumberOppositeHalfEdges() {
return numberOfOppositeHalfEdges;
}
public int getNumberOfAllHalfEdges() {
return numberOfHalfEdges + numberOfOppositeHalfEdges;
}
public List<Polygon> getAdjacentPolygons() {
return adjacentPolygons;
}
public List<LinearRing> getAdjacentRings() {
return adjacentRings;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((to == null) ? 0 : to.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Edge other = (Edge) obj;
if (from == null) {
if (other.from != null) {
return false;
}
} else if (!from.equals(other.from)) {
return false;
}
if (to == null) {
public boolean formedByIgnoreDirection(Vertex v1, Vertex v2) {
return (v1 == from && v2 == to) || (v1 == to && v2 == from);
}
public boolean equalsIgnoreDirection(Edge other) {
return (other.from.equals(from) && other.to.equals(to)) || (other.from.equals(to) && other.to.equals(from));
}
public int getNumberOfHalfEdges() {
return numberOfHalfEdges;
}
public int getNumberOppositeHalfEdges() {
return numberOfOppositeHalfEdges;
}
public int getNumberOfAllHalfEdges() {
return numberOfHalfEdges + numberOfOppositeHalfEdges;
}
public List<Polygon> getAdjacentPolygons() {
return adjacentPolygons;
}
public List<LinearRing> getAdjacentRings() {
return adjacentRings;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((to == null) ? 0 : to.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Edge other = (Edge) obj;
if (from == null) {
if (other.from != null) {
return false;
}
} else if (!from.equals(other.from)) {
return false;
}
if (to == null) {
return other.to == null;
} else return to.equals(other.to);
}
public void addAdjacentPolygon(Polygon p) {
adjacentPolygons.add(p);
}
public void addAdjacentRing(LinearRing lr) {
adjacentRings.add(lr);
}
@Override
public String toString() {
return "Edge [from=" + from + ", to=" + to + "]";
}
public boolean contains(Vertex v) {
return v == from || v == to;
}
public Vertex getConnectionPoint(Edge e) {
if (from == e.getTo() || from == e.getFrom()) {
return from;
}
if (to == e.getTo() || to == e.getFrom()) {
return to;
}
return null;
}
/**
* finds the point on the other end of the edge if the given vertex is one of
* the end points.
*
* @param c the given vertex
* @return the opposite vertex or null if the given vertex is not an end point.
*/
public Vertex getOppositeVertex(Vertex c) {
if (c == from) {
return to;
}
if (c == to) {
return from;
}
return null;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(from);
handler.addInstance(to);
handler.addInstance(adjacentPolygons);
handler.addInstance(adjacentRings);
}
@Override
public Copyable createCopyInstance() {
return new Edge();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
Edge originalEdge = (Edge) original;
from = handler.getCopyInstance(originalEdge.from);
to = handler.getCopyInstance(originalEdge.to);
numberOfHalfEdges = originalEdge.numberOfHalfEdges;
numberOfOppositeHalfEdges = originalEdge.numberOfOppositeHalfEdges;
for (Polygon originalPoly : originalEdge.adjacentPolygons) {
adjacentPolygons.add(handler.getCopyInstance(originalPoly));
}
for (LinearRing originalRing : originalEdge.adjacentRings) {
adjacentRings.add(handler.getCopyInstance(originalRing));
}
}
} else return to.equals(other.to);
}
public void addAdjacentPolygon(Polygon p) {
adjacentPolygons.add(p);
}
public void addAdjacentRing(LinearRing lr) {
adjacentRings.add(lr);
}
@Override
public String toString() {
return "Edge [from=" + from + ", to=" + to + "]";
}
public boolean contains(Vertex v) {
return v == from || v == to;
}
public Vertex getConnectionPoint(Edge e) {
if (from == e.getTo() || from == e.getFrom()) {
return from;
}
if (to == e.getTo() || to == e.getFrom()) {
return to;
}
return null;
}
/**
* finds the point on the other end of the edge if the given vertex is one of
* the end points.
*
* @param c the given vertex
* @return the opposite vertex or null if the given vertex is not an end point.
*/
public Vertex getOppositeVertex(Vertex c) {
if (c == from) {
return to;
}
if (c == to) {
return from;
}
return null;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(from);
handler.addInstance(to);
handler.addInstance(adjacentPolygons);
handler.addInstance(adjacentRings);
}
@Override
public Copyable createCopyInstance() {
return new Edge();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
Edge originalEdge = (Edge) original;
from = handler.getCopyInstance(originalEdge.from);
to = handler.getCopyInstance(originalEdge.to);
numberOfHalfEdges = originalEdge.numberOfHalfEdges;
numberOfOppositeHalfEdges = originalEdge.numberOfOppositeHalfEdges;
for (Polygon originalPoly : originalEdge.adjacentPolygons) {
adjacentPolygons.add(handler.getCopyInstance(originalPoly));
}
for (LinearRing originalRing : originalEdge.adjacentRings) {
adjacentRings.add(handler.getCopyInstance(originalRing));
}
}
}
/*-
* 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
......@@ -20,13 +20,12 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/**
* Possible feature types in CityGML
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public enum FeatureType {
BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING,
BUILDING_PART, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION
BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING,
BUILDING_PART, BUILDING_SUBDIVISION, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION, ROOM, FURNITURE, CITY_FURNITURE,
GENERIC_CITY_OBJECT, TUNNEL, TUNNEL_PART, TUNNEL_CONSTRUCTION_ELEMENT, TUNNEL_INSTALLATION,
}
package de.hft.stuttgart.citydoctor2.datastructure;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractGenericAttributeProperty;
import org.citygml4j.core.model.generics.*;
public class GenericAttribute {
private static final Logger logger = LogManager.getLogger(GenericAttribute.class);
private final AbstractGenericAttributeProperty original;
private String type;
private String name;
private String value;
public GenericAttribute(AbstractGenericAttributeProperty attributeProperty) {
original = attributeProperty;
if (attributeProperty.getObject() == null) {
logger.warn("GenericAttribute {} is null", attributeProperty);
return;
}
name = attributeProperty.getObject().getName();
if (attributeProperty.getObject() instanceof StringAttribute sa) {
type = "StringAttribute";
value = sa.getValue();
} else if (attributeProperty.getObject() instanceof IntAttribute ia) {
type = "IntAttribute";
value = ia.getValue().toString();
} else if (attributeProperty.getObject() instanceof DoubleAttribute da) {
type = "DoubleAttribute";
value = da.getValue().toString();
} else if (attributeProperty.getObject() instanceof DateAttribute date) {
type = "DateAttribute";
value = date.getValue().toString();
} else if (attributeProperty.getObject() instanceof UriAttribute ua) {
type = "UriAttribute";
value = ua.getValue();
} else if (attributeProperty.getObject() instanceof MeasureAttribute ma) {
type = "MeasureAttribute";
value = ma.getValue().toString();
} else if (attributeProperty.getObject() instanceof CodeAttribute ca) {
type = "CodeAttribute";
value = ca.getValue().toString();
} else {
logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject());
value = attributeProperty.getObject().getValue().toString();
type = "Unknown type";
}
}
public AbstractGenericAttributeProperty getOriginal() {
return original;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return String.format("%s: [ %s = %s ]", type, name, value);
}
}
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class GenericCityObject extends CityObject {
@Serial
private static final long serialVersionUID = 5886527664552294353L;
private org.citygml4j.core.model.generics.GenericOccupiedSpace cgmlGos;
private static final Logger logger = LogManager.getLogger(GenericCityObject.class);
private final List<BoundarySurface> boundarySurfaceList = new ArrayList<>();
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (BoundarySurface bs : boundarySurfaceList) {
bs.accept(c);
}
}
@Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) {
continue;
}
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
} else {
Solid solid = CityGmlUtils.createSolid(geom, factory, config);
setSolidAccordingToLod(geom, solid);
}
}
for (BoundarySurface bs : boundarySurfaceList) {
reCreateBoundarySurface(factory, config, bs);
}
}
private void reCreateBoundarySurface(GeometryFactory factory, ParserConfiguration config, BoundarySurface bs) {
if (bs.getGeometries().isEmpty()) {
for (AbstractSpaceBoundaryProperty bsp : cgmlGos.getBoundaries()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
logger.warn("Found empty boundary surface: {}, removing from generic object", bs.getGmlId());
cgmlGos.getBoundaries().remove(bsp);
break;
}
}
return;
}
bs.reCreateGeometries(factory, config);
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
cgmlGos.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
cgmlGos.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
cgmlGos.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings");
}
}
private void setSolidAccordingToLod(Geometry geom, Solid solid) {
switch (geom.getLod()) {
case LOD1:
cgmlGos.setLod1Solid(new SolidProperty(solid));
break;
case LOD2:
cgmlGos.setLod2Solid(new SolidProperty(solid));
break;
case LOD3:
cgmlGos.setLod3Solid(new SolidProperty(solid));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaceList) {
bs.collectContainedErrors(errors);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaceList) {
bs.clearAllContainedCheckResults();
}
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaceList) {
if (bs.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaceList) {
if (bs.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaceList) {
bs.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaceList) {
bs.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(boundarySurfaceList);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
GenericCityObject originalGos = (GenericCityObject) original;
for (BoundarySurface originalBs : originalGos.boundarySurfaceList) {
boundarySurfaceList.add(handler.getCopyInstance(originalBs));
}
cgmlGos = originalGos.cgmlGos;
}
@Override
public AbstractCityObject getGmlObject() {
return null;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.GENERIC_CITY_OBJECT;
}
public List<BoundarySurface> getBoundarySurfaces() {
return boundarySurfaceList;
}
@Override
public void unsetGmlGeometries() {
cgmlGos.setLod1Solid(null);
cgmlGos.setLod2Solid(null);
cgmlGos.setLod3Solid(null);
cgmlGos.setLod2MultiSurface(null);
cgmlGos.setLod3MultiSurface(null);
for (BoundarySurface bs : boundarySurfaceList) {
bs.unsetGmlGeometries();
}
}
public void setGmlObject(org.citygml4j.core.model.generics.GenericOccupiedSpace gos) {
this.cgmlGos = gos;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaceList.add(bs);
bs.setParent(this);
}
@Override
public Copyable createCopyInstance() {
return new GenericCityObject();
}
}
/*-
* 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
......@@ -18,16 +18,6 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
......@@ -39,420 +29,423 @@ import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import java.io.Serial;
import java.util.*;
import java.util.Map.Entry;
/**
* Representation of a geometry containing the polygons and edges
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class Geometry extends GmlElement {
private static final String FAILED_REMOVING_POLYGON = "Removing polygon %s but polygon is not in geometry";
@Serial
private static final long serialVersionUID = 2539031030917731575L;
private static final Random r = new Random();
private GeometryType type;
private final Lod lod;
private CityObject parent;
private final List<Polygon> polygons = new ArrayList<>(2);
private List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices;
public Geometry(GeometryType type, Lod lod) {
this.lod = lod;
this.type = type;
}
void setParent(CityObject parent) {
this.parent = parent;
}
public CityObject getParent() {
return parent;
}
public void setType(GeometryType type) {
this.type = type;
}
public GeometryType getType() {
return type;
}
public Lod getLod() {
return lod;
}
public List<Polygon> getPolygons() {
return polygons;
}
public void addPolygon(Polygon cdPoly) {
polygons.add(cdPoly);
cdPoly.setParent(this);
// set part of boundary surface or building installation or both
if (parent instanceof BoundarySurface bs) {
cdPoly.setPartOfSurface(bs);
if (bs.getParent() instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi);
}
} else if (parent instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi);
}
}
public void updateEdges() {
edges = new ArrayList<>();
edgeMap = new HashMap<>();
Map<Edge, Edge> duplicacyMap = new HashMap<>();
for (Polygon p : polygons) {
LinearRing extRing = p.getExteriorRing();
createEdgesFromRing(duplicacyMap, p, extRing);
for (LinearRing inner : p.getInnerRings()) {
createEdgesFromRing(duplicacyMap, p, inner);
}
}
}
void anonymize() {
setGmlId(GmlId.generateId());
for (Polygon p : polygons) {
p.anonymize();
}
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double minZ = Double.MAX_VALUE;
for (Vertex v : vertices) {
if (v.getX() < minX) {
minX = v.getX();
}
if (v.getY() < minY) {
minY = v.getY();
}
if (v.getZ() < minZ) {
minZ = v.getZ();
}
}
double varX = r.nextDouble() * 10;
double varY = r.nextDouble() * 10;
double varZ = r.nextDouble() * 10;
for (Vertex v : vertices) {
v.setX(v.getX() - minX + varX);
v.setY(v.getY() - minY + varY);
v.setZ(v.getZ() - minZ + varZ);
}
}
private void createEdgesFromRing(Map<Edge, Edge> duplicacyMap, Polygon p, LinearRing ring) {
if (ring == null) {
return;
}
// only go to size -1 as ring should be closed
for (int i = 0; i < ring.getVertices().size() - 1; i++) {
Vertex v0 = ring.getVertices().get(i);
Vertex v1 = ring.getVertices().get(i + 1);
Edge tempEdge = new Edge(v0, v1);
Edge e = duplicacyMap.get(tempEdge);
if (e == null) {
// no duplicate found, enter edges
Edge oppositeEdge = new Edge(v1, v0);
duplicacyMap.put(tempEdge, tempEdge);
duplicacyMap.put(oppositeEdge, tempEdge);
e = tempEdge;
edges.add(e);
edgeMap.put(new SerializablePair<>(v0, v1), e);
edgeMap.put(new SerializablePair<>(v1, v0), e);
} else {
e.addHalfEdge(v0, v1);
}
e.addAdjacentPolygon(p);
e.addAdjacentRing(ring);
}
}
public Vector3d getCenter() {
return calculateBoundingBox().getCenter();
}
/**
* This will calculate two points where every other point in the geometry is
* between those two. If the geometry does not contain points or is null, an
* empty array is returned. This is considered an axis aligned bounding box.
* Only the exterior rings of the polygons is used as inner rings should be
* within the exterior or they are faulty.
*
* @return an array of two points. The first contains the lowest coordinates,
* the second contains the highest coordinates
*/
public BoundingBox calculateBoundingBox() {
return BoundingBoxCalculator.calculateBoundingBox(polygons);
}
public double calculateVolume() {
double sum = 0;
Vector3d center = calculateBoundingBox().getCenter();
for (Polygon p : polygons) {
TesselatedPolygon tesselatedPolygon = p.tesselate();
for (Triangle3d t : tesselatedPolygon.getTriangles()) {
Vector3d p1 = t.getP1().minus(center);
Vector3d p2 = t.getP2().minus(center);
Vector3d p3 = t.getP3().minus(center);
sum += det(p1.getCoordinates(), p2.getCoordinates(), p3.getCoordinates());
}
}
return sum / 6d;
}
private double det(double[] a, double[] b, double[] c) {
return -c[0] * b[1] * a[2] + b[0] * c[1] * a[2] + c[0] * a[1] * b[2] - a[0] * c[1] * b[2] - b[0] * a[1] * c[2]
+ a[0] * b[1] * c[2];
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
for (Polygon p : polygons) {
p.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Polygon p : polygons) {
p.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (Polygon p : polygons) {
p.accept(c);
}
}
@Override
public String toString() {
return "Geometry [type=" + type + ", lod=" + lod + ", id=" + getGmlId() + "]";
}
public List<Vertex> getVertices() {
return vertices;
}
public List<Edge> getEdges() {
return edges;
}
public List<Edge> getEdgesAdjacentTo(Vertex v) {
List<Edge> adjacentEdges = new ArrayList<>();
for (Edge e : edges) {
if (e.getFrom() == v || e.getTo() == v) {
adjacentEdges.add(e);
}
}
return adjacentEdges;
}
public Edge getEdge(Vertex v1, Vertex v2) {
return edgeMap.get(new SerializablePair<>(v1, v2));
}
public void updateEdgesAndVertices() {
updateVertices();
updateEdges();
}
public void updateVertices() {
Set<Vertex> vertexSet = new HashSet<>();
for (Polygon p : getPolygons()) {
updateRing(vertexSet, p.getExteriorRing());
for (LinearRing inner : p.getInnerRings()) {
updateRing(vertexSet, inner);
}
}
vertices = new ArrayList<>(vertexSet);
}
private void updateRing(Set<Vertex> vertexSet, LinearRing ring) {
if (ring == null) {
return;
}
for (Vertex v : ring.getVertices()) {
if (vertexSet.add(v)) {
// new vertex, clear adjacent rings in case new rings have been added
v.clearAdjacentRings(this);
}
// add ring to adjacent rings of vertex
v.addAdjacentRing(ring, this);
}
}
void removePolygon(Polygon p) {
p.removeRings();
if (!polygons.remove(p)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
if (p.isLink()) {
Polygon original = p.getOriginal();
if (!original.getParent().polygons.remove(original)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
} else if (p.isLinkedTo()) {
Polygon link = p.getLinkedFromPolygon();
if (!link.getParent().polygons.remove(link)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
}
}
public void replacePolygon(Polygon p, ConcretePolygon... polygons) {
removePolygon(p);
if (p.isLink()) {
Geometry geom2 = p.getOriginal().getParent();
for (ConcretePolygon newPoly : polygons) {
geom2.addPolygon(newPoly);
addPolygon(new LinkedPolygon(newPoly, this));
}
} else if (p.isLinkedTo()) {
Geometry geom2 = p.getLinkedFromPolygon().getParent();
for (ConcretePolygon newPoly : polygons) {
addPolygon(newPoly);
geom2.addPolygon(new LinkedPolygon(newPoly, geom2));
}
} else {
for (Polygon newPoly : polygons) {
addPolygon(newPoly);
}
}
}
public List<Edge> getEdgesAdjacentTo(Polygon p) {
List<Edge> list = new ArrayList<>();
for (Edge e : edges) {
if (e.getAdjacentPolygons().contains(p)) {
list.add(e);
}
}
return list;
}
public boolean containsPolygon(Polygon other) {
for (Polygon p : polygons) {
if (p.getGmlId().equals(other.getGmlId())) {
return true;
}
}
return false;
}
@Override
public void prepareForChecking() {
updateEdgesAndVertices();
}
@Override
public void clearMetaInformation() {
if (vertices != null) {
for (Vertex v : vertices) {
v.clearAdjacentRings();
}
vertices = null;
}
edges = null;
edgeMap = null;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(parent);
handler.addInstance(polygons);
handler.addInstance(edges);
handler.addInstance(vertices);
if (edgeMap != null) {
for (Entry<SerializablePair<Vertex, Vertex>, Edge> e : edgeMap.entrySet()) {
handler.addInstance(e.getKey().getValue0());
handler.addInstance(e.getKey().getValue1());
handler.addInstance(e.getValue());
}
}
}
@Override
public Copyable createCopyInstance() {
return new Geometry(type, lod);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Geometry originalGeometry = (Geometry) original;
for (Polygon originalPoly : originalGeometry.polygons) {
polygons.add(handler.getCopyInstance(originalPoly));
}
if (originalGeometry.edges != null) {
edges = new ArrayList<>(originalGeometry.edges.size());
for (Edge originalEdge : originalGeometry.edges) {
edges.add(handler.getCopyInstance(originalEdge));
}
}
if (originalGeometry.edgeMap != null) {
edgeMap = new HashMap<>(originalGeometry.edgeMap.size());
for (Entry<SerializablePair<Vertex, Vertex>, Edge> originalEntry : originalGeometry.edgeMap.entrySet()) {
Vertex copyV0 = handler.getCopyInstance(originalEntry.getKey().getValue0());
Vertex copyV1 = handler.getCopyInstance(originalEntry.getKey().getValue1());
SerializablePair<Vertex, Vertex> pair = new SerializablePair<>(copyV0, copyV1);
Edge copyEdge = handler.getCopyInstance(originalEntry.getValue());
edgeMap.put(pair, copyEdge);
}
}
if (originalGeometry.vertices != null) {
vertices = new ArrayList<>(originalGeometry.vertices.size());
for (Vertex originalVertex : originalGeometry.vertices) {
vertices.add(handler.getCopyInstance(originalVertex));
}
}
parent = handler.getCopyInstance(originalGeometry.parent);
}
private static final String FAILED_REMOVING_POLYGON = "Removing polygon %s but polygon is not in geometry";
@Serial
private static final long serialVersionUID = 2539031030917731575L;
private static final Random r = new Random();
private GeometryType type;
private final Lod lod;
private CityObject parent;
private final List<Polygon> polygons = new ArrayList<>(2);
private List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices;
public Geometry(GeometryType type, Lod lod) {
this.lod = lod;
this.type = type;
}
void setParent(CityObject parent) {
this.parent = parent;
}
public CityObject getParent() {
return parent;
}
public void setType(GeometryType type) {
this.type = type;
}
public GeometryType getType() {
return type;
}
public Lod getLod() {
return lod;
}
public List<Polygon> getPolygons() {
return polygons;
}
public void addPolygon(Polygon cdPoly) {
polygons.add(cdPoly);
cdPoly.setParent(this);
// set part of boundary surface or building installation or both
if (parent instanceof BoundarySurface bs) {
cdPoly.setPartOfSurface(bs);
if (bs.getParent() instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi);
}
} else if (parent instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi);
}
}
public void updateEdges() {
edges = new ArrayList<>();
edgeMap = new HashMap<>();
Map<Edge, Edge> duplicacyMap = new HashMap<>();
for (Polygon p : polygons) {
LinearRing extRing = p.getExteriorRing();
createEdgesFromRing(duplicacyMap, p, extRing);
for (LinearRing inner : p.getInnerRings()) {
createEdgesFromRing(duplicacyMap, p, inner);
}
}
}
void anonymize() {
setGmlId(GmlId.generateId());
for (Polygon p : polygons) {
p.anonymize();
}
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double minZ = Double.MAX_VALUE;
for (Vertex v : vertices) {
if (v.getX() < minX) {
minX = v.getX();
}
if (v.getY() < minY) {
minY = v.getY();
}
if (v.getZ() < minZ) {
minZ = v.getZ();
}
}
double varX = r.nextDouble() * 10;
double varY = r.nextDouble() * 10;
double varZ = r.nextDouble() * 10;
for (Vertex v : vertices) {
v.setX(v.getX() - minX + varX);
v.setY(v.getY() - minY + varY);
v.setZ(v.getZ() - minZ + varZ);
}
}
private void createEdgesFromRing(Map<Edge, Edge> duplicacyMap, Polygon p, LinearRing ring) {
if (ring == null) {
return;
}
// only go to size -1 as ring should be closed
for (int i = 0; i < ring.getVertices().size() - 1; i++) {
Vertex v0 = ring.getVertices().get(i);
Vertex v1 = ring.getVertices().get(i + 1);
Edge tempEdge = new Edge(v0, v1);
Edge e = duplicacyMap.get(tempEdge);
if (e == null) {
// no duplicate found, enter edges
Edge oppositeEdge = new Edge(v1, v0);
duplicacyMap.put(tempEdge, tempEdge);
duplicacyMap.put(oppositeEdge, tempEdge);
e = tempEdge;
edges.add(e);
edgeMap.put(new SerializablePair<>(v0, v1), e);
edgeMap.put(new SerializablePair<>(v1, v0), e);
} else {
e.addHalfEdge(v0, v1);
}
e.addAdjacentPolygon(p);
e.addAdjacentRing(ring);
}
}
public Vector3d getCenter() {
return calculateBoundingBox().getCenter();
}
/**
* This will calculate two points where every other point in the geometry is
* between those two. If the geometry does not contain points or is null, an
* empty array is returned. This is considered an axis aligned bounding box.
* Only the exterior rings of the polygons is used as inner rings should be
* within the exterior or they are faulty.
*
* @return an array of two points. The first contains the lowest coordinates,
* the second contains the highest coordinates
*/
public BoundingBox calculateBoundingBox() {
return BoundingBoxCalculator.calculateBoundingBox(polygons);
}
public double calculateVolume() {
double sum = 0;
Vector3d center = calculateBoundingBox().getCenter();
for (Polygon p : polygons) {
TesselatedPolygon tesselatedPolygon = p.tesselate();
for (Triangle3d t : tesselatedPolygon.getTriangles()) {
Vector3d p1 = t.getP1().minus(center);
Vector3d p2 = t.getP2().minus(center);
Vector3d p3 = t.getP3().minus(center);
sum += det(p1.getCoordinates(), p2.getCoordinates(), p3.getCoordinates());
}
}
return sum / 6d;
}
private double det(double[] a, double[] b, double[] c) {
return -c[0] * b[1] * a[2] + b[0] * c[1] * a[2] + c[0] * a[1] * b[2] - a[0] * c[1] * b[2] - b[0] * a[1] * c[2]
+ a[0] * b[1] * c[2];
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
for (Polygon p : polygons) {
p.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Polygon p : polygons) {
p.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (Polygon p : polygons) {
p.accept(c);
}
}
@Override
public String toString() {
return "Geometry [type=" + type + ", lod=" + lod + ", id=" + getGmlId() + "]";
}
public List<Vertex> getVertices() {
return vertices;
}
public List<Edge> getEdges() {
return edges;
}
public List<Edge> getEdgesAdjacentTo(Vertex v) {
List<Edge> adjacentEdges = new ArrayList<>();
for (Edge e : edges) {
if (e.getFrom() == v || e.getTo() == v) {
adjacentEdges.add(e);
}
}
return adjacentEdges;
}
public Edge getEdge(Vertex v1, Vertex v2) {
return edgeMap.get(new SerializablePair<>(v1, v2));
}
public void updateEdgesAndVertices() {
updateVertices();
updateEdges();
}
public void updateVertices() {
Set<Vertex> vertexSet = new HashSet<>();
for (Polygon p : getPolygons()) {
updateRing(vertexSet, p.getExteriorRing());
for (LinearRing inner : p.getInnerRings()) {
updateRing(vertexSet, inner);
}
}
vertices = new ArrayList<>(vertexSet);
}
private void updateRing(Set<Vertex> vertexSet, LinearRing ring) {
if (ring == null) {
return;
}
for (Vertex v : ring.getVertices()) {
if (vertexSet.add(v)) {
// new vertex, clear adjacent rings in case new rings have been added
v.clearAdjacentRings(this);
}
// add ring to adjacent rings of vertex
v.addAdjacentRing(ring, this);
}
}
void removePolygon(Polygon p) {
p.removeRings();
if (!polygons.remove(p)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
if (p.isLink()) {
Polygon original = p.getOriginal();
if (!original.getParent().polygons.remove(original)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
} else if (p.isLinkedTo()) {
Polygon link = p.getLinkedFromPolygon();
if (!link.getParent().polygons.remove(link)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
}
}
}
public void replacePolygon(Polygon p, ConcretePolygon... polygons) {
removePolygon(p);
if (p.isLink()) {
Geometry geom2 = p.getOriginal().getParent();
for (ConcretePolygon newPoly : polygons) {
geom2.addPolygon(newPoly);
addPolygon(new LinkedPolygon(newPoly, this));
}
} else if (p.isLinkedTo()) {
Geometry geom2 = p.getLinkedFromPolygon().getParent();
for (ConcretePolygon newPoly : polygons) {
addPolygon(newPoly);
geom2.addPolygon(new LinkedPolygon(newPoly, geom2));
}
} else {
for (Polygon newPoly : polygons) {
addPolygon(newPoly);
}
}
}
public List<Edge> getEdgesAdjacentTo(Polygon p) {
List<Edge> list = new ArrayList<>();
for (Edge e : edges) {
if (e.getAdjacentPolygons().contains(p)) {
list.add(e);
}
}
return list;
}
public boolean containsPolygon(Polygon other) {
for (Polygon p : polygons) {
if (p.getGmlId().equals(other.getGmlId())) {
return true;
}
}
return false;
}
@Override
public void prepareForChecking() {
updateEdgesAndVertices();
}
@Override
public void clearMetaInformation() {
if (vertices != null) {
for (Vertex v : vertices) {
v.clearAdjacentRings();
}
vertices = null;
}
edges = null;
edgeMap = null;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(parent);
handler.addInstance(polygons);
handler.addInstance(edges);
handler.addInstance(vertices);
if (edgeMap != null) {
for (Entry<SerializablePair<Vertex, Vertex>, Edge> e : edgeMap.entrySet()) {
handler.addInstance(e.getKey().getValue0());
handler.addInstance(e.getKey().getValue1());
handler.addInstance(e.getValue());
}
}
}
@Override
public Copyable createCopyInstance() {
return new Geometry(type, lod);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Geometry originalGeometry = (Geometry) original;
for (Polygon originalPoly : originalGeometry.polygons) {
polygons.add(handler.getCopyInstance(originalPoly));
}
if (originalGeometry.edges != null) {
edges = new ArrayList<>(originalGeometry.edges.size());
for (Edge originalEdge : originalGeometry.edges) {
edges.add(handler.getCopyInstance(originalEdge));
}
}
if (originalGeometry.edgeMap != null) {
edgeMap = new HashMap<>(originalGeometry.edgeMap.size());
for (Entry<SerializablePair<Vertex, Vertex>, Edge> originalEntry : originalGeometry.edgeMap.entrySet()) {
Vertex copyV0 = handler.getCopyInstance(originalEntry.getKey().getValue0());
Vertex copyV1 = handler.getCopyInstance(originalEntry.getKey().getValue1());
SerializablePair<Vertex, Vertex> pair = new SerializablePair<>(copyV0, copyV1);
Edge copyEdge = handler.getCopyInstance(originalEntry.getValue());
edgeMap.put(pair, copyEdge);
}
}
if (originalGeometry.vertices != null) {
vertices = new ArrayList<>(originalGeometry.vertices.size());
for (Vertex originalVertex : originalGeometry.vertices) {
vertices.add(handler.getCopyInstance(originalVertex));
}
}
parent = handler.getCopyInstance(originalGeometry.parent);
}
}
/*-
* 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
......@@ -20,12 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/**
* Available geometry types
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public enum GeometryType {
MULTI_SURFACE, SOLID, COMPOSITE_SURFACE
MULTI_SURFACE, SOLID, COMPOSITE_SURFACE
}
/*-
* 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
......@@ -26,38 +26,37 @@ import java.io.Serial;
/**
* A general GML element that has a gml id
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public abstract class GmlElement extends Checkable implements Copyable {
@Serial
private static final long serialVersionUID = -3242505393303017359L;
private GmlId gmlId;
public void setGmlId(GmlId id) {
gmlId = id;
}
@Override
public GmlId getGmlId() {
if (gmlId == null) {
gmlId = GmlId.generateId();
}
return gmlId;
}
public boolean hasExistingGmlId() {
return gmlId != null && !gmlId.isGenerated();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
GmlElement originalElement = (GmlElement) original;
// generate gml id before copying
gmlId = originalElement.getGmlId();
}
@Serial
private static final long serialVersionUID = -3242505393303017359L;
private GmlId gmlId;
public void setGmlId(GmlId id) {
gmlId = id;
}
@Override
public GmlId getGmlId() {
if (gmlId == null) {
gmlId = GmlId.generateId();
}
return gmlId;
}
public boolean hasExistingGmlId() {
return gmlId != null && !gmlId.isGenerated();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
GmlElement originalElement = (GmlElement) original;
// generate gml id before copying
gmlId = originalElement.getGmlId();
}
}
/*-
* 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
......@@ -25,83 +25,82 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Represents a GML id. Additionally contains information whether this id was
* generated by city doctor
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class GmlId implements Serializable {
@Serial
private static final long serialVersionUID = 4273817255150972966L;
@Serial
private static final long serialVersionUID = 4273817255150972966L;
/* prefixes for generation */
private static final String GENERAL_GEN = "CityDoctor_%d_%d";
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
/* prefixes for generation */
private static final String GENERAL_GEN = "CityDoctor_%d_%d";
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
private final String gmlString;
private final boolean generated;
private final String gmlString;
private final boolean generated;
public GmlId(String gmlId) {
this(gmlId, false);
}
public GmlId(String gmlId) {
this(gmlId, false);
}
private GmlId(String gmlId, boolean generated) {
if (gmlId == null || gmlId.isEmpty()) {
throw new IllegalArgumentException("GmlId may not be null or empty. If no GmlId is given generate one");
}
this.gmlString = gmlId;
this.generated = generated;
}
private GmlId(String gmlId, boolean generated) {
if (gmlId == null || gmlId.isEmpty()) {
throw new IllegalArgumentException("GmlId may not be null or empty. If no GmlId is given generate one");
}
this.gmlString = gmlId;
this.generated = generated;
}
@Override
public String toString() {
return gmlString;
}
@Override
public String toString() {
return gmlString;
}
public String getGmlString() {
return gmlString;
}
public String getGmlString() {
return gmlString;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (generated ? 1231 : 1237);
result = prime * result + ((gmlString == null) ? 0 : gmlString.hashCode());
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (generated ? 1231 : 1237);
result = prime * result + ((gmlString == null) ? 0 : gmlString.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
GmlId other = (GmlId) obj;
if (generated != other.generated) {
return false;
}
if (gmlString == null) {
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
GmlId other = (GmlId) obj;
if (generated != other.generated) {
return false;
}
if (gmlString == null) {
return other.gmlString == null;
} else return gmlString.equals(other.gmlString);
} else return gmlString.equals(other.gmlString);
}
/**
* Determines if the GML-ID was generated by CityDoctor or not.
*
* @return True if it was generated, otherwise false.
*/
public boolean isGenerated() {
return generated;
}
/**
* Determines if the GML-ID was generated by CityDoctor or not.
*
* @return True if it was generated, otherwise false.
*/
public boolean isGenerated() {
return generated;
}
public static GmlId generateId() {
return new GmlId(String.format(GENERAL_GEN, System.currentTimeMillis(), ID_COUNTER.getAndIncrement()), true);
}
public static GmlId generateId() {
return new GmlId(String.format(GENERAL_GEN, System.currentTimeMillis(), ID_COUNTER.getAndIncrement()), true);
}
}
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.math.TransformationMatrix;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.ImplicitGeometry;
import java.io.Serial;
import java.util.List;
/**
* Datastructure for representation and resolving of implicit geometries
*
* @author Riegel
*/
public class ImplicitGeometryHolder extends Geometry {
private static final Logger logger = LogManager.getLogger(ImplicitGeometryHolder.class);
@Serial
private static final long serialVersionUID = -8938931081577196349L;
private ImplicitGeometry cgmlImplicitGeometry = null;
private final PrototypeGeometryType type;
private final Geometry prototypeGeometry;
public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, LibraryObject libObject) {
super(libObject.getType(), libObject.getLod());
prototypeGeometry = libObject;
type = PrototypeGeometryType.LIBRARY_OBJECT;
this.cgmlImplicitGeometry = cgmlImplicitGeometry;
applyTransformation();
}
public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, RelativeGeometry relativeGeometry) {
super(relativeGeometry.getType(), relativeGeometry.getLod());
prototypeGeometry = relativeGeometry;
type = PrototypeGeometryType.RELATIVE_GEOMETRY;
this.cgmlImplicitGeometry = cgmlImplicitGeometry;
applyTransformation();
}
/**
* Applies the transformation matrix of the implicit geometry to a copy of the reference geometry and copies the resulting
* transformed geometry into this object.
*/
private void applyTransformation() {
TransformationMatrix transformMatrix = new TransformationMatrix(cgmlImplicitGeometry);
Geometry transformedGeom = transformMatrix.transformGeometry(prototypeGeometry);
transformedGeom.getPolygons().forEach(this::addPolygon);
this.updateEdgesAndVertices();
}
public PrototypeGeometryType getPrototypeGeometryType() {
return type;
}
@Override
public void accept(Check c) {
prototypeGeometry.accept(c);
}
@Override
public boolean containsError(CheckId checkIdentifier) {
return prototypeGeometry.containsError(checkIdentifier);
}
@Override
public void clearAllContainedCheckResults() {
prototypeGeometry.clearAllContainedCheckResults();
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
prototypeGeometry.clearAllContainedCheckResults();
}
@Override
public boolean containsAnyError() {
return prototypeGeometry.containsAnyError();
}
@Override
public void prepareForChecking() {
this.updateEdgesAndVertices();
prototypeGeometry.prepareForChecking();
}
@Override
public boolean isValidated() {
return prototypeGeometry.isValidated();
}
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
}
/*-
* 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
......@@ -18,10 +18,13 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.bridge.BridgeInstallation;
import org.citygml4j.core.model.construction.AbstractInstallation;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
......@@ -32,252 +35,248 @@ import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
public class Installation extends CityObject {
@Serial
private static final long serialVersionUID = 1576237433322680191L;
private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4);
private AbstractInstallation gmlBi;
private CityObject parent;
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
if (ms != null) {
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
}
} else if (geom.getType() == GeometryType.COMPOSITE_SURFACE) {
CompositeSurface cs = CityGmlUtils.createCompositeSurface(geom, factory, config);
if (cs != null) {
setGeometryAccordingToLod(geom.getLod(), new SurfaceProperty(cs));
}
} else {
throw new IllegalStateException("BuildingInstallation not have Solid geometries");
}
}
for (BoundarySurface bs : boundarySurfaces) {
bs.reCreateGeometries(factory, config);
}
}
private void setGeometryAccordingToLod(Lod lod, GeometryProperty<?> ms) {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
addGeometryToBuildingInstallation(lod, ms, localBi);
} else if (gmlBi instanceof BridgeInstallation localBi) {
addGeometryToBridgeInstallation(lod, ms, localBi);
}
}
private void addGeometryToBuildingInstallation(Lod lod, GeometryProperty<?> ms,
org.citygml4j.core.model.building.BuildingInstallation localBi) {
switch (lod) {
case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms);
break;
case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms);
break;
case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms);
break;
default:
throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
}
}
private void addGeometryToBridgeInstallation(Lod lod, GeometryProperty<?> ms, BridgeInstallation localBi) {
switch (lod) {
case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms);
break;
case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms);
break;
case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms);
break;
default:
throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
}
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (BoundarySurface bs : boundarySurfaces) {
bs.accept(c);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaces) {
bs.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
public void setParent(CityObject parent) {
this.parent = parent;
}
public CityObject getParent() {
return parent;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaces.add(bs);
bs.setParent(this);
}
public void unsetGmlGeometries() {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null);
} else if (gmlBi instanceof BridgeInstallation localBi) {
removeGeometriesFromBridgeInstallation(localBi);
}
for (BoundarySurface bs : boundarySurfaces) {
bs.unsetGmlGeometries();
}
}
private void removeGeometriesFromBridgeInstallation(BridgeInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null);
}
public void setGmlObject(AbstractInstallation gmlBi) {
this.gmlBi = gmlBi;
}
@Override
public String toString() {
return "BuildingInstallation [id=" + getGmlId() + "]";
}
void anonymize() {
setGmlId(GmlId.generateId());
gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
gmlBi.setId(getGmlId().getGmlString());
for (BoundarySurface bs : boundarySurfaces) {
bs.anonymize();
gmlBi.getBoundaries().add(new AbstractSpaceBoundaryProperty(bs.getGmlObject()));
}
}
@Override
public AbstractInstallation getGmlObject() {
return gmlBi;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.INSTALLATION;
}
public List<BoundarySurface> getBoundarySurfaces() {
if (boundarySurfaces == null) {
boundarySurfaces = new ArrayList<>(4);
}
return boundarySurfaces;
}
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearMetaInformation();
}
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaces) {
bs.prepareForChecking();
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Installation originalBi = (Installation) original;
for (BoundarySurface originalBs : originalBi.boundarySurfaces) {
boundarySurfaces.add(handler.getCopyInstance(originalBs));
}
gmlBi = originalBi.gmlBi;
parent = handler.getCopyInstance(parent);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
for (BoundarySurface bs : boundarySurfaces) {
handler.addInstance(bs);
}
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new Installation();
}
@Serial
private static final long serialVersionUID = 1576237433322680191L;
private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4);
private AbstractInstallation gmlBi;
private CityObject parent;
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
if (ms != null) {
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
}
} else if (geom.getType() == GeometryType.COMPOSITE_SURFACE) {
CompositeSurface cs = CityGmlUtils.createCompositeSurface(geom, factory, config);
if (cs != null) {
setGeometryAccordingToLod(geom.getLod(), new SurfaceProperty(cs));
}
} else {
throw new IllegalStateException("BuildingInstallation not have Solid geometries");
}
}
for (BoundarySurface bs : boundarySurfaces) {
bs.reCreateGeometries(factory, config);
}
}
private void setGeometryAccordingToLod(Lod lod, GeometryProperty<?> ms) {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
addGeometryToBuildingInstallation(lod, ms, localBi);
} else if (gmlBi instanceof BridgeInstallation localBi) {
addGeometryToBridgeInstallation(lod, ms, localBi);
}
}
private void addGeometryToBuildingInstallation(Lod lod, GeometryProperty<?> ms,
org.citygml4j.core.model.building.BuildingInstallation localBi) {
switch (lod) {
case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms);
break;
case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms);
break;
case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms);
break;
default:
throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
}
}
private void addGeometryToBridgeInstallation(Lod lod, GeometryProperty<?> ms, BridgeInstallation localBi) {
switch (lod) {
case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms);
break;
case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms);
break;
case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms);
break;
default:
throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
}
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (BoundarySurface bs : boundarySurfaces) {
bs.accept(c);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaces) {
bs.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
public void setParent(CityObject parent) {
this.parent = parent;
}
public CityObject getParent() {
return parent;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaces.add(bs);
bs.setParent(this);
}
public void unsetGmlGeometries() {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null);
} else if (gmlBi instanceof BridgeInstallation localBi) {
removeGeometriesFromBridgeInstallation(localBi);
}
for (BoundarySurface bs : boundarySurfaces) {
bs.unsetGmlGeometries();
}
}
private void removeGeometriesFromBridgeInstallation(BridgeInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null);
}
public void setGmlObject(AbstractInstallation gmlBi) {
this.gmlBi = gmlBi;
}
@Override
public String toString() {
return "BuildingInstallation [id=" + getGmlId() + "]";
}
void anonymize() {
setGmlId(GmlId.generateId());
gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
gmlBi.setId(getGmlId().getGmlString());
for (BoundarySurface bs : boundarySurfaces) {
bs.anonymize();
gmlBi.getBoundaries().add(new AbstractSpaceBoundaryProperty(bs.getGmlObject()));
}
}
@Override
public AbstractInstallation getGmlObject() {
return gmlBi;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.INSTALLATION;
}
public List<BoundarySurface> getBoundarySurfaces() {
if (boundarySurfaces == null) {
boundarySurfaces = new ArrayList<>(4);
}
return boundarySurfaces;
}
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearMetaInformation();
}
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaces) {
bs.prepareForChecking();
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Installation originalBi = (Installation) original;
for (BoundarySurface originalBs : originalBi.boundarySurfaces) {
boundarySurfaces.add(handler.getCopyInstance(originalBs));
}
gmlBi = originalBi.gmlBi;
parent = handler.getCopyInstance(parent);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
for (BoundarySurface bs : boundarySurfaces) {
handler.addInstance(bs);
}
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new Installation();
}
}
/*-
* 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
......@@ -18,107 +18,105 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.landuse.LandUse;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
/**
* Represents a land use CityGML object.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class LandObject extends CityObject {
@Serial
private static final long serialVersionUID = 1887455662411087326L;
private LandUse lu;
public LandObject(LandUse lu) {
this.lu = lu;
}
@Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
} else {
throw new IllegalStateException("Landuse cannot have solids: " + geom);
}
}
}
@Override
public FeatureType getFeatureType() {
return FeatureType.LAND;
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
lu.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD1:
lu.setLod1MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
lu.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
lu.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
lu.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
}
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public AbstractCityObject getGmlObject() {
return lu;
}
@Override
public void unsetGmlGeometries() {
lu.setLod0MultiSurface(null);
lu.setLod1MultiSurface(null);
lu.setLod2MultiSurface(null);
lu.setLod3MultiSurface(null);
lu.getDeprecatedProperties().setLod4MultiSurface(null);
}
public void setGmlObject(LandUse landUse) {
lu = landUse;
}
@Override
public String toString() {
return "LandObject [id=" + getGmlId() + "]";
}
@Override
public Copyable createCopyInstance() {
return new LandObject(lu);
}
@Serial
private static final long serialVersionUID = 1887455662411087326L;
private LandUse lu;
public LandObject(LandUse lu) {
this.lu = lu;
}
@Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
} else {
throw new IllegalStateException("Landuse cannot have solids: " + geom);
}
}
}
@Override
public FeatureType getFeatureType() {
return FeatureType.LAND;
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
lu.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD1:
lu.setLod1MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
lu.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
lu.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
lu.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
}
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public AbstractCityObject getGmlObject() {
return lu;
}
@Override
public void unsetGmlGeometries() {
lu.setLod0MultiSurface(null);
lu.setLod1MultiSurface(null);
lu.setLod2MultiSurface(null);
lu.setLod3MultiSurface(null);
lu.getDeprecatedProperties().setLod4MultiSurface(null);
}
public void setGmlObject(LandUse landUse) {
lu = landUse;
}
@Override
public String toString() {
return "LandObject [id=" + getGmlId() + "]";
}
@Override
public Copyable createCopyInstance() {
return new LandObject(lu);
}
}
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serial;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Reference object for handling of implicit geometries with a library object contained in an external file
*
* @author Riegel
*/
public class LibraryObject extends Geometry {
private static final Logger logger = LogManager.getLogger(LibraryObject.class);
@Serial
private static final long serialVersionUID = -50293435187454911L;
private final String filepath;
private final ParserConfiguration config;
private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
public static LibraryObject of(Path path, ParserConfiguration config) {
if (libraryObjects.containsKey(path.toString())) {
return libraryObjects.get(path.toString());
}
Geometry protoGeom = parseFile(path, config);
if (protoGeom == null) {
return null;
}
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod(), path, config);
protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices();
libraryObjects.put(path.toString(), libOb);
return libOb;
}
private LibraryObject(GeometryType type, Lod lod, Path path, ParserConfiguration config) {
super(type, lod);
this.filepath = path.toString();
this.config = config;
}
private static Geometry parseFile(Path path, ParserConfiguration config) {
Geometry geo = null;
if (path.toFile().exists()) {
try {
CityGmlParser.gagLogger(true);
CityDoctorModel model = CityGmlParser.parseCityGmlFile(path.toString(), config);
List<CityObject> objects = model.createFeatureStream().toList();
if (objects.isEmpty()) {
throw new InvalidGmlFileException("Referenced library-object's gml file does not contain a CityGML object!");
} else if (objects.size() > 1) {
throw new InvalidGmlFileException("Referenced library-object's gml file contains more than one CityGML object!");
}
geo = objects.get(0).getHighestLodGeometry();
} catch (CityGmlParseException e) {
logger.error(String.format(
"Encountered an error while parsing library object %s", path));
logger.error(e.getStackTrace());
} catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace());
} finally {
// Failsafe to remove gag should parsing fail
CityGmlParser.gagLogger(false);
}
} else {
logger.error(String.format("Implicit geometry references non-existing library object file %s.", path));
}
return geo;
}
}
/*-
* 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
......@@ -18,337 +18,332 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.math.ProjectionAxis;
import de.hft.stuttgart.citydoctor2.math.Ring2d;
import de.hft.stuttgart.citydoctor2.math.UnitVector3d;
import de.hft.stuttgart.citydoctor2.math.Vector2d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.math.*;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a linear ring used in polygons. The ring contains the vertices.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class LinearRing extends GmlElement {
@Serial
private static final long serialVersionUID = -2488180830514940722L;
private LinearRingType type;
private Polygon parent;
private final List<Vertex> vertices = new ArrayList<>();
public enum LinearRingType {
EXTERIOR, INTERIOR
}
public LinearRing(LinearRingType type) {
this.type = type;
}
/**
* Checks whether a point is inside this ring. A point on the edge does count as
* inside.
*
* @param v the point.
* @return true if the point is inside or on an edge, false if it is outside.
*/
public boolean isPointInside(Vector3d v) {
// project to 2d ring
ProjectionAxis axis = ProjectionAxis.of(this);
Vector2d point = axis.project(v);
Ring2d ring = Ring2d.of(this, axis);
int t = -1;
for (int i = 0; i < ring.getVertices().size() - 1; i++) {
t = t * crossProdTest(point, ring.getVertices().get(i), ring.getVertices().get(i + 1));
if (t == 0) {
return true;
}
}
return t >= 0;
}
private int crossProdTest(Vector2d a, Vector2d b, Vector2d c) {
if (a.getY() == b.getY() && a.getY() == c.getY()) {
if ((b.getX() <= a.getX() && a.getX() <= c.getX()) || (c.getX() <= a.getX() && a.getX() <= b.getX())) {
return 0;
} else {
return 1;
}
}
if (a.getY() == b.getY() && a.getX() == b.getX()) {
return 0;
}
if (b.getY() > c.getY()) {
Vector2d temp = b;
b = c;
c = temp;
}
if (a.getY() <= b.getY() || a.getY() > c.getY()) {
return 1;
}
return calculateDelta(a, b, c);
}
private int calculateDelta(Vector2d a, Vector2d b, Vector2d c) {
double delta = (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY()) * (c.getX() - a.getX());
if (delta > 0) {
return -1;
} else if (delta < 0) {
return 1;
} else {
return 0;
}
}
/**
* Calculates the normal vector of the ring. Method by Newell. If the Newell
* method would return a (0, 0, 0) vector a cross product is formed from the
* first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
*
* @return the normal as a normalized vector
*/
public UnitVector3d calculateNormalNormalized() {
return calculateNormal().normalize();
}
/**
* Calculates the normal vector of the ring. Method by Newell. If the Newell
* method would return a (0, 0, 0) vector a cross product is formed from the
* first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
*
* @return the normal vector
*/
public Vector3d calculateNormal() {
double[] coords = new double[3];
for (int i = 0; i < vertices.size() - 1; i++) {
Vertex current = vertices.get(i);
Vertex next = vertices.get(i + 1);
coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY());
coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ());
coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX());
}
if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) {
// no valid normal vector found
if (vertices.size() < 3) {
// no three points, return x-axis
return UnitVector3d.X_AXIS;
}
Vertex v1 = vertices.get(0);
Vertex v2 = vertices.get(1);
Vertex v3 = vertices.get(2);
return calculateNormalWithCross(v1, v2, v3);
}
return new Vector3d(coords);
}
public double getArea() {
int n = vertices.size();
if (n < 3)
return 0.0; // a degenerated polygon
// prepare an vertex array with n+2 vertices:
// V[0] ... V[n-1] - the n different vertices
// V[n]=V[0]
// V[n+1]=V[1]
Vertex[] vertexArray = new Vertex[n + 2];
for (int i = 0; i < n; i++) {
vertexArray[i] = vertices.get(i);
}
vertexArray[n] = vertices.get(0);
vertexArray[n + 1] = vertices.get(1);
double area = 0;
// make sure the normal has been calculated
Vector3d normal = calculateNormal();
// select largest abs coordinate to ignore for projection
double ax = Math.abs(normal.getX()); // abs x-coord
double ay = Math.abs(normal.getY()); // abs y-coord
double az = Math.abs(normal.getZ()); // abs z-coord
// coord to ignore: 1=x, 2=y, 3=z
int coord = 3; // ignore z-coord
if (ax > ay) {
if (ax > az) {
coord = 1; // ignore x-coord
}
} else if (ay > az) {
coord = 2; // ignore y-coord
}
// compute area of the 2D projection
for (int i = 1, j = 2, k = 0; i <= vertexArray.length - 2; i++, j++, k++) {
switch (coord) {
case 1:
area += (vertexArray[i].getY() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break;
case 2:
area += (vertexArray[i].getX() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break;
case 3:
area += (vertexArray[i].getX() * (vertexArray[j].getY() - vertexArray[k].getY()));
break;
default:
throw new IllegalStateException();
}
}
// scale to get area before projection
double an = Math.sqrt(ax * ax + ay * ay + az * az); // length of normal vector
switch (coord) {
case 1:
area *= (an / (2 * ax));
break;
case 2:
area *= (an / (2 * ay));
break;
case 3:
area *= (an / (2 * az));
break;
default:
throw new IllegalStateException();
}
return Math.abs(area);
}
private UnitVector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) {
Vector3d dir1 = v2.minus(v1);
Vector3d dir2 = v3.minus(v1);
Vector3d cross = dir1.cross(dir2);
return cross.normalize();
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
}
public void setParent(Polygon polygon) {
parent = polygon;
}
public Polygon getParent() {
return parent;
}
public LinearRingType getType() {
return type;
}
public List<Vertex> getVertices() {
return vertices;
}
public void addVertex(Vertex v) {
vertices.add(v);
if (parent == null) {
return;
}
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
public void addVertex(int i, Vertex v) {
vertices.add(i, v);
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
public void setVertex(int i, Vertex v) {
vertices.set(i, v);
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
@Override
public String toString() {
return "LinearRing [type=" + type + ", gmlId=" + getGmlId() + "]";
}
void anonymize() {
setGmlId(GmlId.generateId());
}
public boolean isRingConnectedViaPoint(LinearRing other) {
for (Vertex v : vertices) {
if (other.getVertices().contains(v)) {
return true;
}
}
return false;
}
public boolean hasPointAsCorner(Vertex v) {
return vertices.contains(v);
}
public void setType(LinearRingType type) {
this.type = type;
}
public void addAllVertices(List<Vertex> extRing) {
vertices.addAll(extRing);
}
@Override
public void prepareForChecking() {
parent.getParent().prepareForChecking();
}
@Override
public void clearMetaInformation() {
parent.getParent().clearMetaInformation();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
LinearRing originalRing = (LinearRing) original;
type = originalRing.type;
parent = handler.getCopyInstance(originalRing.parent);
for (Vertex v : originalRing.vertices) {
vertices.add(handler.getCopyInstance(v));
}
}
@Override
public void collectInstances(CopyHandler handler) {
for (Vertex v : vertices) {
handler.addInstance(v);
}
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new LinearRing(type);
}
@Serial
private static final long serialVersionUID = -2488180830514940722L;
private LinearRingType type;
private Polygon parent;
private final List<Vertex> vertices = new ArrayList<>();
public enum LinearRingType {
EXTERIOR, INTERIOR
}
public LinearRing(LinearRingType type) {
this.type = type;
}
/**
* Checks whether a point is inside this ring. A point on the edge does count as
* inside.
*
* @param v the point.
* @return true if the point is inside or on an edge, false if it is outside.
*/
public boolean isPointInside(Vector3d v) {
// project to 2d ring
ProjectionAxis axis = ProjectionAxis.of(this);
Vector2d point = axis.project(v);
Ring2d ring = Ring2d.of(this, axis);
int t = -1;
for (int i = 0; i < ring.getVertices().size() - 1; i++) {
t = t * crossProdTest(point, ring.getVertices().get(i), ring.getVertices().get(i + 1));
if (t == 0) {
return true;
}
}
return t >= 0;
}
private int crossProdTest(Vector2d a, Vector2d b, Vector2d c) {
if (a.getY() == b.getY() && a.getY() == c.getY()) {
if ((b.getX() <= a.getX() && a.getX() <= c.getX()) || (c.getX() <= a.getX() && a.getX() <= b.getX())) {
return 0;
} else {
return 1;
}
}
if (a.getY() == b.getY() && a.getX() == b.getX()) {
return 0;
}
if (b.getY() > c.getY()) {
Vector2d temp = b;
b = c;
c = temp;
}
if (a.getY() <= b.getY() || a.getY() > c.getY()) {
return 1;
}
return calculateDelta(a, b, c);
}
private int calculateDelta(Vector2d a, Vector2d b, Vector2d c) {
double delta = (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY()) * (c.getX() - a.getX());
if (delta > 0) {
return -1;
} else if (delta < 0) {
return 1;
} else {
return 0;
}
}
/**
* Calculates the normal vector of the ring. Method by Newell. If the Newell
* method would return a (0, 0, 0) vector a cross product is formed from the
* first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
*
* @return the normal as a normalized vector
*/
public UnitVector3d calculateNormalNormalized() {
return calculateNormal().normalize();
}
/**
* Calculates the normal vector of the ring. Method by Newell. If the Newell
* method would return a (0, 0, 0) vector a cross product is formed from the
* first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
*
* @return the normal vector
*/
public Vector3d calculateNormal() {
double[] coords = new double[3];
for (int i = 0; i < vertices.size() - 1; i++) {
Vertex current = vertices.get(i);
Vertex next = vertices.get(i + 1);
coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY());
coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ());
coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX());
}
if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) {
// no valid normal vector found
if (vertices.size() < 3) {
// no three points, return x-axis
return UnitVector3d.X_AXIS;
}
Vertex v1 = vertices.get(0);
Vertex v2 = vertices.get(1);
Vertex v3 = vertices.get(2);
return calculateNormalWithCross(v1, v2, v3);
}
return new Vector3d(coords);
}
public double getArea() {
int n = vertices.size();
if (n < 3)
return 0.0; // a degenerated polygon
// prepare an vertex array with n+2 vertices:
// V[0] ... V[n-1] - the n different vertices
// V[n]=V[0]
// V[n+1]=V[1]
Vertex[] vertexArray = new Vertex[n + 2];
for (int i = 0; i < n; i++) {
vertexArray[i] = vertices.get(i);
}
vertexArray[n] = vertices.get(0);
vertexArray[n + 1] = vertices.get(1);
double area = 0;
// make sure the normal has been calculated
Vector3d normal = calculateNormal();
// select largest abs coordinate to ignore for projection
double ax = Math.abs(normal.getX()); // abs x-coord
double ay = Math.abs(normal.getY()); // abs y-coord
double az = Math.abs(normal.getZ()); // abs z-coord
// coord to ignore: 1=x, 2=y, 3=z
int coord = 3; // ignore z-coord
if (ax > ay) {
if (ax > az) {
coord = 1; // ignore x-coord
}
} else if (ay > az) {
coord = 2; // ignore y-coord
}
// compute area of the 2D projection
for (int i = 1, j = 2, k = 0; i <= vertexArray.length - 2; i++, j++, k++) {
switch (coord) {
case 1:
area += (vertexArray[i].getY() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break;
case 2:
area += (vertexArray[i].getX() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break;
case 3:
area += (vertexArray[i].getX() * (vertexArray[j].getY() - vertexArray[k].getY()));
break;
default:
throw new IllegalStateException();
}
}
// scale to get area before projection
double an = Math.sqrt(ax * ax + ay * ay + az * az); // length of normal vector
switch (coord) {
case 1:
area *= (an / (2 * ax));
break;
case 2:
area *= (an / (2 * ay));
break;
case 3:
area *= (an / (2 * az));
break;
default:
throw new IllegalStateException();
}
return Math.abs(area);
}
private UnitVector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) {
Vector3d dir1 = v2.minus(v1);
Vector3d dir2 = v3.minus(v1);
Vector3d cross = dir1.cross(dir2);
return cross.normalize();
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
}
public void setParent(Polygon polygon) {
parent = polygon;
}
public Polygon getParent() {
return parent;
}
public LinearRingType getType() {
return type;
}
public List<Vertex> getVertices() {
return vertices;
}
public void addVertex(Vertex v) {
vertices.add(v);
if (parent == null) {
return;
}
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
public void addVertex(int i, Vertex v) {
vertices.add(i, v);
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
public void setVertex(int i, Vertex v) {
vertices.set(i, v);
if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
}
v.addAdjacentRing(this, parent.getParent());
}
@Override
public String toString() {
return "LinearRing [type=" + type + ", gmlId=" + getGmlId() + "]";
}
void anonymize() {
setGmlId(GmlId.generateId());
}
public boolean isRingConnectedViaPoint(LinearRing other) {
for (Vertex v : vertices) {
if (other.getVertices().contains(v)) {
return true;
}
}
return false;
}
public boolean hasPointAsCorner(Vertex v) {
return vertices.contains(v);
}
public void setType(LinearRingType type) {
this.type = type;
}
public void addAllVertices(List<Vertex> extRing) {
vertices.addAll(extRing);
}
@Override
public void prepareForChecking() {
parent.getParent().prepareForChecking();
}
@Override
public void clearMetaInformation() {
parent.getParent().clearMetaInformation();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
LinearRing originalRing = (LinearRing) original;
type = originalRing.type;
parent = handler.getCopyInstance(originalRing.parent);
for (Vertex v : originalRing.vertices) {
vertices.add(handler.getCopyInstance(v));
}
}
@Override
public void collectInstances(CopyHandler handler) {
for (Vertex v : vertices) {
handler.addInstance(v);
}
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new LinearRing(type);
}
}
/*-
* 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
......@@ -18,10 +18,6 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.List;
import java.util.Map;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
......@@ -31,275 +27,277 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial;
import java.util.List;
import java.util.Map;
/**
* A polygon that does not contain the geometry but is only a link to an actual
* polygon. Created when href in CityGML are used.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class LinkedPolygon extends Polygon {
@Serial
private static final long serialVersionUID = -4897578390280277931L;
private Geometry parent;
private ConcretePolygon poly;
private LinkedPolygon() {
}
/**
*
* @param poly polygon this is linked to
* @param parent the parent of the linked polygon
*/
public LinkedPolygon(ConcretePolygon poly, Geometry parent) {
this.parent = parent;
this.poly = poly;
poly.setLinkedTo(this);
for (Vertex v : poly.getExteriorRing().getVertices()) {
v.addAdjacentRing(poly.getExteriorRing(), parent);
}
for (LinearRing lr : poly.getInnerRings()) {
for (Vertex v : lr.getVertices()) {
v.addAdjacentRing(lr, parent);
}
}
}
@Override
public CheckResult getCheckResult(Check c) {
return poly.getCheckResult(c);
}
@Override
public Map<CheckId, CheckResult> getAllCheckResults() {
return poly.getAllCheckResults();
}
@Override
public boolean hasAnyError() {
return poly.hasAnyError();
}
@Override
public boolean hasDependencyNotMetError(CheckId id) {
return poly.hasDependencyNotMetError(id);
}
@Override
public CheckResult getCheckResult(CheckId id) {
return poly.getCheckResult(id);
}
@Override
public boolean hasCheckResults() {
return poly.hasCheckResults();
}
@Override
public void setGmlId(GmlId id) {
poly.setGmlId(id);
}
@Override
public GmlId getGmlId() {
return poly.getGmlId();
}
@Override
public void accept(Check c) {
// linked polygons are not checked
setValidated(true);
}
@Override
public void addCheckResult(CheckResult cr) {
poly.addCheckResult(cr);
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
poly.collectContainedErrors(errors);
}
@Override
public boolean containsAnyError() {
return poly.containsAnyError();
}
@Override
public boolean containsError(CheckId checkIdentifier) {
return poly.containsError(checkIdentifier);
}
@Override
public void clearCheckResults() {
poly.clearCheckResults();
}
@Override
public Vector3d calculateNormalNormalized() {
return poly.calculateNormalNormalized();
}
@Override
public Vector3d calculateNormal() {
return poly.calculateNormal();
}
@Override
public TesselatedPolygon tesselate() {
return poly.tesselate();
}
@Override
public LinearRing getExteriorRing() {
return poly.getExteriorRing();
}
@Override
public List<LinearRing> getInnerRings() {
return poly.getInnerRings();
}
@Override
public boolean isPointInsideExteriorRing(Vector3d v) {
return poly.isPointInsideExteriorRing(v);
}
@Override
public Geometry getParent() {
return parent;
}
@Override
public void setParent(Geometry geometry) {
this.parent = geometry;
}
@Override
public void setExteriorRing(LinearRing extRing) {
poly.setExteriorRing(extRing);
}
@Override
public boolean isPolygonConnectedViaPoint(Polygon other) {
return poly.isPolygonConnectedViaPoint(other);
}
@Override
public String toString() {
return "LinkedPolygon [" + poly.getGmlId() + "]";
}
@Override
public void addInteriorRing(LinearRing inter) {
poly.addInteriorRing(inter);
}
@Override
public BoundarySurface getPartOfSurface() {
return poly.getPartOfSurface();
}
@Override
public void setPartOfSurface(BoundarySurface bs) {
poly.setPartOfSurface(bs);
}
@Override
public void removeInnerRing(LinearRing ring) {
poly.removeInnerRing(ring);
}
@Override
public void setPartOfInstallation(Installation bi) {
poly.setPartOfInstallation(bi);
}
@Override
public Installation getPartOfInstallation() {
return poly.getPartOfInstallation();
}
@Override
public boolean hasPointAsCorner(Vertex v) {
return poly.hasPointAsCorner(v);
}
@Override
public void removeRings() {
poly.removeRings();
}
@Override
public boolean isLink() {
return true;
}
@Override
public LinkedPolygon getLinkedFromPolygon() {
return this;
}
@Override
void anonymize() {
poly.anonymize();
}
@Override
public void clearAllContainedCheckResults() {
poly.clearAllContainedCheckResults();
}
@Override
public ConcretePolygon getOriginal() {
return poly;
}
@Override
public void prepareForChecking() {
poly.prepareForChecking();
}
@Override
public void clearMetaInformation() {
poly.clearMetaInformation();
}
@Override
public boolean isLinkedTo() {
return false;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(parent);
handler.addInstance(poly);
}
@Override
public Copyable createCopyInstance() {
return new LinkedPolygon();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
LinkedPolygon linkedOriginal = (LinkedPolygon) original;
parent = handler.getCopyInstance(linkedOriginal.parent);
poly = handler.getCopyInstance(linkedOriginal.poly);
}
@Override
public void remove() {
poly.remove();
}
@Override
public double getArea() {
return poly.getArea();
}
@Serial
private static final long serialVersionUID = -4897578390280277931L;
private Geometry parent;
private ConcretePolygon poly;
private LinkedPolygon() {
}
/**
* @param poly polygon this is linked to
* @param parent the parent of the linked polygon
*/
public LinkedPolygon(ConcretePolygon poly, Geometry parent) {
this.parent = parent;
this.poly = poly;
poly.setLinkedTo(this);
for (Vertex v : poly.getExteriorRing().getVertices()) {
v.addAdjacentRing(poly.getExteriorRing(), parent);
}
for (LinearRing lr : poly.getInnerRings()) {
for (Vertex v : lr.getVertices()) {
v.addAdjacentRing(lr, parent);
}
}
}
@Override
public CheckResult getCheckResult(Check c) {
return poly.getCheckResult(c);
}
@Override
public Map<CheckId, CheckResult> getAllCheckResults() {
return poly.getAllCheckResults();
}
@Override
public boolean hasAnyError() {
return poly.hasAnyError();
}
@Override
public boolean hasDependencyNotMetError(CheckId id) {
return poly.hasDependencyNotMetError(id);
}
@Override
public CheckResult getCheckResult(CheckId id) {
return poly.getCheckResult(id);
}
@Override
public boolean hasCheckResults() {
return poly.hasCheckResults();
}
@Override
public void setGmlId(GmlId id) {
poly.setGmlId(id);
}
@Override
public GmlId getGmlId() {
return poly.getGmlId();
}
@Override
public void accept(Check c) {
// linked polygons are not checked
setValidated(true);
}
@Override
public void addCheckResult(CheckResult cr) {
poly.addCheckResult(cr);
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
poly.collectContainedErrors(errors);
}
@Override
public boolean containsAnyError() {
return poly.containsAnyError();
}
@Override
public boolean containsError(CheckId checkIdentifier) {
return poly.containsError(checkIdentifier);
}
@Override
public void clearCheckResults() {
poly.clearCheckResults();
}
@Override
public Vector3d calculateNormalNormalized() {
return poly.calculateNormalNormalized();
}
@Override
public Vector3d calculateNormal() {
return poly.calculateNormal();
}
@Override
public TesselatedPolygon tesselate() {
return poly.tesselate();
}
@Override
public LinearRing getExteriorRing() {
return poly.getExteriorRing();
}
@Override
public List<LinearRing> getInnerRings() {
return poly.getInnerRings();
}
@Override
public boolean isPointInsideExteriorRing(Vector3d v) {
return poly.isPointInsideExteriorRing(v);
}
@Override
public Geometry getParent() {
return parent;
}
@Override
public void setParent(Geometry geometry) {
this.parent = geometry;
}
@Override
public void setExteriorRing(LinearRing extRing) {
poly.setExteriorRing(extRing);
}
@Override
public boolean isPolygonConnectedViaPoint(Polygon other) {
return poly.isPolygonConnectedViaPoint(other);
}
@Override
public String toString() {
return "LinkedPolygon [" + poly.getGmlId() + "]";
}
@Override
public void addInteriorRing(LinearRing inter) {
poly.addInteriorRing(inter);
}
@Override
public BoundarySurface getPartOfSurface() {
return poly.getPartOfSurface();
}
@Override
public void setPartOfSurface(BoundarySurface bs) {
poly.setPartOfSurface(bs);
}
@Override
public void removeInnerRing(LinearRing ring) {
poly.removeInnerRing(ring);
}
@Override
public void setPartOfInstallation(Installation bi) {
poly.setPartOfInstallation(bi);
}
@Override
public Installation getPartOfInstallation() {
return poly.getPartOfInstallation();
}
@Override
public boolean hasPointAsCorner(Vertex v) {
return poly.hasPointAsCorner(v);
}
@Override
public void removeRings() {
poly.removeRings();
}
@Override
public boolean isLink() {
return true;
}
@Override
public LinkedPolygon getLinkedFromPolygon() {
return this;
}
@Override
void anonymize() {
poly.anonymize();
}
@Override
public void clearAllContainedCheckResults() {
poly.clearAllContainedCheckResults();
}
@Override
public ConcretePolygon getOriginal() {
return poly;
}
@Override
public void prepareForChecking() {
poly.prepareForChecking();
}
@Override
public void clearMetaInformation() {
poly.clearMetaInformation();
}
@Override
public boolean isLinkedTo() {
return false;
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(parent);
handler.addInstance(poly);
}
@Override
public Copyable createCopyInstance() {
return new LinkedPolygon();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
LinkedPolygon linkedOriginal = (LinkedPolygon) original;
parent = handler.getCopyInstance(linkedOriginal.parent);
poly = handler.getCopyInstance(linkedOriginal.poly);
}
@Override
public void remove() {
poly.remove();
}
@Override
public double getArea() {
return poly.getArea();
}
}
/*-
* 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
......@@ -20,24 +20,23 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/**
* The different LODs available in CityGML
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public enum Lod {
LOD0(0), LOD1(1), LOD2(2), LOD3(3), LOD4(4);
LOD0(0), LOD1(1), LOD2(2), LOD3(3), LOD4(4);
private final int rank;
private final int rank;
private Lod(int rank) {
this.rank = rank;
}
private Lod(int rank) {
this.rank = rank;
}
public boolean isHigher(Lod other) {
if (other == null) {
return true;
}
return rank > other.rank;
}
public boolean isHigher(Lod other) {
if (other == null) {
return true;
}
return rank > other.rank;
}
}
/*-
* 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
......@@ -18,17 +18,16 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import org.citygml4j.core.model.construction.AbstractFillingSurface;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.construction.AbstractFillingSurface;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import java.io.Serial;
......@@ -36,145 +35,144 @@ import java.io.Serial;
* Represents an Opening suchs a window or Door in a surface of a feature.
* Contains a reference to the boundary surface where this opening is embedded
* in.
*
* @author Matthias Betz
*
* @author Matthias Betz
*/
public class Opening extends CityObject {
@Serial
private static final long serialVersionUID = 6409303152284607944L;
private BoundarySurface partOf;
private OpeningType type;
private SurfaceFeatureType featureType;
private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
AbstractFillingSurface ao) {
this.featureType = featureType;
this.partOf = partOf;
this.type = type;
this.ao = ao;
}
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
if (ao.getId() != null) {
ao.setId(getGmlId().getGmlString());
}
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
} else {
throw new IllegalStateException("Openings can only have MultiSurface geometries");
}
}
}
private void setGeometryAccordingToLod(Lod lod, MultiSurfaceProperty ms) {
switch (lod) {
case LOD0:
ao.setLod0MultiSurface(ms);
break;
case LOD1:
ao.setLod1MultiSurface(ms);
break;
case LOD2:
ao.setLod2MultiSurface(ms);
break;
case LOD3:
ao.setLod3MultiSurface(ms);
break;
case LOD4:
ao.getDeprecatedProperties().setLod4MultiSurface(ms);
break;
default:
throw new IllegalStateException("Cannot add geometry to opening because lod is not allowed: " + lod);
}
}
public SurfaceFeatureType getSurfaceFeatureType() {
return featureType;
}
public BoundarySurface getPartOf() {
return partOf;
}
public void setType(OpeningType type) {
this.type = type;
}
public OpeningType getType() {
return type;
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
}
public void unsetGmlGeometries() {
ao.setLod0MultiSurface(null);
ao.setLod1MultiSurface(null);
ao.setLod2MultiSurface(null);
ao.setLod3MultiSurface(null);
ao.getDeprecatedProperties().setLod4MultiSurface(null);
}
@Override
public String toString() {
return "Opening [type=" + type + ", id=" + getGmlId() + "]";
}
public void setPartOfSurface(BoundarySurface boundarySurface) {
partOf = boundarySurface;
}
@Override
public AbstractCityObject getGmlObject() {
return ao;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.OPENING;
}
@Override
public Copyable createCopyInstance() {
return new Opening(type);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(partOf);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Opening originalOpening = (Opening) original;
partOf = handler.getCopyInstance(originalOpening.partOf);
type = originalOpening.type;
featureType = originalOpening.featureType;
ao = originalOpening.ao;
}
@Serial
private static final long serialVersionUID = 6409303152284607944L;
private BoundarySurface partOf;
private OpeningType type;
private SurfaceFeatureType featureType;
private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
AbstractFillingSurface ao) {
this.featureType = featureType;
this.partOf = partOf;
this.type = type;
this.ao = ao;
}
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
if (ao.getId() != null) {
ao.setId(getGmlId().getGmlString());
}
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
} else {
throw new IllegalStateException("Openings can only have MultiSurface geometries");
}
}
}
private void setGeometryAccordingToLod(Lod lod, MultiSurfaceProperty ms) {
switch (lod) {
case LOD0:
ao.setLod0MultiSurface(ms);
break;
case LOD1:
ao.setLod1MultiSurface(ms);
break;
case LOD2:
ao.setLod2MultiSurface(ms);
break;
case LOD3:
ao.setLod3MultiSurface(ms);
break;
case LOD4:
ao.getDeprecatedProperties().setLod4MultiSurface(ms);
break;
default:
throw new IllegalStateException("Cannot add geometry to opening because lod is not allowed: " + lod);
}
}
public SurfaceFeatureType getSurfaceFeatureType() {
return featureType;
}
public BoundarySurface getPartOf() {
return partOf;
}
public void setType(OpeningType type) {
this.type = type;
}
public OpeningType getType() {
return type;
}
@Override
public void accept(Check c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
}
public void unsetGmlGeometries() {
ao.setLod0MultiSurface(null);
ao.setLod1MultiSurface(null);
ao.setLod2MultiSurface(null);
ao.setLod3MultiSurface(null);
ao.getDeprecatedProperties().setLod4MultiSurface(null);
}
@Override
public String toString() {
return "Opening [type=" + type + ", id=" + getGmlId() + "]";
}
public void setPartOfSurface(BoundarySurface boundarySurface) {
partOf = boundarySurface;
}
@Override
public AbstractCityObject getGmlObject() {
return ao;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.OPENING;
}
@Override
public Copyable createCopyInstance() {
return new Opening(type);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(partOf);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Opening originalOpening = (Opening) original;
partOf = handler.getCopyInstance(originalOpening.partOf);
type = originalOpening.type;
featureType = originalOpening.featureType;
ao = originalOpening.ao;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment