Commit 3dac795e authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

Version 3.17.0 Release

See merge request !28
1 merge request!28Version 3.17.0 Release
Pipeline #11012 passed with stage
in 1 minute and 10 seconds
Showing with 207 additions and 64 deletions
+207 -64
...@@ -52,6 +52,11 @@ public class Building extends AbstractBuilding { ...@@ -52,6 +52,11 @@ public class Building extends AbstractBuilding {
} }
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
@Override @Override
public void accept(Check c) { public void accept(Check c) {
super.accept(c); super.accept(c);
......
...@@ -42,6 +42,11 @@ public class BuildingPart extends AbstractBuilding { ...@@ -42,6 +42,11 @@ public class BuildingPart extends AbstractBuilding {
return parent; return parent;
} }
@Override
public CityObject getTopLevelCityObject() {
return getParent().getTopLevelCityObject();
}
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.BUILDING_PART; return FeatureType.BUILDING_PART;
......
...@@ -50,6 +50,11 @@ public class BuildingRoom extends AbstractRoom { ...@@ -50,6 +50,11 @@ public class BuildingRoom extends AbstractRoom {
parent = handler.getCopyInstance(oRoom.getParent()); parent = handler.getCopyInstance(oRoom.getParent());
} }
@Override
public CityObject getTopLevelCityObject() {
return getParent().getTopLevelCityObject();
}
@Override @Override
public void collectInstances(CopyHandler handler) { public void collectInstances(CopyHandler handler) {
super.collectInstances(handler); super.collectInstances(handler);
......
...@@ -126,4 +126,8 @@ public class BuildingUnit extends AbstractBuildingSubdivision { ...@@ -126,4 +126,8 @@ public class BuildingUnit extends AbstractBuildingSubdivision {
} }
this.abs = originalBu.abs; this.abs = originalBu.abs;
} }
public List<Storey> getStoreys() {
return storeys;
}
} }
...@@ -50,6 +50,11 @@ public class CityFurniture extends CityObject { ...@@ -50,6 +50,11 @@ public class CityFurniture extends CityObject {
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(null); cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(null);
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
@Override @Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
...@@ -71,12 +76,18 @@ public class CityFurniture extends CityObject { ...@@ -71,12 +76,18 @@ public class CityFurniture extends CityObject {
case LOD0: case LOD0:
cgmlCityFurniture.setLod0MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD1:
cgmlCityFurniture.getDeprecatedProperties().setLod1Geometry(new MultiSurfaceProperty(ms));
break;
case LOD2: case LOD2:
cgmlCityFurniture.setLod2MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD3: case LOD3:
cgmlCityFurniture.setLod3MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD4:
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(new MultiSurfaceProperty(ms));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings");
} }
...@@ -93,6 +104,8 @@ public class CityFurniture extends CityObject { ...@@ -93,6 +104,8 @@ public class CityFurniture extends CityObject {
case LOD3: case LOD3:
cgmlCityFurniture.setLod3Solid(new SolidProperty(solid)); cgmlCityFurniture.setLod3Solid(new SolidProperty(solid));
break; break;
case LOD4:
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
} }
......
...@@ -102,6 +102,11 @@ public abstract class CityObject extends GmlElement { ...@@ -102,6 +102,11 @@ public abstract class CityObject extends GmlElement {
return highestLodGeometry; return highestLodGeometry;
} }
/**
* Returns the top-level CityObject (like Building or Tunnel) belonging to this object.
*/
public abstract CityObject getTopLevelCityObject();
public void addGenericAttribute(GenericAttribute genericAttribute) { public void addGenericAttribute(GenericAttribute genericAttribute) {
genericAttributeList.add(genericAttribute); genericAttributeList.add(genericAttribute);
} }
......
...@@ -2,6 +2,7 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -2,6 +2,7 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -9,7 +10,7 @@ import java.util.List; ...@@ -9,7 +10,7 @@ import java.util.List;
* *
* @author Riegel * @author Riegel
*/ */
public final class CompositeCollection { public final class CompositeCollection implements Serializable {
@Serial @Serial
private static final long serialVersionUID = -1867197873443341287L; private static final long serialVersionUID = -1867197873443341287L;
...@@ -31,6 +32,7 @@ public final class CompositeCollection { ...@@ -31,6 +32,7 @@ public final class CompositeCollection {
return childComposites; return childComposites;
} }
//TODO stream
public List<ConcretePolygon> getCompositeMembers() { public List<ConcretePolygon> getCompositeMembers() {
List<ConcretePolygon> copy = new ArrayList<>(compositeMembers); List<ConcretePolygon> copy = new ArrayList<>(compositeMembers);
for (CompositeCollection c : childComposites) { for (CompositeCollection c : childComposites) {
......
...@@ -50,6 +50,7 @@ public class ConcretePolygon extends Polygon { ...@@ -50,6 +50,7 @@ public class ConcretePolygon extends Polygon {
private BoundarySurface partOfSurface; private BoundarySurface partOfSurface;
private Installation partfOfInstallation; private Installation partfOfInstallation;
private CompositeCollection partOfComposite = null; private CompositeCollection partOfComposite = null;
private PatchCollection partOfPatch = null;
private Geometry parent; private Geometry parent;
private LinkedPolygon linkedFromPolygon; private LinkedPolygon linkedFromPolygon;
...@@ -141,6 +142,18 @@ public class ConcretePolygon extends Polygon { ...@@ -141,6 +142,18 @@ public class ConcretePolygon extends Polygon {
this.partOfComposite = comp; this.partOfComposite = comp;
} }
protected void setPartOfPatch(PatchCollection pc) {
this.partOfPatch = pc;
}
public PatchCollection getPartOfPatch(PatchCollection pc) {
return partOfPatch;
}
public boolean isPatchMember() {
return partOfPatch != null;
}
public CompositeCollection getPartOfComposite() { public CompositeCollection getPartOfComposite() {
return partOfComposite; return partOfComposite;
} }
......
...@@ -26,7 +26,7 @@ public class GenericAttribute { ...@@ -26,7 +26,7 @@ public class GenericAttribute {
if (attributeProperty.getObject() instanceof StringAttribute sa) { if (attributeProperty.getObject() instanceof StringAttribute sa) {
type = "StringAttribute"; type = "StringAttribute";
value = sa.getValue(); value = String.format("\"%s\"", sa.getValue());
} else if (attributeProperty.getObject() instanceof IntAttribute ia) { } else if (attributeProperty.getObject() instanceof IntAttribute ia) {
type = "IntAttribute"; type = "IntAttribute";
value = ia.getValue().toString(); value = ia.getValue().toString();
...@@ -41,10 +41,10 @@ public class GenericAttribute { ...@@ -41,10 +41,10 @@ public class GenericAttribute {
value = ua.getValue(); value = ua.getValue();
} else if (attributeProperty.getObject() instanceof MeasureAttribute ma) { } else if (attributeProperty.getObject() instanceof MeasureAttribute ma) {
type = "MeasureAttribute"; type = "MeasureAttribute";
value = ma.getValue().toString(); value = String.format("%s %s", ma.getValue().getValue().toString(), ma.getValue().getUom());
} else if (attributeProperty.getObject() instanceof CodeAttribute ca) { } else if (attributeProperty.getObject() instanceof CodeAttribute ca) {
type = "CodeAttribute"; type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage());
value = ca.getValue().toString(); value = String.format("'''%s''' %n CodeSpace: %s", ca.getValue().getValue(), ca.getValue().getCodeSpace());
} else { } else {
logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject()); logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject());
value = attributeProperty.getObject().getValue().toString(); value = attributeProperty.getObject().getValue().toString();
......
...@@ -84,14 +84,20 @@ public class GenericCityObject extends CityObject { ...@@ -84,14 +84,20 @@ public class GenericCityObject extends CityObject {
case LOD0: case LOD0:
cgmlGos.setLod0MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD1:
cgmlGos.getDeprecatedProperties().setLod1Geometry(new MultiSurfaceProperty(ms));
break;
case LOD2: case LOD2:
cgmlGos.setLod2MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD3: case LOD3:
cgmlGos.setLod3MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD4:
cgmlGos.getDeprecatedProperties().setLod4Geometry(new MultiSurfaceProperty(ms));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to generic city object");
} }
} }
...@@ -106,6 +112,9 @@ public class GenericCityObject extends CityObject { ...@@ -106,6 +112,9 @@ public class GenericCityObject extends CityObject {
case LOD3: case LOD3:
cgmlGos.setLod3Solid(new SolidProperty(solid)); cgmlGos.setLod3Solid(new SolidProperty(solid));
break; break;
case LOD4:
cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
} }
...@@ -213,6 +222,11 @@ public class GenericCityObject extends CityObject { ...@@ -213,6 +222,11 @@ public class GenericCityObject extends CityObject {
} }
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
public void setGmlObject(org.citygml4j.core.model.generics.GenericOccupiedSpace gos) { public void setGmlObject(org.citygml4j.core.model.generics.GenericOccupiedSpace gos) {
this.cgmlGos = gos; this.cgmlGos = gos;
} }
......
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.List;
import org.citygml4j.core.model.core.ImplicitGeometry;
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.math.TransformationMatrix; 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 * Datastructure for representation and resolving of implicit geometries
...@@ -18,7 +17,6 @@ import java.util.List; ...@@ -18,7 +17,6 @@ import java.util.List;
*/ */
public class ImplicitGeometryHolder extends Geometry { public class ImplicitGeometryHolder extends Geometry {
private static final Logger logger = LogManager.getLogger(ImplicitGeometryHolder.class);
@Serial @Serial
private static final long serialVersionUID = -8938931081577196349L; private static final long serialVersionUID = -8938931081577196349L;
......
...@@ -195,6 +195,11 @@ public class Installation extends CityObject { ...@@ -195,6 +195,11 @@ public class Installation extends CityObject {
} }
} }
@Override
public CityObject getTopLevelCityObject() {
return getParent().getTopLevelCityObject();
}
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);
......
...@@ -105,6 +105,11 @@ public class LandObject extends CityObject { ...@@ -105,6 +105,11 @@ public class LandObject extends CityObject {
lu.getDeprecatedProperties().setLod4MultiSurface(null); lu.getDeprecatedProperties().setLod4MultiSurface(null);
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
public void setGmlObject(LandUse landUse) { public void setGmlObject(LandUse landUse) {
lu = landUse; lu = landUse;
} }
......
...@@ -4,17 +4,20 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; ...@@ -4,17 +4,20 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.Serial; import java.io.Serial;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Reference object for handling of implicit geometries with a library object contained in an external file * Reference object for handling of implicit geometries with a library object
* contained in an external file
* *
* @author Riegel * @author Riegel
*/ */
...@@ -23,8 +26,7 @@ public class LibraryObject extends Geometry { ...@@ -23,8 +26,7 @@ public class LibraryObject extends Geometry {
private static final Logger logger = LogManager.getLogger(LibraryObject.class); private static final Logger logger = LogManager.getLogger(LibraryObject.class);
@Serial @Serial
private static final long serialVersionUID = -50293435187454911L; private static final long serialVersionUID = -50293435187454911L;
private final String filepath;
private final ParserConfiguration config;
private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>(); private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
public static LibraryObject of(Path path, ParserConfiguration config) { public static LibraryObject of(Path path, ParserConfiguration config) {
...@@ -35,42 +37,45 @@ public class LibraryObject extends Geometry { ...@@ -35,42 +37,45 @@ public class LibraryObject extends Geometry {
if (protoGeom == null) { if (protoGeom == null) {
return null; return null;
} }
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod(), path, config); LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod());
protoGeom.getPolygons().forEach(libOb::addPolygon); protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices(); libOb.updateEdgesAndVertices();
libraryObjects.put(path.toString(), libOb); libraryObjects.put(path.toString(), libOb);
return libOb; return libOb;
} }
private LibraryObject(GeometryType type, Lod lod, Path path, ParserConfiguration config) { public static LibraryObject of(CityGmlZipEntry entry, ParserConfiguration config) {
String fileName = entry.getEntrySubPath();
if (libraryObjects.containsKey(fileName)){
return libraryObjects.get(fileName);
}
Geometry protoGeom = parseZipEntry(entry, config);
if (protoGeom == null) {
return null;
}
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod());
protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices();
libraryObjects.put(fileName, libOb);
return libOb;
}
private LibraryObject(GeometryType type, Lod lod) {
super(type, lod); super(type, lod);
this.filepath = path.toString();
this.config = config;
} }
private static Geometry parseFile(Path path, ParserConfiguration config) { private static Geometry parseFile(Path path, ParserConfiguration config) {
Geometry geo = null; Geometry geo = null;
if (path.toFile().exists()) { if (Files.exists(path)) {
try { try {
CityGmlParser.gagLogger(true); geo = getProtoGeometry(CityGmlParser.parseCityGmlFileSilently(path.toString(), config));
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) { } catch (CityGmlParseException e) {
logger.error(String.format( logger.error(String.format(
"Encountered an error while parsing library object %s", path)); "Encountered an error while parsing library object %s", path));
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
} catch (InvalidGmlFileException e) { } catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
} finally {
// Failsafe to remove gag should parsing fail
CityGmlParser.gagLogger(false);
} }
} else { } else {
logger.error(String.format("Implicit geometry references non-existing library object file %s.", path)); logger.error(String.format("Implicit geometry references non-existing library object file %s.", path));
...@@ -78,4 +83,32 @@ public class LibraryObject extends Geometry { ...@@ -78,4 +83,32 @@ public class LibraryObject extends Geometry {
return geo; return geo;
} }
private static Geometry parseZipEntry(CityGmlZipEntry entry, ParserConfiguration config) {
Geometry geo = null;
try {
entry.loadEntry(config);
geo = getProtoGeometry(entry.getModel());
} catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace());
} catch (CityGmlParseException e) {
logger.error(String.format(
"Encountered an error while parsing library object %s", entry.getEntrySubPath()));
logger.error(e.getStackTrace());
}
return geo;
}
private static Geometry getProtoGeometry(CityDoctorModel model) throws InvalidGmlFileException, CityGmlParseException {
if (model == null) {
throw new CityGmlParseException("CityDoctorModel of referenced LibraryObject is null");
}
List<CityObject> objects = model.createFeatureStream().toList();
if (objects.isEmpty()) {
throw new InvalidGmlFileException("Referenced library-object gml file does not contain any CityGML objects!");
} else if (objects.size() > 1) {
throw new InvalidGmlFileException("Referenced library-object gml file contains more than one CityGML object!");
}
return objects.get(0).getHighestLodGeometry();
}
} }
...@@ -135,6 +135,11 @@ public class Opening extends CityObject { ...@@ -135,6 +135,11 @@ public class Opening extends CityObject {
ao.getDeprecatedProperties().setLod4MultiSurface(null); ao.getDeprecatedProperties().setLod4MultiSurface(null);
} }
@Override
public CityObject getTopLevelCityObject() {
return partOf.getTopLevelCityObject();
}
@Override @Override
public String toString() { public String toString() {
return "Opening [type=" + type + ", id=" + getGmlId() + "]"; return "Opening [type=" + type + ", id=" + getGmlId() + "]";
......
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public final class PatchCollection implements Serializable {
@Serial
private static final long serialVersionUID = -1748657379840997228L;
private List<ConcretePolygon> patchMembers = new ArrayList<>();
public void addPatchMember(ConcretePolygon patchMember) {
patchMembers.add(patchMember);
patchMember.setPartOfPatch(this);
}
public List<ConcretePolygon> getPatchMembers() {
return new ArrayList<>(patchMembers);
}
}
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serial; import java.io.Serial;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
...@@ -15,7 +11,6 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -15,7 +11,6 @@ import java.util.concurrent.ConcurrentHashMap;
*/ */
public class RelativeGeometry extends Geometry { public class RelativeGeometry extends Geometry {
private static final Logger logger = LogManager.getLogger(RelativeGeometry.class);
@Serial @Serial
private static final long serialVersionUID = -686112245455298977L; private static final long serialVersionUID = -686112245455298977L;
...@@ -32,10 +27,7 @@ public class RelativeGeometry extends Geometry { ...@@ -32,10 +27,7 @@ public class RelativeGeometry extends Geometry {
return relGeo; return relGeo;
} }
private RelativeGeometry(GeometryType type, Lod lod) { private RelativeGeometry(GeometryType type, Lod lod) {
super(type, lod); super(type, lod);
} }
} }
...@@ -146,6 +146,11 @@ public class ReliefObject extends CityObject { ...@@ -146,6 +146,11 @@ public class ReliefObject extends CityObject {
// no geometries // no geometries
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.LAND; return FeatureType.LAND;
......
...@@ -125,4 +125,8 @@ public class Storey extends AbstractBuildingSubdivision { ...@@ -125,4 +125,8 @@ public class Storey extends AbstractBuildingSubdivision {
} }
this.abs = originalSt.abs; this.abs = originalSt.abs;
} }
public List<BuildingUnit> getBuildingUnits() {
return buildingUnits;
}
} }
...@@ -91,6 +91,11 @@ public class TinObject extends CityObject { ...@@ -91,6 +91,11 @@ public class TinObject extends CityObject {
gmlRelief.setTin(null); gmlRelief.setTin(null);
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.LAND; return FeatureType.LAND;
......
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