Commit 0f3d9a85 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

CityDoctor Release Version 3.16.0

See merge request !11
parents b7b8f5fe b2d40f78
Pipeline #10323 passed with stage
in 1 minute and 25 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 * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,184 +18,191 @@ ...@@ -18,184 +18,191 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; 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, ... * Abstract class for general features such as Buildings, Water objects, ...
* <br> * <br>
* Contains the geometries * Contains the geometries
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public abstract class CityObject extends GmlElement { public abstract class CityObject extends GmlElement {
@Serial @Serial
private static final long serialVersionUID = 651712070755024188L; private static final long serialVersionUID = 651712070755024188L;
private final List<Geometry> geometryList = new ArrayList<>(); 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 * Recreates the CityGML4j geometry in this object. The CityGML4j geometry is
* deleted from the data structure as was mapped to the city doctor data * 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 * structure. For writing CityGML files the geometry has to be restored. Also
* maps changes to geometry back to CityGML4j * maps changes to geometry back to CityGML4j
* *
* @param factory needed to create CityGML4j data structures * @param factory needed to create CityGML4j data structures
* @param config contains information whether a city doctor point was * @param config contains information whether a city doctor point was
* transformed to a different coordinate system. It would need to * transformed to a different coordinate system. It would need to
* be transformed to the original coordinate system * be transformed to the original coordinate system
*/ */
public abstract void reCreateGeometries(GeometryFactory factory, ParserConfiguration config); public abstract void reCreateGeometries(GeometryFactory factory, ParserConfiguration config);
/** /**
* Getter for the CityGML4j data object * Getter for the CityGML4j data object
* *
* @return the CityGML4j data object * @return the CityGML4j data object
*/ */
public abstract AbstractCityObject getGmlObject(); public abstract AbstractCityObject getGmlObject();
/** /**
* Remove the CityGML4j geometries from the data structure to save memory. * Remove the CityGML4j geometries from the data structure to save memory.
*/ */
public abstract void unsetGmlGeometries(); public abstract void unsetGmlGeometries();
public void addGeometry(Geometry geom) { public void addGeometry(Geometry geom) {
Objects.requireNonNull(geom); Objects.requireNonNull(geom);
geometryList.add(geom); geometryList.add(geom);
geom.setParent(this); geom.setParent(this);
} }
public List<Geometry> getGeometries() {
return geometryList; public List<Geometry> getGeometries() {
} return geometryList;
}
public void removeGeometry(Lod lod) {
public void removeGeometry(Lod lod) {
geometryList.removeIf(geom -> geom.getLod() == 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); geometryList.removeIf(geom -> geom.getLod() == lod && geom.getType() == type);
} }
public Geometry getHighestLodGeometry() { public Geometry getHighestLodGeometry() {
Geometry highestLodGeometry = null; Geometry highestLodGeometry = null;
Lod highestLod = null; Lod highestLod = null;
for (Geometry geom : geometryList) { for (Geometry geom : geometryList) {
if (highestLod == null || geom.getLod().isHigher(highestLod)) { if (highestLod == null || geom.getLod().isHigher(highestLod)) {
highestLodGeometry = geom; highestLodGeometry = geom;
highestLod = geom.getLod(); highestLod = geom.getLod();
} }
} }
return highestLodGeometry; return highestLodGeometry;
} }
public abstract FeatureType getFeatureType(); public void addGenericAttribute(GenericAttribute genericAttribute) {
genericAttributeList.add(genericAttribute);
@Override }
public void accept(Check c) {
super.accept(c); public List<GenericAttribute> getGenericAttributes() {
if (c.canExecute(this)) { return genericAttributeList;
c.check(this); }
}
for (Geometry geom : geometryList) { public abstract FeatureType getFeatureType();
geom.accept(c);
} @Override
} public void accept(Check c) {
super.accept(c);
@Override if (c.canExecute(this)) {
public boolean containsError(CheckId checkIdentifier) { c.check(this);
boolean hasError = super.containsError(checkIdentifier); }
if (hasError) { for (Geometry geom : geometryList) {
return true; geom.accept(c);
} }
for (Geometry geom : geometryList) { }
if (geom.containsError(checkIdentifier)) {
return true; @Override
} public boolean containsError(CheckId checkIdentifier) {
} boolean hasError = super.containsError(checkIdentifier);
return false; if (hasError) {
} return true;
}
@Override for (Geometry geom : geometryList) {
public void clearAllContainedCheckResults() { if (geom.containsError(checkIdentifier)) {
super.clearCheckResults(); return true;
for (Geometry geom : geometryList) { }
geom.clearAllContainedCheckResults(); }
} return false;
} }
@Override @Override
public void collectContainedErrors(List<CheckError> errors) { public void clearAllContainedCheckResults() {
super.collectContainedErrors(errors); super.clearCheckResults();
for (Geometry geom : geometryList) { for (Geometry geom : geometryList) {
geom.collectContainedErrors(errors); geom.clearAllContainedCheckResults();
} }
} }
@Override @Override
public boolean containsAnyError() { public void collectContainedErrors(List<CheckError> errors) {
boolean hasError = super.containsAnyError(); super.collectContainedErrors(errors);
if (hasError) { for (Geometry geom : geometryList) {
return true; geom.collectContainedErrors(errors);
} }
for (Geometry geom : geometryList) { }
if (geom.containsAnyError()) {
return true; @Override
} public boolean containsAnyError() {
} boolean hasError = super.containsAnyError();
return false; if (hasError) {
} return true;
}
public Geometry getGeometry(GeometryType type, Lod lod) { for (Geometry geom : geometryList) {
for (Geometry geom : geometryList) { if (geom.containsAnyError()) {
if (geom.getType() == type && geom.getLod() == lod) { return true;
return geom; }
} }
} return false;
return null; }
}
public Geometry getGeometry(GeometryType type, Lod lod) {
@Override for (Geometry geom : geometryList) {
public void prepareForChecking() { if (geom.getType() == type && geom.getLod() == lod) {
for (Geometry geom : geometryList) { return geom;
geom.prepareForChecking(); }
} }
} return null;
}
@Override
public void clearMetaInformation() { @Override
for (Geometry geom : geometryList) { public void prepareForChecking() {
geom.clearMetaInformation(); for (Geometry geom : geometryList) {
} geom.prepareForChecking();
} }
}
@Override
public void collectInstances(CopyHandler handler) { @Override
for (Geometry geom : geometryList) { public void clearMetaInformation() {
handler.addInstance(geom); for (Geometry geom : geometryList) {
} geom.clearMetaInformation();
} }
}
@Override
public void fillValues(Copyable original, CopyHandler handler) { @Override
super.fillValues(original, handler); public void collectInstances(CopyHandler handler) {
CityObject originalCo = (CityObject) original; for (Geometry geom : geometryList) {
for (Geometry geom : originalCo.geometryList) { handler.addInstance(geom);
geometryList.add(handler.getCopyInstance(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 @@ ...@@ -18,11 +18,6 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
...@@ -33,6 +28,11 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; ...@@ -33,6 +28,11 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; 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 * A polygon that actually contains the rings and points representing the
* geometry * geometry
...@@ -49,12 +49,11 @@ public class ConcretePolygon extends Polygon { ...@@ -49,12 +49,11 @@ public class ConcretePolygon extends Polygon {
private List<LinearRing> innerRings; private List<LinearRing> innerRings;
private BoundarySurface partOfSurface; private BoundarySurface partOfSurface;
private Installation partfOfInstallation; private Installation partfOfInstallation;
private CompositeCollection partOfComposite = null;
private Geometry parent; private Geometry parent;
private LinkedPolygon linkedFromPolygon; private LinkedPolygon linkedFromPolygon;
public ConcretePolygon() { public ConcretePolygon() {}
// TODO Auto-generated constructor stub
}
/* /*
* (non-Javadoc) * (non-Javadoc)
...@@ -138,6 +137,18 @@ public class ConcretePolygon extends Polygon { ...@@ -138,6 +137,18 @@ public class ConcretePolygon extends Polygon {
parent = geometry; parent = geometry;
} }
protected void setPartOfComposite(CompositeCollection comp) {
this.partOfComposite = comp;
}
public CompositeCollection getPartOfComposite() {
return partOfComposite;
}
public boolean isCompositeMember() {
return (partOfComposite != null);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
......
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,202 +18,201 @@ ...@@ -18,202 +18,201 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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 * Representing an edge between two consecutive points of a linear ring
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class Edge implements Serializable, Copyable { public class Edge implements Serializable, Copyable {
@Serial @Serial
private static final long serialVersionUID = -504694863498128296L; private static final long serialVersionUID = -504694863498128296L;
private final List<Polygon> adjacentPolygons = new ArrayList<>(2); private final List<Polygon> adjacentPolygons = new ArrayList<>(2);
private final List<LinearRing> adjacentRings = new ArrayList<>(2); private final List<LinearRing> adjacentRings = new ArrayList<>(2);
private Vertex from; private Vertex from;
private Vertex to; private Vertex to;
// start with 1 for a new edge // start with 1 for a new edge
private int numberOfHalfEdges = 1; private int numberOfHalfEdges = 1;
private int numberOfOppositeHalfEdges; private int numberOfOppositeHalfEdges;
public Edge(Vertex from, Vertex to) { public Edge(Vertex from, Vertex to) {
this.from = from; this.from = from;
this.to = to; this.to = to;
} }
private Edge() { private Edge() {
} }
public Vertex getFrom() { public Vertex getFrom() {
return from; return from;
} }
public Vertex getTo() { public Vertex getTo() {
return to; return to;
} }
public void addHalfEdge(Vertex v0, Vertex v1) { public void addHalfEdge(Vertex v0, Vertex v1) {
if (v0 == null || v1 == null) { if (v0 == null || v1 == null) {
return; return;
} }
if (isPointOfEdge(v0, from) && isPointOfEdge(v1, to)) { if (isPointOfEdge(v0, from) && isPointOfEdge(v1, to)) {
numberOfHalfEdges++; numberOfHalfEdges++;
return; return;
} }
if (isPointOfEdge(v1, from) && isPointOfEdge(v0, to)) { if (isPointOfEdge(v1, from) && isPointOfEdge(v0, to)) {
numberOfOppositeHalfEdges++; numberOfOppositeHalfEdges++;
return; return;
} }
throw new IllegalStateException( throw new IllegalStateException(
"The given vertices do not form this edge\n v0=" + v0 + ", v1=" + v1 + ", edge" + this); "The given vertices do not form this edge\n v0=" + v0 + ", v1=" + v1 + ", edge" + this);
} }
private boolean isPointOfEdge(Vertex v0, Vertex edgePoint) { private boolean isPointOfEdge(Vertex v0, Vertex edgePoint) {
return v0.equals(edgePoint); return v0.equals(edgePoint);
} }
public boolean formedByIgnoreDirection(Vertex v1, Vertex v2) { public boolean formedByIgnoreDirection(Vertex v1, Vertex v2) {
return (v1 == from && v2 == to) || (v1 == to && v2 == from); return (v1 == from && v2 == to) || (v1 == to && v2 == from);
} }
public boolean equalsIgnoreDirection(Edge other) { public boolean equalsIgnoreDirection(Edge other) {
return (other.from.equals(from) && other.to.equals(to)) || (other.from.equals(to) && other.to.equals(from)); return (other.from.equals(from) && other.to.equals(to)) || (other.from.equals(to) && other.to.equals(from));
} }
public int getNumberOfHalfEdges() { public int getNumberOfHalfEdges() {
return numberOfHalfEdges; return numberOfHalfEdges;
} }
public int getNumberOppositeHalfEdges() { public int getNumberOppositeHalfEdges() {
return numberOfOppositeHalfEdges; return numberOfOppositeHalfEdges;
} }
public int getNumberOfAllHalfEdges() { public int getNumberOfAllHalfEdges() {
return numberOfHalfEdges + numberOfOppositeHalfEdges; return numberOfHalfEdges + numberOfOppositeHalfEdges;
} }
public List<Polygon> getAdjacentPolygons() { public List<Polygon> getAdjacentPolygons() {
return adjacentPolygons; return adjacentPolygons;
} }
public List<LinearRing> getAdjacentRings() { public List<LinearRing> getAdjacentRings() {
return adjacentRings; return adjacentRings;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((from == null) ? 0 : from.hashCode()); result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((to == null) ? 0 : to.hashCode()); result = prime * result + ((to == null) ? 0 : to.hashCode());
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
Edge other = (Edge) obj; Edge other = (Edge) obj;
if (from == null) { if (from == null) {
if (other.from != null) { if (other.from != null) {
return false; return false;
} }
} else if (!from.equals(other.from)) { } else if (!from.equals(other.from)) {
return false; return false;
} }
if (to == null) { if (to == null) {
return other.to == null; return other.to == null;
} else return to.equals(other.to); } else return to.equals(other.to);
} }
public void addAdjacentPolygon(Polygon p) { public void addAdjacentPolygon(Polygon p) {
adjacentPolygons.add(p); adjacentPolygons.add(p);
} }
public void addAdjacentRing(LinearRing lr) { public void addAdjacentRing(LinearRing lr) {
adjacentRings.add(lr); adjacentRings.add(lr);
} }
@Override @Override
public String toString() { public String toString() {
return "Edge [from=" + from + ", to=" + to + "]"; return "Edge [from=" + from + ", to=" + to + "]";
} }
public boolean contains(Vertex v) { public boolean contains(Vertex v) {
return v == from || v == to; return v == from || v == to;
} }
public Vertex getConnectionPoint(Edge e) { public Vertex getConnectionPoint(Edge e) {
if (from == e.getTo() || from == e.getFrom()) { if (from == e.getTo() || from == e.getFrom()) {
return from; return from;
} }
if (to == e.getTo() || to == e.getFrom()) { if (to == e.getTo() || to == e.getFrom()) {
return to; return to;
} }
return null; return null;
} }
/** /**
* finds the point on the other end of the edge if the given vertex is one of * finds the point on the other end of the edge if the given vertex is one of
* the end points. * the end points.
* *
* @param c the given vertex * @param c the given vertex
* @return the opposite vertex or null if the given vertex is not an end point. * @return the opposite vertex or null if the given vertex is not an end point.
*/ */
public Vertex getOppositeVertex(Vertex c) { public Vertex getOppositeVertex(Vertex c) {
if (c == from) { if (c == from) {
return to; return to;
} }
if (c == to) { if (c == to) {
return from; return from;
} }
return null; return null;
} }
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
handler.addInstance(from); handler.addInstance(from);
handler.addInstance(to); handler.addInstance(to);
handler.addInstance(adjacentPolygons); handler.addInstance(adjacentPolygons);
handler.addInstance(adjacentRings); handler.addInstance(adjacentRings);
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new Edge(); return new Edge();
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
Edge originalEdge = (Edge) original; Edge originalEdge = (Edge) original;
from = handler.getCopyInstance(originalEdge.from); from = handler.getCopyInstance(originalEdge.from);
to = handler.getCopyInstance(originalEdge.to); to = handler.getCopyInstance(originalEdge.to);
numberOfHalfEdges = originalEdge.numberOfHalfEdges; numberOfHalfEdges = originalEdge.numberOfHalfEdges;
numberOfOppositeHalfEdges = originalEdge.numberOfOppositeHalfEdges; numberOfOppositeHalfEdges = originalEdge.numberOfOppositeHalfEdges;
for (Polygon originalPoly : originalEdge.adjacentPolygons) { for (Polygon originalPoly : originalEdge.adjacentPolygons) {
adjacentPolygons.add(handler.getCopyInstance(originalPoly)); adjacentPolygons.add(handler.getCopyInstance(originalPoly));
} }
for (LinearRing originalRing : originalEdge.adjacentRings) { for (LinearRing originalRing : originalEdge.adjacentRings) {
adjacentRings.add(handler.getCopyInstance(originalRing)); adjacentRings.add(handler.getCopyInstance(originalRing));
} }
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -20,13 +20,12 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -20,13 +20,12 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/** /**
* Possible feature types in CityGML * Possible feature types in CityGML
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public enum FeatureType { public enum FeatureType {
BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING, BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING,
BUILDING_PART, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION 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 * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,16 +18,6 @@ ...@@ -18,16 +18,6 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
...@@ -39,420 +29,423 @@ import de.hft.stuttgart.citydoctor2.utils.CopyHandler; ...@@ -39,420 +29,423 @@ import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; import de.hft.stuttgart.citydoctor2.utils.Copyable;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair; 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 * Representation of a geometry containing the polygons and edges
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class Geometry extends GmlElement { public class Geometry extends GmlElement {
private static final String FAILED_REMOVING_POLYGON = "Removing polygon %s but polygon is not in geometry"; private static final String FAILED_REMOVING_POLYGON = "Removing polygon %s but polygon is not in geometry";
@Serial @Serial
private static final long serialVersionUID = 2539031030917731575L; private static final long serialVersionUID = 2539031030917731575L;
private static final Random r = new Random(); private static final Random r = new Random();
private GeometryType type; private GeometryType type;
private final Lod lod; private final Lod lod;
private CityObject parent; private CityObject parent;
private final List<Polygon> polygons = new ArrayList<>(2); private final List<Polygon> polygons = new ArrayList<>(2);
private List<Edge> edges; private List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap; private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices; private List<Vertex> vertices;
public Geometry(GeometryType type, Lod lod) { public Geometry(GeometryType type, Lod lod) {
this.lod = lod; this.lod = lod;
this.type = type; this.type = type;
} }
void setParent(CityObject parent) { void setParent(CityObject parent) {
this.parent = parent; this.parent = parent;
} }
public CityObject getParent() { public CityObject getParent() {
return parent; return parent;
} }
public void setType(GeometryType type) { public void setType(GeometryType type) {
this.type = type; this.type = type;
} }
public GeometryType getType() { public GeometryType getType() {
return type; return type;
} }
public Lod getLod() { public Lod getLod() {
return lod; return lod;
} }
public List<Polygon> getPolygons() { public List<Polygon> getPolygons() {
return polygons; return polygons;
} }
public void addPolygon(Polygon cdPoly) { public void addPolygon(Polygon cdPoly) {
polygons.add(cdPoly); polygons.add(cdPoly);
cdPoly.setParent(this); cdPoly.setParent(this);
// set part of boundary surface or building installation or both // set part of boundary surface or building installation or both
if (parent instanceof BoundarySurface bs) { if (parent instanceof BoundarySurface bs) {
cdPoly.setPartOfSurface(bs); cdPoly.setPartOfSurface(bs);
if (bs.getParent() instanceof Installation bi) { if (bs.getParent() instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi); cdPoly.setPartOfInstallation(bi);
} }
} else if (parent instanceof Installation bi) { } else if (parent instanceof Installation bi) {
cdPoly.setPartOfInstallation(bi); cdPoly.setPartOfInstallation(bi);
} }
} }
public void updateEdges() { public void updateEdges() {
edges = new ArrayList<>(); edges = new ArrayList<>();
edgeMap = new HashMap<>(); edgeMap = new HashMap<>();
Map<Edge, Edge> duplicacyMap = new HashMap<>(); Map<Edge, Edge> duplicacyMap = new HashMap<>();
for (Polygon p : polygons) { for (Polygon p : polygons) {
LinearRing extRing = p.getExteriorRing(); LinearRing extRing = p.getExteriorRing();
createEdgesFromRing(duplicacyMap, p, extRing); createEdgesFromRing(duplicacyMap, p, extRing);
for (LinearRing inner : p.getInnerRings()) { for (LinearRing inner : p.getInnerRings()) {
createEdgesFromRing(duplicacyMap, p, inner); createEdgesFromRing(duplicacyMap, p, inner);
} }
} }
} }
void anonymize() { void anonymize() {
setGmlId(GmlId.generateId()); setGmlId(GmlId.generateId());
for (Polygon p : polygons) { for (Polygon p : polygons) {
p.anonymize(); p.anonymize();
} }
double minX = Double.MAX_VALUE; double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE; double minY = Double.MAX_VALUE;
double minZ = Double.MAX_VALUE; double minZ = Double.MAX_VALUE;
for (Vertex v : vertices) { for (Vertex v : vertices) {
if (v.getX() < minX) { if (v.getX() < minX) {
minX = v.getX(); minX = v.getX();
} }
if (v.getY() < minY) { if (v.getY() < minY) {
minY = v.getY(); minY = v.getY();
} }
if (v.getZ() < minZ) { if (v.getZ() < minZ) {
minZ = v.getZ(); minZ = v.getZ();
} }
} }
double varX = r.nextDouble() * 10; double varX = r.nextDouble() * 10;
double varY = r.nextDouble() * 10; double varY = r.nextDouble() * 10;
double varZ = r.nextDouble() * 10; double varZ = r.nextDouble() * 10;
for (Vertex v : vertices) { for (Vertex v : vertices) {
v.setX(v.getX() - minX + varX); v.setX(v.getX() - minX + varX);
v.setY(v.getY() - minY + varY); v.setY(v.getY() - minY + varY);
v.setZ(v.getZ() - minZ + varZ); v.setZ(v.getZ() - minZ + varZ);
} }
} }
private void createEdgesFromRing(Map<Edge, Edge> duplicacyMap, Polygon p, LinearRing ring) { private void createEdgesFromRing(Map<Edge, Edge> duplicacyMap, Polygon p, LinearRing ring) {
if (ring == null) { if (ring == null) {
return; return;
} }
// only go to size -1 as ring should be closed // only go to size -1 as ring should be closed
for (int i = 0; i < ring.getVertices().size() - 1; i++) { for (int i = 0; i < ring.getVertices().size() - 1; i++) {
Vertex v0 = ring.getVertices().get(i); Vertex v0 = ring.getVertices().get(i);
Vertex v1 = ring.getVertices().get(i + 1); Vertex v1 = ring.getVertices().get(i + 1);
Edge tempEdge = new Edge(v0, v1); Edge tempEdge = new Edge(v0, v1);
Edge e = duplicacyMap.get(tempEdge); Edge e = duplicacyMap.get(tempEdge);
if (e == null) { if (e == null) {
// no duplicate found, enter edges // no duplicate found, enter edges
Edge oppositeEdge = new Edge(v1, v0); Edge oppositeEdge = new Edge(v1, v0);
duplicacyMap.put(tempEdge, tempEdge); duplicacyMap.put(tempEdge, tempEdge);
duplicacyMap.put(oppositeEdge, tempEdge); duplicacyMap.put(oppositeEdge, tempEdge);
e = tempEdge; e = tempEdge;
edges.add(e); edges.add(e);
edgeMap.put(new SerializablePair<>(v0, v1), e); edgeMap.put(new SerializablePair<>(v0, v1), e);
edgeMap.put(new SerializablePair<>(v1, v0), e); edgeMap.put(new SerializablePair<>(v1, v0), e);
} else { } else {
e.addHalfEdge(v0, v1); e.addHalfEdge(v0, v1);
} }
e.addAdjacentPolygon(p); e.addAdjacentPolygon(p);
e.addAdjacentRing(ring); e.addAdjacentRing(ring);
} }
} }
public Vector3d getCenter() { public Vector3d getCenter() {
return calculateBoundingBox().getCenter(); return calculateBoundingBox().getCenter();
} }
/** /**
* This will calculate two points where every other point in the geometry is * 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 * 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. * 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 * Only the exterior rings of the polygons is used as inner rings should be
* within the exterior or they are faulty. * within the exterior or they are faulty.
* *
* @return an array of two points. The first contains the lowest coordinates, * @return an array of two points. The first contains the lowest coordinates,
* the second contains the highest coordinates * the second contains the highest coordinates
*/ */
public BoundingBox calculateBoundingBox() { public BoundingBox calculateBoundingBox() {
return BoundingBoxCalculator.calculateBoundingBox(polygons); return BoundingBoxCalculator.calculateBoundingBox(polygons);
} }
public double calculateVolume() { public double calculateVolume() {
double sum = 0; double sum = 0;
Vector3d center = calculateBoundingBox().getCenter(); Vector3d center = calculateBoundingBox().getCenter();
for (Polygon p : polygons) { for (Polygon p : polygons) {
TesselatedPolygon tesselatedPolygon = p.tesselate(); TesselatedPolygon tesselatedPolygon = p.tesselate();
for (Triangle3d t : tesselatedPolygon.getTriangles()) { for (Triangle3d t : tesselatedPolygon.getTriangles()) {
Vector3d p1 = t.getP1().minus(center); Vector3d p1 = t.getP1().minus(center);
Vector3d p2 = t.getP2().minus(center); Vector3d p2 = t.getP2().minus(center);
Vector3d p3 = t.getP3().minus(center); Vector3d p3 = t.getP3().minus(center);
sum += det(p1.getCoordinates(), p2.getCoordinates(), p3.getCoordinates()); sum += det(p1.getCoordinates(), p2.getCoordinates(), p3.getCoordinates());
} }
} }
return sum / 6d; return sum / 6d;
} }
private double det(double[] a, double[] b, double[] c) { 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] 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]; + a[0] * b[1] * c[2];
} }
@Override @Override
public boolean containsError(CheckId checkIdentifier) { public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier); boolean hasError = super.containsError(checkIdentifier);
if (hasError) { if (hasError) {
return true; return true;
} }
for (Polygon p : polygons) { for (Polygon p : polygons) {
if (p.containsError(checkIdentifier)) { if (p.containsError(checkIdentifier)) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public void clearAllContainedCheckResults() { public void clearAllContainedCheckResults() {
super.clearCheckResults(); super.clearCheckResults();
for (Polygon p : polygons) { for (Polygon p : polygons) {
p.clearAllContainedCheckResults(); p.clearAllContainedCheckResults();
} }
} }
@Override @Override
public void collectContainedErrors(List<CheckError> errors) { public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors); super.collectContainedErrors(errors);
for (Polygon p : polygons) { for (Polygon p : polygons) {
p.collectContainedErrors(errors); p.collectContainedErrors(errors);
} }
} }
@Override @Override
public boolean containsAnyError() { public boolean containsAnyError() {
boolean hasError = super.containsAnyError(); boolean hasError = super.containsAnyError();
if (hasError) { if (hasError) {
return true; return true;
} }
for (Polygon p : polygons) { for (Polygon p : polygons) {
if (p.containsAnyError()) { if (p.containsAnyError()) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
for (Polygon p : polygons) { for (Polygon p : polygons) {
p.accept(c); p.accept(c);
} }
} }
@Override @Override
public String toString() { public String toString() {
return "Geometry [type=" + type + ", lod=" + lod + ", id=" + getGmlId() + "]"; return "Geometry [type=" + type + ", lod=" + lod + ", id=" + getGmlId() + "]";
} }
public List<Vertex> getVertices() { public List<Vertex> getVertices() {
return vertices; return vertices;
} }
public List<Edge> getEdges() { public List<Edge> getEdges() {
return edges; return edges;
} }
public List<Edge> getEdgesAdjacentTo(Vertex v) { public List<Edge> getEdgesAdjacentTo(Vertex v) {
List<Edge> adjacentEdges = new ArrayList<>(); List<Edge> adjacentEdges = new ArrayList<>();
for (Edge e : edges) { for (Edge e : edges) {
if (e.getFrom() == v || e.getTo() == v) { if (e.getFrom() == v || e.getTo() == v) {
adjacentEdges.add(e); adjacentEdges.add(e);
} }
} }
return adjacentEdges; return adjacentEdges;
} }
public Edge getEdge(Vertex v1, Vertex v2) { public Edge getEdge(Vertex v1, Vertex v2) {
return edgeMap.get(new SerializablePair<>(v1, v2)); return edgeMap.get(new SerializablePair<>(v1, v2));
} }
public void updateEdgesAndVertices() { public void updateEdgesAndVertices() {
updateVertices(); updateVertices();
updateEdges(); updateEdges();
} }
public void updateVertices() { public void updateVertices() {
Set<Vertex> vertexSet = new HashSet<>(); Set<Vertex> vertexSet = new HashSet<>();
for (Polygon p : getPolygons()) { for (Polygon p : getPolygons()) {
updateRing(vertexSet, p.getExteriorRing()); updateRing(vertexSet, p.getExteriorRing());
for (LinearRing inner : p.getInnerRings()) { for (LinearRing inner : p.getInnerRings()) {
updateRing(vertexSet, inner); updateRing(vertexSet, inner);
} }
} }
vertices = new ArrayList<>(vertexSet); vertices = new ArrayList<>(vertexSet);
} }
private void updateRing(Set<Vertex> vertexSet, LinearRing ring) { private void updateRing(Set<Vertex> vertexSet, LinearRing ring) {
if (ring == null) { if (ring == null) {
return; return;
} }
for (Vertex v : ring.getVertices()) { for (Vertex v : ring.getVertices()) {
if (vertexSet.add(v)) { if (vertexSet.add(v)) {
// new vertex, clear adjacent rings in case new rings have been added // new vertex, clear adjacent rings in case new rings have been added
v.clearAdjacentRings(this); v.clearAdjacentRings(this);
} }
// add ring to adjacent rings of vertex // add ring to adjacent rings of vertex
v.addAdjacentRing(ring, this); v.addAdjacentRing(ring, this);
} }
} }
void removePolygon(Polygon p) { void removePolygon(Polygon p) {
p.removeRings(); p.removeRings();
if (!polygons.remove(p)) { if (!polygons.remove(p)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p)); throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
} }
if (p.isLink()) { if (p.isLink()) {
Polygon original = p.getOriginal(); Polygon original = p.getOriginal();
if (!original.getParent().polygons.remove(original)) { if (!original.getParent().polygons.remove(original)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p)); throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
} }
} else if (p.isLinkedTo()) { } else if (p.isLinkedTo()) {
Polygon link = p.getLinkedFromPolygon(); Polygon link = p.getLinkedFromPolygon();
if (!link.getParent().polygons.remove(link)) { if (!link.getParent().polygons.remove(link)) {
throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p)); throw new IllegalStateException(String.format(FAILED_REMOVING_POLYGON, p));
} }
} }
} }
public void replacePolygon(Polygon p, ConcretePolygon... polygons) { public void replacePolygon(Polygon p, ConcretePolygon... polygons) {
removePolygon(p); removePolygon(p);
if (p.isLink()) { if (p.isLink()) {
Geometry geom2 = p.getOriginal().getParent(); Geometry geom2 = p.getOriginal().getParent();
for (ConcretePolygon newPoly : polygons) { for (ConcretePolygon newPoly : polygons) {
geom2.addPolygon(newPoly); geom2.addPolygon(newPoly);
addPolygon(new LinkedPolygon(newPoly, this)); addPolygon(new LinkedPolygon(newPoly, this));
} }
} else if (p.isLinkedTo()) { } else if (p.isLinkedTo()) {
Geometry geom2 = p.getLinkedFromPolygon().getParent(); Geometry geom2 = p.getLinkedFromPolygon().getParent();
for (ConcretePolygon newPoly : polygons) { for (ConcretePolygon newPoly : polygons) {
addPolygon(newPoly); addPolygon(newPoly);
geom2.addPolygon(new LinkedPolygon(newPoly, geom2)); geom2.addPolygon(new LinkedPolygon(newPoly, geom2));
} }
} else { } else {
for (Polygon newPoly : polygons) { for (Polygon newPoly : polygons) {
addPolygon(newPoly); addPolygon(newPoly);
} }
} }
} }
public List<Edge> getEdgesAdjacentTo(Polygon p) { public List<Edge> getEdgesAdjacentTo(Polygon p) {
List<Edge> list = new ArrayList<>(); List<Edge> list = new ArrayList<>();
for (Edge e : edges) { for (Edge e : edges) {
if (e.getAdjacentPolygons().contains(p)) { if (e.getAdjacentPolygons().contains(p)) {
list.add(e); list.add(e);
} }
} }
return list; return list;
} }
public boolean containsPolygon(Polygon other) { public boolean containsPolygon(Polygon other) {
for (Polygon p : polygons) { for (Polygon p : polygons) {
if (p.getGmlId().equals(other.getGmlId())) { if (p.getGmlId().equals(other.getGmlId())) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public void prepareForChecking() { public void prepareForChecking() {
updateEdgesAndVertices(); updateEdgesAndVertices();
} }
@Override @Override
public void clearMetaInformation() { public void clearMetaInformation() {
if (vertices != null) { if (vertices != null) {
for (Vertex v : vertices) { for (Vertex v : vertices) {
v.clearAdjacentRings(); v.clearAdjacentRings();
} }
vertices = null; vertices = null;
} }
edges = null; edges = null;
edgeMap = null; edgeMap = null;
} }
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
handler.addInstance(parent); handler.addInstance(parent);
handler.addInstance(polygons); handler.addInstance(polygons);
handler.addInstance(edges); handler.addInstance(edges);
handler.addInstance(vertices); handler.addInstance(vertices);
if (edgeMap != null) { if (edgeMap != null) {
for (Entry<SerializablePair<Vertex, Vertex>, Edge> e : edgeMap.entrySet()) { for (Entry<SerializablePair<Vertex, Vertex>, Edge> e : edgeMap.entrySet()) {
handler.addInstance(e.getKey().getValue0()); handler.addInstance(e.getKey().getValue0());
handler.addInstance(e.getKey().getValue1()); handler.addInstance(e.getKey().getValue1());
handler.addInstance(e.getValue()); handler.addInstance(e.getValue());
} }
} }
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new Geometry(type, lod); return new Geometry(type, lod);
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler); super.fillValues(original, handler);
Geometry originalGeometry = (Geometry) original; Geometry originalGeometry = (Geometry) original;
for (Polygon originalPoly : originalGeometry.polygons) { for (Polygon originalPoly : originalGeometry.polygons) {
polygons.add(handler.getCopyInstance(originalPoly)); polygons.add(handler.getCopyInstance(originalPoly));
} }
if (originalGeometry.edges != null) { if (originalGeometry.edges != null) {
edges = new ArrayList<>(originalGeometry.edges.size()); edges = new ArrayList<>(originalGeometry.edges.size());
for (Edge originalEdge : originalGeometry.edges) { for (Edge originalEdge : originalGeometry.edges) {
edges.add(handler.getCopyInstance(originalEdge)); edges.add(handler.getCopyInstance(originalEdge));
} }
} }
if (originalGeometry.edgeMap != null) { if (originalGeometry.edgeMap != null) {
edgeMap = new HashMap<>(originalGeometry.edgeMap.size()); edgeMap = new HashMap<>(originalGeometry.edgeMap.size());
for (Entry<SerializablePair<Vertex, Vertex>, Edge> originalEntry : originalGeometry.edgeMap.entrySet()) { for (Entry<SerializablePair<Vertex, Vertex>, Edge> originalEntry : originalGeometry.edgeMap.entrySet()) {
Vertex copyV0 = handler.getCopyInstance(originalEntry.getKey().getValue0()); Vertex copyV0 = handler.getCopyInstance(originalEntry.getKey().getValue0());
Vertex copyV1 = handler.getCopyInstance(originalEntry.getKey().getValue1()); Vertex copyV1 = handler.getCopyInstance(originalEntry.getKey().getValue1());
SerializablePair<Vertex, Vertex> pair = new SerializablePair<>(copyV0, copyV1); SerializablePair<Vertex, Vertex> pair = new SerializablePair<>(copyV0, copyV1);
Edge copyEdge = handler.getCopyInstance(originalEntry.getValue()); Edge copyEdge = handler.getCopyInstance(originalEntry.getValue());
edgeMap.put(pair, copyEdge); edgeMap.put(pair, copyEdge);
} }
} }
if (originalGeometry.vertices != null) { if (originalGeometry.vertices != null) {
vertices = new ArrayList<>(originalGeometry.vertices.size()); vertices = new ArrayList<>(originalGeometry.vertices.size());
for (Vertex originalVertex : originalGeometry.vertices) { for (Vertex originalVertex : originalGeometry.vertices) {
vertices.add(handler.getCopyInstance(originalVertex)); vertices.add(handler.getCopyInstance(originalVertex));
} }
} }
parent = handler.getCopyInstance(originalGeometry.parent); parent = handler.getCopyInstance(originalGeometry.parent);
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -20,12 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -20,12 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/** /**
* Available geometry types * Available geometry types
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public enum GeometryType { 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 * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -26,38 +26,37 @@ import java.io.Serial; ...@@ -26,38 +26,37 @@ import java.io.Serial;
/** /**
* A general GML element that has a gml id * A general GML element that has a gml id
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public abstract class GmlElement extends Checkable implements Copyable { public abstract class GmlElement extends Checkable implements Copyable {
@Serial @Serial
private static final long serialVersionUID = -3242505393303017359L; private static final long serialVersionUID = -3242505393303017359L;
private GmlId gmlId; private GmlId gmlId;
public void setGmlId(GmlId id) { public void setGmlId(GmlId id) {
gmlId = id; gmlId = id;
} }
@Override @Override
public GmlId getGmlId() { public GmlId getGmlId() {
if (gmlId == null) { if (gmlId == null) {
gmlId = GmlId.generateId(); gmlId = GmlId.generateId();
} }
return gmlId; return gmlId;
} }
public boolean hasExistingGmlId() { public boolean hasExistingGmlId() {
return gmlId != null && !gmlId.isGenerated(); return gmlId != null && !gmlId.isGenerated();
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
GmlElement originalElement = (GmlElement) original; GmlElement originalElement = (GmlElement) original;
// generate gml id before copying // generate gml id before copying
gmlId = originalElement.getGmlId(); gmlId = originalElement.getGmlId();
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -25,83 +25,82 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -25,83 +25,82 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Represents a GML id. Additionally contains information whether this id was * Represents a GML id. Additionally contains information whether this id was
* generated by city doctor * generated by city doctor
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class GmlId implements Serializable { public class GmlId implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 4273817255150972966L; private static final long serialVersionUID = 4273817255150972966L;
/* prefixes for generation */ /* prefixes for generation */
private static final String GENERAL_GEN = "CityDoctor_%d_%d"; private static final String GENERAL_GEN = "CityDoctor_%d_%d";
private static final AtomicInteger ID_COUNTER = new AtomicInteger(); private static final AtomicInteger ID_COUNTER = new AtomicInteger();
private final String gmlString; private final String gmlString;
private final boolean generated; private final boolean generated;
public GmlId(String gmlId) { public GmlId(String gmlId) {
this(gmlId, false); this(gmlId, false);
} }
private GmlId(String gmlId, boolean generated) { private GmlId(String gmlId, boolean generated) {
if (gmlId == null || gmlId.isEmpty()) { if (gmlId == null || gmlId.isEmpty()) {
throw new IllegalArgumentException("GmlId may not be null or empty. If no GmlId is given generate one"); throw new IllegalArgumentException("GmlId may not be null or empty. If no GmlId is given generate one");
} }
this.gmlString = gmlId; this.gmlString = gmlId;
this.generated = generated; this.generated = generated;
} }
@Override @Override
public String toString() { public String toString() {
return gmlString; return gmlString;
} }
public String getGmlString() { public String getGmlString() {
return gmlString; return gmlString;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + (generated ? 1231 : 1237); result = prime * result + (generated ? 1231 : 1237);
result = prime * result + ((gmlString == null) ? 0 : gmlString.hashCode()); result = prime * result + ((gmlString == null) ? 0 : gmlString.hashCode());
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
GmlId other = (GmlId) obj; GmlId other = (GmlId) obj;
if (generated != other.generated) { if (generated != other.generated) {
return false; return false;
} }
if (gmlString == null) { if (gmlString == null) {
return other.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. * Determines if the GML-ID was generated by CityDoctor or not.
* *
* @return True if it was generated, otherwise false. * @return True if it was generated, otherwise false.
*/ */
public boolean isGenerated() { public boolean isGenerated() {
return generated; return generated;
} }
public static GmlId generateId() { public static GmlId generateId() {
return new GmlId(String.format(GENERAL_GEN, System.currentTimeMillis(), ID_COUNTER.getAndIncrement()), true); 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 * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,10 +18,13 @@ ...@@ -18,10 +18,13 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial; import de.hft.stuttgart.citydoctor2.check.Check;
import java.util.ArrayList; import de.hft.stuttgart.citydoctor2.check.CheckError;
import java.util.List; 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.bridge.BridgeInstallation;
import org.citygml4j.core.model.construction.AbstractInstallation; import org.citygml4j.core.model.construction.AbstractInstallation;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty; import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
...@@ -32,252 +35,248 @@ import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; ...@@ -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.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty; import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check; import java.io.Serial;
import de.hft.stuttgart.citydoctor2.check.CheckError; import java.util.ArrayList;
import de.hft.stuttgart.citydoctor2.check.CheckId; import java.util.List;
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;
public class Installation extends CityObject { public class Installation extends CityObject {
@Serial @Serial
private static final long serialVersionUID = 1576237433322680191L; private static final long serialVersionUID = 1576237433322680191L;
private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4); private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4);
private AbstractInstallation gmlBi; private AbstractInstallation gmlBi;
private CityObject parent; private CityObject parent;
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) { if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
if (ms != null) { if (ms != null) {
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms)); setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
} }
} else if (geom.getType() == GeometryType.COMPOSITE_SURFACE) { } else if (geom.getType() == GeometryType.COMPOSITE_SURFACE) {
CompositeSurface cs = CityGmlUtils.createCompositeSurface(geom, factory, config); CompositeSurface cs = CityGmlUtils.createCompositeSurface(geom, factory, config);
if (cs != null) { if (cs != null) {
setGeometryAccordingToLod(geom.getLod(), new SurfaceProperty(cs)); setGeometryAccordingToLod(geom.getLod(), new SurfaceProperty(cs));
} }
} else { } else {
throw new IllegalStateException("BuildingInstallation not have Solid geometries"); throw new IllegalStateException("BuildingInstallation not have Solid geometries");
} }
} }
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.reCreateGeometries(factory, config); bs.reCreateGeometries(factory, config);
} }
} }
private void setGeometryAccordingToLod(Lod lod, GeometryProperty<?> ms) { private void setGeometryAccordingToLod(Lod lod, GeometryProperty<?> ms) {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) { if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
addGeometryToBuildingInstallation(lod, ms, localBi); addGeometryToBuildingInstallation(lod, ms, localBi);
} else if (gmlBi instanceof BridgeInstallation localBi) { } else if (gmlBi instanceof BridgeInstallation localBi) {
addGeometryToBridgeInstallation(lod, ms, localBi); addGeometryToBridgeInstallation(lod, ms, localBi);
} }
} }
private void addGeometryToBuildingInstallation(Lod lod, GeometryProperty<?> ms, private void addGeometryToBuildingInstallation(Lod lod, GeometryProperty<?> ms,
org.citygml4j.core.model.building.BuildingInstallation localBi) { org.citygml4j.core.model.building.BuildingInstallation localBi) {
switch (lod) { switch (lod) {
case LOD2: case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms); localBi.getDeprecatedProperties().setLod2Geometry(ms);
break; break;
case LOD3: case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms); localBi.getDeprecatedProperties().setLod3Geometry(ms);
break; break;
case LOD4: case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms); localBi.getDeprecatedProperties().setLod4Geometry(ms);
break; break;
default: default:
throw new IllegalStateException("Found geometry with LOD other than LOD2," throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod); + " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
} }
} }
private void addGeometryToBridgeInstallation(Lod lod, GeometryProperty<?> ms, BridgeInstallation localBi) { private void addGeometryToBridgeInstallation(Lod lod, GeometryProperty<?> ms, BridgeInstallation localBi) {
switch (lod) { switch (lod) {
case LOD2: case LOD2:
localBi.getDeprecatedProperties().setLod2Geometry(ms); localBi.getDeprecatedProperties().setLod2Geometry(ms);
break; break;
case LOD3: case LOD3:
localBi.getDeprecatedProperties().setLod3Geometry(ms); localBi.getDeprecatedProperties().setLod3Geometry(ms);
break; break;
case LOD4: case LOD4:
localBi.getDeprecatedProperties().setLod4Geometry(ms); localBi.getDeprecatedProperties().setLod4Geometry(ms);
break; break;
default: default:
throw new IllegalStateException("Found geometry with LOD other than LOD2," throw new IllegalStateException("Found geometry with LOD other than LOD2,"
+ " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod); + " LOD3, LOD4, which is illegal for BuildingInstallations: " + lod);
} }
} }
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.accept(c); bs.accept(c);
} }
} }
@Override @Override
public void clearAllContainedCheckResults() { public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults(); super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.clearAllContainedCheckResults(); bs.clearAllContainedCheckResults();
} }
} }
@Override @Override
public void collectContainedErrors(List<CheckError> errors) { public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors); super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.collectContainedErrors(errors); bs.collectContainedErrors(errors);
} }
} }
@Override @Override
public boolean containsAnyError() { public boolean containsAnyError() {
boolean hasError = super.containsAnyError(); boolean hasError = super.containsAnyError();
if (hasError) { if (hasError) {
return true; return true;
} }
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsAnyError()) { if (bs.containsAnyError()) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public boolean containsError(CheckId checkIdentifier) { public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier); boolean hasError = super.containsError(checkIdentifier);
if (hasError) { if (hasError) {
return true; return true;
} }
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsError(checkIdentifier)) { if (bs.containsError(checkIdentifier)) {
return true; return true;
} }
} }
return false; return false;
} }
public void setParent(CityObject parent) { public void setParent(CityObject parent) {
this.parent = parent; this.parent = parent;
} }
public CityObject getParent() { public CityObject getParent() {
return parent; return parent;
} }
public void addBoundarySurface(BoundarySurface bs) { public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaces.add(bs); boundarySurfaces.add(bs);
bs.setParent(this); bs.setParent(this);
} }
public void unsetGmlGeometries() { public void unsetGmlGeometries() {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) { if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null); localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null); localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null); localBi.getDeprecatedProperties().setLod4Geometry(null);
} else if (gmlBi instanceof BridgeInstallation localBi) { } else if (gmlBi instanceof BridgeInstallation localBi) {
removeGeometriesFromBridgeInstallation(localBi); removeGeometriesFromBridgeInstallation(localBi);
} }
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.unsetGmlGeometries(); bs.unsetGmlGeometries();
} }
} }
private void removeGeometriesFromBridgeInstallation(BridgeInstallation localBi) { private void removeGeometriesFromBridgeInstallation(BridgeInstallation localBi) {
localBi.getDeprecatedProperties().setLod2Geometry(null); localBi.getDeprecatedProperties().setLod2Geometry(null);
localBi.getDeprecatedProperties().setLod3Geometry(null); localBi.getDeprecatedProperties().setLod3Geometry(null);
localBi.getDeprecatedProperties().setLod4Geometry(null); localBi.getDeprecatedProperties().setLod4Geometry(null);
} }
public void setGmlObject(AbstractInstallation gmlBi) { public void setGmlObject(AbstractInstallation gmlBi) {
this.gmlBi = gmlBi; this.gmlBi = gmlBi;
} }
@Override @Override
public String toString() { public String toString() {
return "BuildingInstallation [id=" + getGmlId() + "]"; return "BuildingInstallation [id=" + getGmlId() + "]";
} }
void anonymize() { void anonymize() {
setGmlId(GmlId.generateId()); setGmlId(GmlId.generateId());
gmlBi = new org.citygml4j.core.model.building.BuildingInstallation(); gmlBi = new org.citygml4j.core.model.building.BuildingInstallation();
gmlBi.setId(getGmlId().getGmlString()); gmlBi.setId(getGmlId().getGmlString());
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.anonymize(); bs.anonymize();
gmlBi.getBoundaries().add(new AbstractSpaceBoundaryProperty(bs.getGmlObject())); gmlBi.getBoundaries().add(new AbstractSpaceBoundaryProperty(bs.getGmlObject()));
} }
} }
@Override @Override
public AbstractInstallation getGmlObject() { public AbstractInstallation getGmlObject() {
return gmlBi; return gmlBi;
} }
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.INSTALLATION; return FeatureType.INSTALLATION;
} }
public List<BoundarySurface> getBoundarySurfaces() { public List<BoundarySurface> getBoundarySurfaces() {
if (boundarySurfaces == null) { if (boundarySurfaces == null) {
boundarySurfaces = new ArrayList<>(4); boundarySurfaces = new ArrayList<>(4);
} }
return boundarySurfaces; return boundarySurfaces;
} }
@Override @Override
public void clearMetaInformation() { public void clearMetaInformation() {
super.clearMetaInformation(); super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.clearMetaInformation(); bs.clearMetaInformation();
} }
} }
@Override @Override
public void prepareForChecking() { public void prepareForChecking() {
super.prepareForChecking(); super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.prepareForChecking(); bs.prepareForChecking();
} }
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler); super.fillValues(original, handler);
Installation originalBi = (Installation) original; Installation originalBi = (Installation) original;
for (BoundarySurface originalBs : originalBi.boundarySurfaces) { for (BoundarySurface originalBs : originalBi.boundarySurfaces) {
boundarySurfaces.add(handler.getCopyInstance(originalBs)); boundarySurfaces.add(handler.getCopyInstance(originalBs));
} }
gmlBi = originalBi.gmlBi; gmlBi = originalBi.gmlBi;
parent = handler.getCopyInstance(parent); parent = handler.getCopyInstance(parent);
} }
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
super.collectInstances(handler); super.collectInstances(handler);
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
handler.addInstance(bs); handler.addInstance(bs);
} }
handler.addInstance(parent); handler.addInstance(parent);
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new Installation(); return new Installation();
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,107 +18,105 @@ ...@@ -18,107 +18,105 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.core.AbstractCityObject;
import org.citygml4j.core.model.landuse.LandUse; import org.citygml4j.core.model.landuse.LandUse;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; 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; import java.io.Serial;
/** /**
* Represents a land use CityGML object. * Represents a land use CityGML object.
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class LandObject extends CityObject { public class LandObject extends CityObject {
@Serial @Serial
private static final long serialVersionUID = 1887455662411087326L; private static final long serialVersionUID = 1887455662411087326L;
private LandUse lu; private LandUse lu;
public LandObject(LandUse lu) { public LandObject(LandUse lu) {
this.lu = lu; this.lu = lu;
} }
@Override @Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) { if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms); setMultiSurfaceAccordingToLod(geom, ms);
} else { } else {
throw new IllegalStateException("Landuse cannot have solids: " + geom); throw new IllegalStateException("Landuse cannot have solids: " + geom);
} }
} }
} }
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.LAND; return FeatureType.LAND;
} }
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) { private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) { switch (geom.getLod()) {
case LOD0: case LOD0:
lu.setLod0MultiSurface(new MultiSurfaceProperty(ms)); lu.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD1: case LOD1:
lu.setLod1MultiSurface(new MultiSurfaceProperty(ms)); lu.setLod1MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD2: case LOD2:
lu.setLod2MultiSurface(new MultiSurfaceProperty(ms)); lu.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD3: case LOD3:
lu.setLod3MultiSurface(new MultiSurfaceProperty(ms)); lu.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD4: case LOD4:
lu.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms)); lu.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break; break;
} }
} }
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
} }
@Override @Override
public AbstractCityObject getGmlObject() { public AbstractCityObject getGmlObject() {
return lu; return lu;
} }
@Override @Override
public void unsetGmlGeometries() { public void unsetGmlGeometries() {
lu.setLod0MultiSurface(null); lu.setLod0MultiSurface(null);
lu.setLod1MultiSurface(null); lu.setLod1MultiSurface(null);
lu.setLod2MultiSurface(null); lu.setLod2MultiSurface(null);
lu.setLod3MultiSurface(null); lu.setLod3MultiSurface(null);
lu.getDeprecatedProperties().setLod4MultiSurface(null); lu.getDeprecatedProperties().setLod4MultiSurface(null);
} }
public void setGmlObject(LandUse landUse) { public void setGmlObject(LandUse landUse) {
lu = landUse; lu = landUse;
} }
@Override @Override
public String toString() { public String toString() {
return "LandObject [id=" + getGmlId() + "]"; return "LandObject [id=" + getGmlId() + "]";
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new LandObject(lu); 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 * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,337 +18,332 @@ ...@@ -18,337 +18,332 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Check;
import de.hft.stuttgart.citydoctor2.math.ProjectionAxis; import de.hft.stuttgart.citydoctor2.math.*;
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.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; 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. * Represents a linear ring used in polygons. The ring contains the vertices.
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class LinearRing extends GmlElement { public class LinearRing extends GmlElement {
@Serial @Serial
private static final long serialVersionUID = -2488180830514940722L; private static final long serialVersionUID = -2488180830514940722L;
private LinearRingType type; private LinearRingType type;
private Polygon parent; private Polygon parent;
private final List<Vertex> vertices = new ArrayList<>(); private final List<Vertex> vertices = new ArrayList<>();
public enum LinearRingType { public enum LinearRingType {
EXTERIOR, INTERIOR EXTERIOR, INTERIOR
} }
public LinearRing(LinearRingType type) { public LinearRing(LinearRingType type) {
this.type = type; this.type = type;
} }
/** /**
* Checks whether a point is inside this ring. A point on the edge does count as * Checks whether a point is inside this ring. A point on the edge does count as
* inside. * inside.
* *
* @param v the point. * @param v the point.
* @return true if the point is inside or on an edge, false if it is outside. * @return true if the point is inside or on an edge, false if it is outside.
*/ */
public boolean isPointInside(Vector3d v) { public boolean isPointInside(Vector3d v) {
// project to 2d ring // project to 2d ring
ProjectionAxis axis = ProjectionAxis.of(this); ProjectionAxis axis = ProjectionAxis.of(this);
Vector2d point = axis.project(v); Vector2d point = axis.project(v);
Ring2d ring = Ring2d.of(this, axis); Ring2d ring = Ring2d.of(this, axis);
int t = -1; int t = -1;
for (int i = 0; i < ring.getVertices().size() - 1; i++) { for (int i = 0; i < ring.getVertices().size() - 1; i++) {
t = t * crossProdTest(point, ring.getVertices().get(i), ring.getVertices().get(i + 1)); t = t * crossProdTest(point, ring.getVertices().get(i), ring.getVertices().get(i + 1));
if (t == 0) { if (t == 0) {
return true; return true;
} }
} }
return t >= 0; return t >= 0;
} }
private int crossProdTest(Vector2d a, Vector2d b, Vector2d c) { private int crossProdTest(Vector2d a, Vector2d b, Vector2d c) {
if (a.getY() == b.getY() && a.getY() == c.getY()) { 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())) { if ((b.getX() <= a.getX() && a.getX() <= c.getX()) || (c.getX() <= a.getX() && a.getX() <= b.getX())) {
return 0; return 0;
} else { } else {
return 1; return 1;
} }
} }
if (a.getY() == b.getY() && a.getX() == b.getX()) { if (a.getY() == b.getY() && a.getX() == b.getX()) {
return 0; return 0;
} }
if (b.getY() > c.getY()) { if (b.getY() > c.getY()) {
Vector2d temp = b; Vector2d temp = b;
b = c; b = c;
c = temp; c = temp;
} }
if (a.getY() <= b.getY() || a.getY() > c.getY()) { if (a.getY() <= b.getY() || a.getY() > c.getY()) {
return 1; return 1;
} }
return calculateDelta(a, b, c); return calculateDelta(a, b, c);
} }
private int calculateDelta(Vector2d a, Vector2d b, Vector2d 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()); double delta = (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY()) * (c.getX() - a.getX());
if (delta > 0) { if (delta > 0) {
return -1; return -1;
} else if (delta < 0) { } else if (delta < 0) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} }
/** /**
* Calculates the normal vector of the ring. Method by Newell. If the Newell * 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 * 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. * first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
* *
* @return the normal as a normalized vector * @return the normal as a normalized vector
*/ */
public UnitVector3d calculateNormalNormalized() { public UnitVector3d calculateNormalNormalized() {
return calculateNormal().normalize(); return calculateNormal().normalize();
} }
/** /**
* Calculates the normal vector of the ring. Method by Newell. If the Newell * 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 * 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. * first 3 vertices. If there are no 3 vertices available (1, 0, 0) is returned.
* *
* @return the normal vector * @return the normal vector
*/ */
public Vector3d calculateNormal() { public Vector3d calculateNormal() {
double[] coords = new double[3]; double[] coords = new double[3];
for (int i = 0; i < vertices.size() - 1; i++) { for (int i = 0; i < vertices.size() - 1; i++) {
Vertex current = vertices.get(i); Vertex current = vertices.get(i);
Vertex next = vertices.get(i + 1); Vertex next = vertices.get(i + 1);
coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY()); coords[0] += (current.getZ() + next.getZ()) * (current.getY() - next.getY());
coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ()); coords[1] += (current.getX() + next.getX()) * (current.getZ() - next.getZ());
coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX()); coords[2] += (current.getY() + next.getY()) * (current.getX() - next.getX());
} }
if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) { if (coords[0] == 0 && coords[1] == 0 && coords[2] == 0) {
// no valid normal vector found // no valid normal vector found
if (vertices.size() < 3) { if (vertices.size() < 3) {
// no three points, return x-axis // no three points, return x-axis
return UnitVector3d.X_AXIS; return UnitVector3d.X_AXIS;
} }
Vertex v1 = vertices.get(0); Vertex v1 = vertices.get(0);
Vertex v2 = vertices.get(1); Vertex v2 = vertices.get(1);
Vertex v3 = vertices.get(2); Vertex v3 = vertices.get(2);
return calculateNormalWithCross(v1, v2, v3); return calculateNormalWithCross(v1, v2, v3);
} }
return new Vector3d(coords); return new Vector3d(coords);
} }
public double getArea() { public double getArea() {
int n = vertices.size(); int n = vertices.size();
if (n < 3) if (n < 3)
return 0.0; // a degenerated polygon return 0.0; // a degenerated polygon
// prepare an vertex array with n+2 vertices: // prepare an vertex array with n+2 vertices:
// V[0] ... V[n-1] - the n different vertices // V[0] ... V[n-1] - the n different vertices
// V[n]=V[0] // V[n]=V[0]
// V[n+1]=V[1] // V[n+1]=V[1]
Vertex[] vertexArray = new Vertex[n + 2]; Vertex[] vertexArray = new Vertex[n + 2];
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
vertexArray[i] = vertices.get(i); vertexArray[i] = vertices.get(i);
} }
vertexArray[n] = vertices.get(0); vertexArray[n] = vertices.get(0);
vertexArray[n + 1] = vertices.get(1); vertexArray[n + 1] = vertices.get(1);
double area = 0; double area = 0;
// make sure the normal has been calculated // make sure the normal has been calculated
Vector3d normal = calculateNormal(); Vector3d normal = calculateNormal();
// select largest abs coordinate to ignore for projection // select largest abs coordinate to ignore for projection
double ax = Math.abs(normal.getX()); // abs x-coord double ax = Math.abs(normal.getX()); // abs x-coord
double ay = Math.abs(normal.getY()); // abs y-coord double ay = Math.abs(normal.getY()); // abs y-coord
double az = Math.abs(normal.getZ()); // abs z-coord double az = Math.abs(normal.getZ()); // abs z-coord
// coord to ignore: 1=x, 2=y, 3=z // coord to ignore: 1=x, 2=y, 3=z
int coord = 3; // ignore z-coord int coord = 3; // ignore z-coord
if (ax > ay) { if (ax > ay) {
if (ax > az) { if (ax > az) {
coord = 1; // ignore x-coord coord = 1; // ignore x-coord
} }
} else if (ay > az) { } else if (ay > az) {
coord = 2; // ignore y-coord coord = 2; // ignore y-coord
} }
// compute area of the 2D projection // compute area of the 2D projection
for (int i = 1, j = 2, k = 0; i <= vertexArray.length - 2; i++, j++, k++) { for (int i = 1, j = 2, k = 0; i <= vertexArray.length - 2; i++, j++, k++) {
switch (coord) { switch (coord) {
case 1: case 1:
area += (vertexArray[i].getY() * (vertexArray[j].getZ() - vertexArray[k].getZ())); area += (vertexArray[i].getY() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break; break;
case 2: case 2:
area += (vertexArray[i].getX() * (vertexArray[j].getZ() - vertexArray[k].getZ())); area += (vertexArray[i].getX() * (vertexArray[j].getZ() - vertexArray[k].getZ()));
break; break;
case 3: case 3:
area += (vertexArray[i].getX() * (vertexArray[j].getY() - vertexArray[k].getY())); area += (vertexArray[i].getX() * (vertexArray[j].getY() - vertexArray[k].getY()));
break; break;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
// scale to get area before projection // scale to get area before projection
double an = Math.sqrt(ax * ax + ay * ay + az * az); // length of normal vector double an = Math.sqrt(ax * ax + ay * ay + az * az); // length of normal vector
switch (coord) { switch (coord) {
case 1: case 1:
area *= (an / (2 * ax)); area *= (an / (2 * ax));
break; break;
case 2: case 2:
area *= (an / (2 * ay)); area *= (an / (2 * ay));
break; break;
case 3: case 3:
area *= (an / (2 * az)); area *= (an / (2 * az));
break; break;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
return Math.abs(area); return Math.abs(area);
} }
private UnitVector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) { private UnitVector3d calculateNormalWithCross(Vertex v1, Vertex v2, Vertex v3) {
Vector3d dir1 = v2.minus(v1); Vector3d dir1 = v2.minus(v1);
Vector3d dir2 = v3.minus(v1); Vector3d dir2 = v3.minus(v1);
Vector3d cross = dir1.cross(dir2); Vector3d cross = dir1.cross(dir2);
return cross.normalize(); return cross.normalize();
} }
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
} }
@Override @Override
public void clearAllContainedCheckResults() { public void clearAllContainedCheckResults() {
super.clearCheckResults(); super.clearCheckResults();
} }
public void setParent(Polygon polygon) { public void setParent(Polygon polygon) {
parent = polygon; parent = polygon;
} }
public Polygon getParent() { public Polygon getParent() {
return parent; return parent;
} }
public LinearRingType getType() { public LinearRingType getType() {
return type; return type;
} }
public List<Vertex> getVertices() { public List<Vertex> getVertices() {
return vertices; return vertices;
} }
public void addVertex(Vertex v) { public void addVertex(Vertex v) {
vertices.add(v); vertices.add(v);
if (parent == null) { if (parent == null) {
return; return;
} }
if (parent.isLinkedTo()) { if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent()); v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
} }
v.addAdjacentRing(this, parent.getParent()); v.addAdjacentRing(this, parent.getParent());
} }
public void addVertex(int i, Vertex v) { public void addVertex(int i, Vertex v) {
vertices.add(i, v); vertices.add(i, v);
if (parent.isLinkedTo()) { if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent()); v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
} }
v.addAdjacentRing(this, parent.getParent()); v.addAdjacentRing(this, parent.getParent());
} }
public void setVertex(int i, Vertex v) { public void setVertex(int i, Vertex v) {
vertices.set(i, v); vertices.set(i, v);
if (parent.isLinkedTo()) { if (parent.isLinkedTo()) {
v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent()); v.addAdjacentRing(this, parent.getLinkedFromPolygon().getParent());
} }
v.addAdjacentRing(this, parent.getParent()); v.addAdjacentRing(this, parent.getParent());
} }
@Override @Override
public String toString() { public String toString() {
return "LinearRing [type=" + type + ", gmlId=" + getGmlId() + "]"; return "LinearRing [type=" + type + ", gmlId=" + getGmlId() + "]";
} }
void anonymize() { void anonymize() {
setGmlId(GmlId.generateId()); setGmlId(GmlId.generateId());
} }
public boolean isRingConnectedViaPoint(LinearRing other) { public boolean isRingConnectedViaPoint(LinearRing other) {
for (Vertex v : vertices) { for (Vertex v : vertices) {
if (other.getVertices().contains(v)) { if (other.getVertices().contains(v)) {
return true; return true;
} }
} }
return false; return false;
} }
public boolean hasPointAsCorner(Vertex v) { public boolean hasPointAsCorner(Vertex v) {
return vertices.contains(v); return vertices.contains(v);
} }
public void setType(LinearRingType type) { public void setType(LinearRingType type) {
this.type = type; this.type = type;
} }
public void addAllVertices(List<Vertex> extRing) { public void addAllVertices(List<Vertex> extRing) {
vertices.addAll(extRing); vertices.addAll(extRing);
} }
@Override @Override
public void prepareForChecking() { public void prepareForChecking() {
parent.getParent().prepareForChecking(); parent.getParent().prepareForChecking();
} }
@Override @Override
public void clearMetaInformation() { public void clearMetaInformation() {
parent.getParent().clearMetaInformation(); parent.getParent().clearMetaInformation();
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler); super.fillValues(original, handler);
LinearRing originalRing = (LinearRing) original; LinearRing originalRing = (LinearRing) original;
type = originalRing.type; type = originalRing.type;
parent = handler.getCopyInstance(originalRing.parent); parent = handler.getCopyInstance(originalRing.parent);
for (Vertex v : originalRing.vertices) { for (Vertex v : originalRing.vertices) {
vertices.add(handler.getCopyInstance(v)); vertices.add(handler.getCopyInstance(v));
} }
} }
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
for (Vertex v : vertices) { for (Vertex v : vertices) {
handler.addInstance(v); handler.addInstance(v);
} }
handler.addInstance(parent); handler.addInstance(parent);
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new LinearRing(type); return new LinearRing(type);
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,10 +18,6 @@ ...@@ -18,10 +18,6 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
...@@ -31,275 +27,277 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; ...@@ -31,275 +27,277 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; 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 * A polygon that does not contain the geometry but is only a link to an actual
* polygon. Created when href in CityGML are used. * polygon. Created when href in CityGML are used.
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class LinkedPolygon extends Polygon { public class LinkedPolygon extends Polygon {
@Serial @Serial
private static final long serialVersionUID = -4897578390280277931L; private static final long serialVersionUID = -4897578390280277931L;
private Geometry parent; private Geometry parent;
private ConcretePolygon poly; private ConcretePolygon poly;
private LinkedPolygon() { private LinkedPolygon() {
} }
/** /**
* * @param poly polygon this is linked to
* @param poly polygon this is linked to * @param parent the parent of the linked polygon
* @param parent the parent of the linked polygon */
*/ public LinkedPolygon(ConcretePolygon poly, Geometry parent) {
public LinkedPolygon(ConcretePolygon poly, Geometry parent) { this.parent = parent;
this.parent = parent; this.poly = poly;
this.poly = poly; poly.setLinkedTo(this);
poly.setLinkedTo(this); for (Vertex v : poly.getExteriorRing().getVertices()) {
for (Vertex v : poly.getExteriorRing().getVertices()) { v.addAdjacentRing(poly.getExteriorRing(), parent);
v.addAdjacentRing(poly.getExteriorRing(), parent); }
} for (LinearRing lr : poly.getInnerRings()) {
for (LinearRing lr : poly.getInnerRings()) { for (Vertex v : lr.getVertices()) {
for (Vertex v : lr.getVertices()) { v.addAdjacentRing(lr, parent);
v.addAdjacentRing(lr, parent); }
} }
} }
}
@Override
@Override public CheckResult getCheckResult(Check c) {
public CheckResult getCheckResult(Check c) { return poly.getCheckResult(c);
return poly.getCheckResult(c); }
}
@Override
@Override public Map<CheckId, CheckResult> getAllCheckResults() {
public Map<CheckId, CheckResult> getAllCheckResults() { return poly.getAllCheckResults();
return poly.getAllCheckResults(); }
}
@Override
@Override public boolean hasAnyError() {
public boolean hasAnyError() { return poly.hasAnyError();
return poly.hasAnyError(); }
}
@Override
@Override public boolean hasDependencyNotMetError(CheckId id) {
public boolean hasDependencyNotMetError(CheckId id) { return poly.hasDependencyNotMetError(id);
return poly.hasDependencyNotMetError(id); }
}
@Override
@Override public CheckResult getCheckResult(CheckId id) {
public CheckResult getCheckResult(CheckId id) { return poly.getCheckResult(id);
return poly.getCheckResult(id); }
}
@Override
@Override public boolean hasCheckResults() {
public boolean hasCheckResults() { return poly.hasCheckResults();
return poly.hasCheckResults(); }
}
@Override
@Override public void setGmlId(GmlId id) {
public void setGmlId(GmlId id) { poly.setGmlId(id);
poly.setGmlId(id); }
}
@Override
@Override public GmlId getGmlId() {
public GmlId getGmlId() { return poly.getGmlId();
return poly.getGmlId(); }
}
@Override
@Override public void accept(Check c) {
public void accept(Check c) { // linked polygons are not checked
// linked polygons are not checked setValidated(true);
setValidated(true); }
}
@Override
@Override public void addCheckResult(CheckResult cr) {
public void addCheckResult(CheckResult cr) { poly.addCheckResult(cr);
poly.addCheckResult(cr); }
}
@Override
@Override public void collectContainedErrors(List<CheckError> errors) {
public void collectContainedErrors(List<CheckError> errors) { poly.collectContainedErrors(errors);
poly.collectContainedErrors(errors); }
}
@Override
@Override public boolean containsAnyError() {
public boolean containsAnyError() { return poly.containsAnyError();
return poly.containsAnyError(); }
}
@Override
@Override public boolean containsError(CheckId checkIdentifier) {
public boolean containsError(CheckId checkIdentifier) { return poly.containsError(checkIdentifier);
return poly.containsError(checkIdentifier); }
}
@Override
@Override public void clearCheckResults() {
public void clearCheckResults() { poly.clearCheckResults();
poly.clearCheckResults(); }
}
@Override
@Override public Vector3d calculateNormalNormalized() {
public Vector3d calculateNormalNormalized() { return poly.calculateNormalNormalized();
return poly.calculateNormalNormalized(); }
}
@Override
@Override public Vector3d calculateNormal() {
public Vector3d calculateNormal() { return poly.calculateNormal();
return poly.calculateNormal(); }
}
@Override
@Override public TesselatedPolygon tesselate() {
public TesselatedPolygon tesselate() { return poly.tesselate();
return poly.tesselate(); }
}
@Override
@Override public LinearRing getExteriorRing() {
public LinearRing getExteriorRing() { return poly.getExteriorRing();
return poly.getExteriorRing(); }
}
@Override
@Override public List<LinearRing> getInnerRings() {
public List<LinearRing> getInnerRings() { return poly.getInnerRings();
return poly.getInnerRings(); }
}
@Override
@Override public boolean isPointInsideExteriorRing(Vector3d v) {
public boolean isPointInsideExteriorRing(Vector3d v) { return poly.isPointInsideExteriorRing(v);
return poly.isPointInsideExteriorRing(v); }
}
@Override
@Override public Geometry getParent() {
public Geometry getParent() { return parent;
return parent; }
}
@Override
@Override public void setParent(Geometry geometry) {
public void setParent(Geometry geometry) { this.parent = geometry;
this.parent = geometry; }
}
@Override
@Override public void setExteriorRing(LinearRing extRing) {
public void setExteriorRing(LinearRing extRing) { poly.setExteriorRing(extRing);
poly.setExteriorRing(extRing); }
}
@Override
@Override public boolean isPolygonConnectedViaPoint(Polygon other) {
public boolean isPolygonConnectedViaPoint(Polygon other) { return poly.isPolygonConnectedViaPoint(other);
return poly.isPolygonConnectedViaPoint(other); }
}
@Override
@Override public String toString() {
public String toString() { return "LinkedPolygon [" + poly.getGmlId() + "]";
return "LinkedPolygon [" + poly.getGmlId() + "]"; }
}
@Override
@Override public void addInteriorRing(LinearRing inter) {
public void addInteriorRing(LinearRing inter) { poly.addInteriorRing(inter);
poly.addInteriorRing(inter); }
}
@Override
@Override public BoundarySurface getPartOfSurface() {
public BoundarySurface getPartOfSurface() { return poly.getPartOfSurface();
return poly.getPartOfSurface(); }
}
@Override
@Override public void setPartOfSurface(BoundarySurface bs) {
public void setPartOfSurface(BoundarySurface bs) { poly.setPartOfSurface(bs);
poly.setPartOfSurface(bs); }
}
@Override
@Override public void removeInnerRing(LinearRing ring) {
public void removeInnerRing(LinearRing ring) { poly.removeInnerRing(ring);
poly.removeInnerRing(ring); }
}
@Override
@Override public void setPartOfInstallation(Installation bi) {
public void setPartOfInstallation(Installation bi) { poly.setPartOfInstallation(bi);
poly.setPartOfInstallation(bi); }
}
@Override
@Override public Installation getPartOfInstallation() {
public Installation getPartOfInstallation() { return poly.getPartOfInstallation();
return poly.getPartOfInstallation(); }
}
@Override
@Override public boolean hasPointAsCorner(Vertex v) {
public boolean hasPointAsCorner(Vertex v) { return poly.hasPointAsCorner(v);
return poly.hasPointAsCorner(v); }
}
@Override
@Override public void removeRings() {
public void removeRings() { poly.removeRings();
poly.removeRings(); }
}
@Override
@Override public boolean isLink() {
public boolean isLink() { return true;
return true; }
}
@Override
@Override public LinkedPolygon getLinkedFromPolygon() {
public LinkedPolygon getLinkedFromPolygon() { return this;
return this; }
}
@Override
@Override void anonymize() {
void anonymize() { poly.anonymize();
poly.anonymize(); }
}
@Override
@Override public void clearAllContainedCheckResults() {
public void clearAllContainedCheckResults() { poly.clearAllContainedCheckResults();
poly.clearAllContainedCheckResults(); }
}
@Override
@Override public ConcretePolygon getOriginal() {
public ConcretePolygon getOriginal() { return poly;
return poly; }
}
@Override
@Override public void prepareForChecking() {
public void prepareForChecking() { poly.prepareForChecking();
poly.prepareForChecking(); }
}
@Override
@Override public void clearMetaInformation() {
public void clearMetaInformation() { poly.clearMetaInformation();
poly.clearMetaInformation(); }
}
@Override
@Override public boolean isLinkedTo() {
public boolean isLinkedTo() { return false;
return false; }
}
@Override
@Override public void collectInstances(CopyHandler handler) {
public void collectInstances(CopyHandler handler) { handler.addInstance(parent);
handler.addInstance(parent); handler.addInstance(poly);
handler.addInstance(poly); }
}
@Override
@Override public Copyable createCopyInstance() {
public Copyable createCopyInstance() { return new LinkedPolygon();
return new LinkedPolygon(); }
}
@Override
@Override public void fillValues(Copyable original, CopyHandler handler) {
public void fillValues(Copyable original, CopyHandler handler) { LinkedPolygon linkedOriginal = (LinkedPolygon) original;
LinkedPolygon linkedOriginal = (LinkedPolygon) original; parent = handler.getCopyInstance(linkedOriginal.parent);
parent = handler.getCopyInstance(linkedOriginal.parent); poly = handler.getCopyInstance(linkedOriginal.poly);
poly = handler.getCopyInstance(linkedOriginal.poly); }
}
@Override
@Override public void remove() {
public void remove() { poly.remove();
poly.remove(); }
}
@Override
@Override public double getArea() {
public double getArea() { return poly.getArea();
return poly.getArea(); }
}
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -20,24 +20,23 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -20,24 +20,23 @@ package de.hft.stuttgart.citydoctor2.datastructure;
/** /**
* The different LODs available in CityGML * The different LODs available in CityGML
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public enum Lod { 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) { private Lod(int rank) {
this.rank = rank; this.rank = rank;
} }
public boolean isHigher(Lod other) { public boolean isHigher(Lod other) {
if (other == null) { if (other == null) {
return true; return true;
} }
return rank > other.rank; return rank > other.rank;
} }
} }
/*- /*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* *
* This file is part of CityDoctor2. * This file is part of CityDoctor2.
* *
* CityDoctor2 is free software: you can redistribute it and/or modify * CityDoctor2 is free software: you can redistribute it and/or modify
...@@ -18,17 +18,16 @@ ...@@ -18,17 +18,16 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; 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.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable; 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; import java.io.Serial;
...@@ -36,145 +35,144 @@ 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. * 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 * Contains a reference to the boundary surface where this opening is embedded
* in. * in.
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public class Opening extends CityObject { public class Opening extends CityObject {
@Serial @Serial
private static final long serialVersionUID = 6409303152284607944L; private static final long serialVersionUID = 6409303152284607944L;
private BoundarySurface partOf; private BoundarySurface partOf;
private OpeningType type; private OpeningType type;
private SurfaceFeatureType featureType; private SurfaceFeatureType featureType;
private AbstractFillingSurface ao; private AbstractFillingSurface ao;
private Opening(OpeningType type) { private Opening(OpeningType type) {
this.type = type; this.type = type;
} }
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf, public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
AbstractFillingSurface ao) { AbstractFillingSurface ao) {
this.featureType = featureType; this.featureType = featureType;
this.partOf = partOf; this.partOf = partOf;
this.type = type; this.type = type;
this.ao = ao; this.ao = ao;
} }
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
if (ao.getId() != null) { if (ao.getId() != null) {
ao.setId(getGmlId().getGmlString()); ao.setId(getGmlId().getGmlString());
} }
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) { if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms)); setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
} else { } else {
throw new IllegalStateException("Openings can only have MultiSurface geometries"); throw new IllegalStateException("Openings can only have MultiSurface geometries");
} }
} }
} }
private void setGeometryAccordingToLod(Lod lod, MultiSurfaceProperty ms) { private void setGeometryAccordingToLod(Lod lod, MultiSurfaceProperty ms) {
switch (lod) { switch (lod) {
case LOD0: case LOD0:
ao.setLod0MultiSurface(ms); ao.setLod0MultiSurface(ms);
break; break;
case LOD1: case LOD1:
ao.setLod1MultiSurface(ms); ao.setLod1MultiSurface(ms);
break; break;
case LOD2: case LOD2:
ao.setLod2MultiSurface(ms); ao.setLod2MultiSurface(ms);
break; break;
case LOD3: case LOD3:
ao.setLod3MultiSurface(ms); ao.setLod3MultiSurface(ms);
break; break;
case LOD4: case LOD4:
ao.getDeprecatedProperties().setLod4MultiSurface(ms); ao.getDeprecatedProperties().setLod4MultiSurface(ms);
break; break;
default: default:
throw new IllegalStateException("Cannot add geometry to opening because lod is not allowed: " + lod); throw new IllegalStateException("Cannot add geometry to opening because lod is not allowed: " + lod);
} }
} }
public SurfaceFeatureType getSurfaceFeatureType() { public SurfaceFeatureType getSurfaceFeatureType() {
return featureType; return featureType;
} }
public BoundarySurface getPartOf() { public BoundarySurface getPartOf() {
return partOf; return partOf;
} }
public void setType(OpeningType type) { public void setType(OpeningType type) {
this.type = type; this.type = type;
} }
public OpeningType getType() { public OpeningType getType() {
return type; return type;
} }
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
} }
@Override @Override
public void clearAllContainedCheckResults() { public void clearAllContainedCheckResults() {
super.clearCheckResults(); super.clearCheckResults();
} }
public void unsetGmlGeometries() { public void unsetGmlGeometries() {
ao.setLod0MultiSurface(null); ao.setLod0MultiSurface(null);
ao.setLod1MultiSurface(null); ao.setLod1MultiSurface(null);
ao.setLod2MultiSurface(null); ao.setLod2MultiSurface(null);
ao.setLod3MultiSurface(null); ao.setLod3MultiSurface(null);
ao.getDeprecatedProperties().setLod4MultiSurface(null); ao.getDeprecatedProperties().setLod4MultiSurface(null);
} }
@Override @Override
public String toString() { public String toString() {
return "Opening [type=" + type + ", id=" + getGmlId() + "]"; return "Opening [type=" + type + ", id=" + getGmlId() + "]";
} }
public void setPartOfSurface(BoundarySurface boundarySurface) { public void setPartOfSurface(BoundarySurface boundarySurface) {
partOf = boundarySurface; partOf = boundarySurface;
} }
@Override @Override
public AbstractCityObject getGmlObject() { public AbstractCityObject getGmlObject() {
return ao; return ao;
} }
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.OPENING; return FeatureType.OPENING;
} }
@Override @Override
public Copyable createCopyInstance() { public Copyable createCopyInstance() {
return new Opening(type); return new Opening(type);
} }
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
super.collectInstances(handler); super.collectInstances(handler);
handler.addInstance(partOf); handler.addInstance(partOf);
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler); super.fillValues(original, handler);
Opening originalOpening = (Opening) original; Opening originalOpening = (Opening) original;
partOf = handler.getCopyInstance(originalOpening.partOf); partOf = handler.getCopyInstance(originalOpening.partOf);
type = originalOpening.type; type = originalOpening.type;
featureType = originalOpening.featureType; featureType = originalOpening.featureType;
ao = originalOpening.ao; 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