Commit 4e5dbdb9 authored by Matthias Betz's avatar Matthias Betz
Browse files

add check for missing ground surfaces

parent bdb267ae
Pipeline #9139 passed with stage
in 59 seconds
......@@ -53,6 +53,7 @@ public class CheckId implements Serializable {
public static final CheckId C_SE_BS_ROOF_UNFRAGMENTED = new CheckId("C_SE_BS_ROOF_UNFRAGMENTED");
public static final CheckId C_GE_S_NOT_CLOSED = new CheckId("C_GE_S_NOT_CLOSED");
public static final CheckId C_GE_P_ORIENTATION_RINGS_SAME = new CheckId("C_GE_P_ORIENTATION_RINGS_SAME");
public static final CheckId C_SE_POLYGON_WITHOUT_SURFACE = new CheckId("C_SE_POLYGON_WITHOUT_SURFACE");
private String name;
......
......@@ -63,6 +63,7 @@ public class ErrorId implements Serializable {
public static final ErrorId SE_SCHEMATRON_ERROR = new ErrorId("SE_SCHEMATRON_ERROR");
public static final ErrorId SE_BS_UNFRAGMENTED = new ErrorId("SE_BS_UNFRAGMENTED");
public static final ErrorId GE_P_DEGENERATED_RING = new ErrorId("GE_P_DEGENERATED_POLYGON");
public static final ErrorId SE_POLYGON_WITHOUT_SURFACE = new ErrorId("SE_POLYGON_WITHOUT_SURFACE");
private String name;
......
......@@ -40,6 +40,7 @@ import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
......@@ -130,6 +131,8 @@ public interface ErrorVisitor {
public void visit(AttributeValueWrongError err);
public void visit(AttributeInvalidError cdErr);
public void visit(AttributeInvalidError err);
public void visit(PolygonWithoutSurfaceError err);
}
......@@ -36,6 +36,7 @@ public class HealingID {
public static final HealingID S_NOT_CLOSED = new HealingID("S_NOT_CLOSED");
public static final HealingID P_NON_PLANAR_POLYGON_CPP = new HealingID("P_NON_PLANAR_POLYGON_CPP");
public static final HealingID S_NOT_CLOSED_CPP = new HealingID("S_NOT_CLOSED_CPP");
public static final HealingID SE_POLYGON_WITHOUT_SURFACE = new HealingID("SE_POLYGON_WITHOUT_SURFACE");
private String idString;
......
......@@ -39,6 +39,7 @@ import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
......@@ -195,6 +196,10 @@ public interface HealingMethod {
default boolean visit(AttributeMissingError err, ModificationListener l) {
return false;
}
default boolean visit(PolygonWithoutSurfaceError err, ModificationListener l) {
return false;
}
public HealingMethod createNew();
......
......@@ -46,6 +46,7 @@ import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
......@@ -398,4 +399,9 @@ public class QualityAdeErrorVisitor implements ErrorVisitor {
res.getErrors().add(new AbstractErrorProperty(err));
}
@Override
public void visit(PolygonWithoutSurfaceError err) {
// not translated
}
}
......@@ -66,7 +66,8 @@ public class Requirement implements Serializable {
public static final Requirement R_SE_BS_IS_FLOOR = new Requirement("R_SE_BS_IS_FLOOR", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_WALL = new Requirement("R_SE_BS_IS_WALL", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_GROUND = new Requirement("R_SE_BS_IS_GROUND", RequirementType.SEMANTIC);
public static final Requirement R_SE_POLYGON_WITHOUT_SURFACE = new Requirement("R_SE_POLYGON_WITHOUT_SURFACE", RequirementType.SEMANTIC);
static {
// fill requirements with default parameters
ArrayList<DefaultParameter> defaultParameters = new ArrayList<>();
......
package de.hft.stuttgart.citydoctor2.check.error;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
import de.hft.stuttgart.citydoctor2.check.ErrorType;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
public class PolygonWithoutSurfaceError implements CheckError {
private static final long serialVersionUID = 2676579487514583105L;
private Polygon p;
public PolygonWithoutSurfaceError(Polygon polygon) {
p = polygon;
}
@Override
public ErrorType getType() {
return ErrorType.ERROR;
}
@Override
public ErrorId getErrorId() {
return ErrorId.SE_POLYGON_WITHOUT_SURFACE;
}
public Polygon getPolygon() {
return p;
}
@Override
public GmlElement getFeature() {
return p;
}
@Override
public void accept(ErrorVisitor errorVisitor) {
errorVisitor.visit(this);
}
@Override
public boolean accept(HealingMethod method, ModificationListener l) {
return method.visit(this, l);
}
@Override
public void report(ErrorReport report) {
report.add(p);
}
}
......@@ -91,6 +91,16 @@ public abstract class CityObject extends GmlElement {
}
}
}
public void removeGeometry(Lod lod, GeometryType type) {
Iterator<Geometry> it = geometryList.iterator();
while (it.hasNext()) {
Geometry next = it.next();
if (next.getLod() == lod && next.getType() == type) {
it.remove();
}
}
}
public Geometry getHighestLodGeometry() {
Geometry highestLodGeometry = null;
......
......@@ -147,7 +147,7 @@ public class Citygml3GeometryMapper extends GeometryWalker {
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z / config.getFromMetres();
z = z / config.getFromMeters();
}
x = round(x, config.getNumberOfRoundingPlaces());
y = round(y, config.getNumberOfRoundingPlaces());
......
......@@ -451,9 +451,9 @@ public class CityGmlParser {
double fromMetres = projection.getFromMetres();
if (fromMetres > 0) {
// also transform height information
config.setFromMetres(fromMetres);
config.setFromMeters(fromMetres);
} else {
config.setFromMetres(1.0);
config.setFromMeters(1.0);
}
}
......
......@@ -48,7 +48,7 @@ public class ParserConfiguration implements Serializable {
private boolean hasTransformation = false;
private boolean useLowMemoryConsumption = false;
private transient double fromMetres = 1.0;
private transient double fromMeters = 1.0;
public ParserConfiguration(int numberOfRoundingPlaces, boolean validate) {
this(numberOfRoundingPlaces, validate, false);
......@@ -106,12 +106,12 @@ public class ParserConfiguration implements Serializable {
return originalTransform;
}
public void setFromMetres(double d) {
fromMetres = d;
public void setFromMeters(double d) {
fromMeters = d;
}
public double getFromMetres() {
return fromMetres;
public double getFromMeters() {
return fromMeters;
}
public boolean useLowMemoryConsumption() {
......
......@@ -59,12 +59,22 @@ public final class CityGmlUtils {
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon();
// exterior ring
LinearRing extLr = cdPoly.getExteriorRing();
if (extLr.getVertices().size() < 3) {
// this ring does not have enough points in it
// this leads to errors when exporting therefore ignore it
return null;
}
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new AbstractRingProperty(gmlLr));
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) {
gmlLr = createGmlRing(factory, config, lr);
if (lr.getVertices().size() < 3) {
// this ring does not have enough points in it
// this leads to errors when exporting therefore ignore it
return null;
}
gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr));
}
gmlPoly.setId(cdPoly.getGmlId().getGmlString());
......@@ -73,6 +83,7 @@ public final class CityGmlUtils {
public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) {
ProjCoordinate p1 = new ProjCoordinate();
ProjCoordinate p2 = new ProjCoordinate();
List<Double> ringValues = new ArrayList<>();
......@@ -87,12 +98,13 @@ public final class CityGmlUtils {
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z * config.getFromMetres();
z = z * config.getFromMeters();
}
ringValues.add(x);
ringValues.add(y);
ringValues.add(z);
}
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
gmlLr.setId(lr.getGmlId().getGmlString());
return gmlLr;
......
......@@ -52,6 +52,7 @@ import de.hft.stuttgart.citydoctor2.checks.semantics.IsCeilingCheck;
import de.hft.stuttgart.citydoctor2.checks.semantics.IsFloorCheck;
import de.hft.stuttgart.citydoctor2.checks.semantics.IsGroundCheck;
import de.hft.stuttgart.citydoctor2.checks.semantics.IsWallCheck;
import de.hft.stuttgart.citydoctor2.checks.semantics.PolygonWithoutSurfaceCheck;
import de.hft.stuttgart.citydoctor2.checks.semantics.RoofSurfaceUnfragmentedCheck;
import de.hft.stuttgart.citydoctor2.utils.Localization;
......@@ -110,6 +111,7 @@ public class Checks {
publish(new IsCeilingCheck());
publish(new IsGroundCheck());
publish(new RoofSurfaceUnfragmentedCheck());
publish(new PolygonWithoutSurfaceCheck());
// load checks from service loader
ServiceLoader<Check> checkLoader = ServiceLoader.load(Check.class);
......
package de.hft.stuttgart.citydoctor2.checks.semantics;
import java.util.Collections;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
public class PolygonWithoutSurfaceCheck extends Check {
@Override
public void check(Polygon poly) {
Lod lod = poly.getParent().getLod();
if (lod == Lod.LOD2 || lod == Lod.LOD3 || lod == Lod.LOD4) {
// only check LOD2-4
CheckResult cr;
if (poly.getPartOfSurface() == null) {
PolygonWithoutSurfaceError err = new PolygonWithoutSurfaceError(poly);
cr = new CheckResult(this, ResultStatus.ERROR, err);
} else {
cr = new CheckResult(this, ResultStatus.OK, null);
}
poly.addCheckResult(cr);
}
}
@Override
public Set<Requirement> appliesToRequirements() {
return Collections.singleton(Requirement.R_SE_POLYGON_WITHOUT_SURFACE);
}
@Override
public CheckId getCheckId() {
return CheckId.C_SE_POLYGON_WITHOUT_SURFACE;
}
@Override
public RequirementType getType() {
return RequirementType.SEMANTIC;
}
@Override
public Check createNewInstance() {
return new PolygonWithoutSurfaceCheck();
}
}
package de.hft.stuttgart.citydoctor2.checks.semantics;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
public class PolygonWithoutSurfaceCheckTest {
@Test
public void testPolygonWithoutSurface() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
Polygon poly = new ConcretePolygon();
geom.addPolygon(poly);
PolygonWithoutSurfaceCheck check = new PolygonWithoutSurfaceCheck();
poly.accept(check);
CheckResult checkResult = poly.getCheckResult(check);
assertNotNull(checkResult);
assertEquals(ResultStatus.ERROR, checkResult.getResultStatus());
assertEquals(CheckId.C_SE_POLYGON_WITHOUT_SURFACE, checkResult.getCheckIdentifier());
CheckError error = checkResult.getError();
assertNotNull(error);
assertEquals(ErrorId.SE_POLYGON_WITHOUT_SURFACE, error.getErrorId());
assertTrue(error instanceof PolygonWithoutSurfaceError);
PolygonWithoutSurfaceError errorCast = (PolygonWithoutSurfaceError) error;
assertSame(poly, errorCast.getPolygon());
}
@Test
public void testPolygonWithSurface() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
Polygon poly = new ConcretePolygon();
BoundarySurface bs = new BoundarySurface(null);
bs.addGeometry(geom);
geom.addPolygon(poly);
PolygonWithoutSurfaceCheck check = new PolygonWithoutSurfaceCheck();
poly.accept(check);
CheckResult checkResult = poly.getCheckResult(check);
assertNotNull(checkResult);
assertEquals(ResultStatus.OK, checkResult.getResultStatus());
assertEquals(CheckId.C_SE_POLYGON_WITHOUT_SURFACE, checkResult.getCheckIdentifier());
CheckError error = checkResult.getError();
assertNull(error);
}
@Test
public void testPolygonWithWrongLod() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
Polygon poly = new ConcretePolygon();
BoundarySurface bs = new BoundarySurface(null);
bs.addGeometry(geom);
geom.addPolygon(poly);
PolygonWithoutSurfaceCheck check = new PolygonWithoutSurfaceCheck();
poly.accept(check);
CheckResult checkResult = poly.getCheckResult(check);
assertNull(checkResult);
}
}
......@@ -103,12 +103,12 @@
<dependency>
<groupId>org.citygml4j</groupId>
<artifactId>citygml4j-core</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.citygml4j</groupId>
<artifactId>citygml4j-xml</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>de.hft.stuttgart</groupId>
......@@ -156,6 +156,11 @@
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
......
Markdown is supported
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