Commit b2d40f78 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev_citygml3' into 'dev'

CityGML 3.0. Support

See merge request !10
parents ec3bffa6 45b8f722
Pipeline #10321 passed with stage
in 1 minute and 35 seconds
...@@ -122,6 +122,9 @@ public class CityGmlParser { ...@@ -122,6 +122,9 @@ public class CityGmlParser {
private static CityGMLContext context; private static CityGMLContext context;
private static List<QName> chunkProperties = new ArrayList<>(); private static List<QName> chunkProperties = new ArrayList<>();
// Toggle to suppress logger output for parsing of libraryObjects
private static boolean gagged = false;
static { static {
System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
FACTORY = SAXParserFactory.newInstance(); FACTORY = SAXParserFactory.newInstance();
...@@ -326,20 +329,29 @@ public class CityGmlParser { ...@@ -326,20 +329,29 @@ public class CityGmlParser {
return writer; return writer;
} }
/**
* Suppresses logger output of {@link #readAndKeepFeatures} for the next parse.
* Used to prevent logging spam while resolving implicit geometries.
*/
public static void gagLogger(boolean value){
gagged = value;
}
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file, private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file,
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException { CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) { try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) {
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file); Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file);
CityGMLVersion version = null;
// model is read in chunked mode // model is read in chunked mode
// object members are replaced by href in model // object members are replaced by href in model
// need to remove the refs and re-add unparsed objects // need to remove the refs and re-add unparsed objects
List<AbstractCityObject> acos = new ArrayList<>(); List<AbstractCityObject> acos = new ArrayList<>();
while (reader.hasNext()) { while (reader.hasNext()) {
AbstractFeature chunk = reader.next(); AbstractFeature chunk = reader.next();
version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI());
if (chunk instanceof CityModel cModel) { if (chunk instanceof CityModel cModel) {
cModel.setCityObjectMembers(null); cModel.setCityObjectMembers(null);
mapper.setCityModel(cModel); mapper.setCityModel(cModel);
CityGMLVersion version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI());
mapper.setCityGMLVersion(version); mapper.setCityGMLVersion(version);
} else if (chunk instanceof AbstractCityObject aco) { } else if (chunk instanceof AbstractCityObject aco) {
acos.add(aco); acos.add(aco);
...@@ -362,10 +374,14 @@ public class CityGmlParser { ...@@ -362,10 +374,14 @@ public class CityGmlParser {
for (AbstractCityObject aco : acos) { for (AbstractCityObject aco : acos) {
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco));
} }
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled() && !gagged) {
logger.info(Localization.getText("CityGmlParser.parsedObjects"), logger.info(Localization.getText("CityGmlParser.parsedObjects"),
mapper.getModel().getNumberOfFeatures()); mapper.getModel().getNumberOfFeatures());
} else if (gagged){
// Remove gag
gagged = false;
} }
mapper.setCityGMLVersion(version);
return mapper.getModel(); return mapper.getModel();
} }
} }
......
/*- /*-
* 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,181 +18,198 @@ ...@@ -18,181 +18,198 @@
*/ */
package de.hft.stuttgart.citydoctor2.utils; package de.hft.stuttgart.citydoctor2.utils;
import java.util.ArrayList; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import java.util.List; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
import org.locationtech.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate; import org.locationtech.proj4j.ProjCoordinate;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface; import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty; import org.xmlobjects.gml.model.geometry.primitives.*;
import org.xmlobjects.gml.model.geometry.primitives.Shell;
import org.xmlobjects.gml.model.geometry.primitives.ShellProperty; import java.util.ArrayList;
import org.xmlobjects.gml.model.geometry.primitives.Solid; import java.util.HashSet;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty; import java.util.List;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
/** /**
* Utility class dedicated to create CityGML4j datastructures. * Utility class dedicated to create CityGML4j datastructures.
*
* @author Matthias Betz
* *
* @author Matthias Betz
*/ */
public final class CityGmlUtils { public final class CityGmlUtils {
private CityGmlUtils() {
// util class private CityGmlUtils() {
} // util class
}
public static org.xmlobjects.gml.model.geometry.primitives.Polygon createGmlPolygon(GeometryFactory factory,
Polygon cdPoly, ParserConfiguration config) { public static org.xmlobjects.gml.model.geometry.primitives.Polygon createGmlPolygon(GeometryFactory factory,
if (cdPoly.getExteriorRing() == null) { Polygon cdPoly, ParserConfiguration config) {
return null; if (cdPoly.getExteriorRing() == null) {
} return null;
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon(); }
// exterior ring org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon();
LinearRing extLr = cdPoly.getExteriorRing(); // exterior ring
if (extLr.getVertices().size() < 3) { LinearRing extLr = cdPoly.getExteriorRing();
// this ring does not have enough points in it if (extLr.getVertices().size() < 3) {
// this leads to errors when exporting therefore ignore it // this ring does not have enough points in it
return null; // 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)); org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new AbstractRingProperty(gmlLr));
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) { // interior rings
gmlLr = createGmlRing(factory, config, lr); for (LinearRing lr : cdPoly.getInnerRings()) {
if (lr.getVertices().size() < 3) { gmlLr = createGmlRing(factory, config, lr);
// this ring does not have enough points in it if (lr.getVertices().size() < 3) {
// this leads to errors when exporting therefore ignore it // this ring does not have enough points in it
return null; // this leads to errors when exporting therefore ignore it
} return null;
gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr)); }
} gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr));
gmlPoly.setId(cdPoly.getGmlId().getGmlString()); }
return gmlPoly; gmlPoly.setId(cdPoly.getGmlId().getGmlString());
} return gmlPoly;
}
public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) { public static CompositeSurface createGmlComposite(GeometryFactory factory, CompositeCollection comp,
ParserConfiguration config) {
ProjCoordinate p1 = new ProjCoordinate(); List<SurfaceProperty> surfaces = new ArrayList<>();
ProjCoordinate p2 = new ProjCoordinate(); for (ConcretePolygon cd : comp.getNonRecursiveCompositeMembers()) {
List<Double> ringValues = new ArrayList<>(); surfaces.add(new SurfaceProperty(createGmlPolygon(factory, cd, config)));
BasicCoordinateTransform trans = config.getOriginalTransform(); }
for (Vertex v : lr.getVertices()) { for (CompositeCollection cc : comp.getChildComposites()) {
double x = v.getX(); surfaces.add(new SurfaceProperty(createGmlComposite(factory, cc, config)));
double y = v.getY(); }
double z = v.getZ(); if (surfaces.isEmpty()) {
if (trans != null) { return null;
p1.x = x; }
p1.y = y; return new CompositeSurface(surfaces);
trans.transform(p1, p2); }
x = p2.x;
y = p2.y;
z = z * config.getFromMeters(); public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
} ParserConfiguration config, LinearRing lr) {
ringValues.add(x);
ringValues.add(y); ProjCoordinate p1 = new ProjCoordinate();
ringValues.add(z); ProjCoordinate p2 = new ProjCoordinate();
} List<Double> ringValues = new ArrayList<>();
BasicCoordinateTransform trans = config.getOriginalTransform();
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3); for (Vertex v : lr.getVertices()) {
gmlLr.setId(lr.getGmlId().getGmlString()); double x = v.getX();
return gmlLr; double y = v.getY();
} double z = v.getZ();
if (trans != null) {
public static Solid createSolid(Geometry geom, GeometryFactory factory, ParserConfiguration config) { p1.x = x;
if (geom.getType() != GeometryType.SOLID) { p1.y = y;
throw new IllegalArgumentException("Only solids are allowed"); trans.transform(p1, p2);
} x = p2.x;
y = p2.y;
CompositeSurface comp = new CompositeSurface(); z = z * config.getFromMeters();
List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers(); }
for (Polygon cdPoly : geom.getPolygons()) { ringValues.add(x);
if (!cdPoly.isLink()) { ringValues.add(y);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); ringValues.add(z);
if (gmlPoly != null) { }
surfaceMember.add(new SurfaceProperty(gmlPoly));
} org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
} else { gmlLr.setId(lr.getGmlId().getGmlString());
// add reference to polygon return gmlLr;
surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString())); }
}
} public static Solid createSolid(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
if (geom.getType() != GeometryType.SOLID) {
if (surfaceMember.isEmpty()) { throw new IllegalArgumentException("Only solids are allowed");
return null; }
}
Solid solid = new Solid(); CompositeSurface comp = new CompositeSurface();
Shell shell = new Shell(surfaceMember); List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers();
solid.setExterior(new ShellProperty(shell)); for (Polygon cdPoly : geom.getPolygons()) {
solid.setId(geom.getGmlId().getGmlString()); if (!cdPoly.isLink()) {
return solid; org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
} if (gmlPoly != null) {
surfaceMember.add(new SurfaceProperty(gmlPoly));
public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory, }
ParserConfiguration config) { } else {
if (geom.getType() != GeometryType.MULTI_SURFACE) { // add reference to polygon
throw new IllegalArgumentException("This can only handle MultiSurfaces"); surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
} }
List<SurfaceProperty> surfaces = new ArrayList<>(); }
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) { if (surfaceMember.isEmpty()) {
// is not part of a boundary surface return null;
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); }
if (gmlPoly != null) { Solid solid = new Solid();
surfaces.add(new SurfaceProperty(gmlPoly)); Shell shell = new Shell(surfaceMember);
} solid.setExterior(new ShellProperty(shell));
} else { solid.setId(geom.getGmlId().getGmlString());
// add reference to polygon return solid;
surfaces.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString())); }
}
} public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory,
if (surfaces.isEmpty()) { ParserConfiguration config) {
return null; if (geom.getType() != GeometryType.MULTI_SURFACE && geom.getType() != GeometryType.COMPOSITE_SURFACE) {
} throw new IllegalArgumentException("This can only handle MultiSurfaces");
MultiSurface ms = new MultiSurface(surfaces); }
ms.setId(geom.getGmlId().getGmlString()); List<SurfaceProperty> surfaces = new ArrayList<>();
return ms; Set<CompositeCollection> compositeCollections = new HashSet<>();
} for (Polygon cdPoly : geom.getPolygons()) {
if (cdPoly instanceof ConcretePolygon conc && conc.isCompositeMember()) {
public static MultiSurface createMultiSurface(List<Polygon> polygons, GeometryFactory factory, compositeCollections.add(conc.getPartOfComposite());
ParserConfiguration config) { } else if (!cdPoly.isLink()) {
List<SurfaceProperty> surfaces = new ArrayList<>(); // is not part of a boundary surface
for (Polygon cdPoly : polygons) { org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); if (gmlPoly != null) {
if (gmlPoly != null) { surfaces.add(new SurfaceProperty(gmlPoly));
surfaces.add(new SurfaceProperty(gmlPoly)); }
} } else {
} // add reference to polygon
if (surfaces.isEmpty()) { surfaces.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
return null; }
} }
return new MultiSurface(surfaces); for (CompositeCollection cdPoly : compositeCollections) {
} surfaces.add(new SurfaceProperty(createGmlComposite(factory, cdPoly, config)));
}
public static CompositeSurface createCompositeSurface(Geometry geom, GeometryFactory factory, if (surfaces.isEmpty()) {
ParserConfiguration config) { return null;
List<SurfaceProperty> surfaces = new ArrayList<>(); }
for (Polygon cdPoly : geom.getPolygons()) { MultiSurface ms = new MultiSurface(surfaces);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); ms.setId(geom.getGmlId().getGmlString());
if (gmlPoly != null) { return ms;
surfaces.add(new SurfaceProperty(gmlPoly)); }
}
} public static MultiSurface createMultiSurface(List<Polygon> polygons, GeometryFactory factory,
if (surfaces.isEmpty()) { ParserConfiguration config) {
return null; List<SurfaceProperty> surfaces = new ArrayList<>();
} for (Polygon cdPoly : polygons) {
return new CompositeSurface(surfaces); org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
} if (gmlPoly != null) {
surfaces.add(new SurfaceProperty(gmlPoly));
}
}
if (surfaces.isEmpty()) {
return null;
}
return new MultiSurface(surfaces);
}
public static CompositeSurface createCompositeSurface(Geometry geom, GeometryFactory factory,
ParserConfiguration config) {
List<SurfaceProperty> surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(new SurfaceProperty(gmlPoly));
}
}
if (surfaces.isEmpty()) {
return null;
}
return new CompositeSurface(surfaces);
}
} }
...@@ -68,7 +68,7 @@ public class CityGMLWriterUtils { ...@@ -68,7 +68,7 @@ public class CityGMLWriterUtils {
public static void writeCityModel(String file, CityDoctorModel model) throws CityDoctorWriteException { public static void writeCityModel(String file, CityDoctorModel model) throws CityDoctorWriteException {
CityGMLContext gmlContext = CityGmlParser.getContext(); CityGMLContext gmlContext = CityGmlParser.getContext();
CityModel cModel = model.getCityModel(); CityModel cModel = model.getCityModel();
CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(CityGMLVersion.v2_0); CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(model.getCityGMLVersion());
try (CityGMLWriter writer = factory.createCityGMLWriter(new File(file))) { try (CityGMLWriter writer = factory.createCityGMLWriter(new File(file))) {
writer.withIndent(" "); writer.withIndent(" ");
writer.withDefaultPrefixes(); writer.withDefaultPrefixes();
...@@ -92,6 +92,9 @@ public class CityGMLWriterUtils { ...@@ -92,6 +92,9 @@ public class CityGMLWriterUtils {
storeCityObjects(model.getLand(), gmlFactory, model, cModel, val); storeCityObjects(model.getLand(), gmlFactory, model, cModel, val);
storeCityObjects(model.getTransportation(), gmlFactory, model, cModel, val); storeCityObjects(model.getTransportation(), gmlFactory, model, cModel, val);
storeCityObjects(model.getWater(), gmlFactory, model, cModel, val); storeCityObjects(model.getWater(), gmlFactory, model, cModel, val);
storeCityObjects(model.getCityFurniture(), gmlFactory, model, cModel, val);
storeCityObjects(model.getGenericCityObjects(), gmlFactory, model, cModel, val);
storeCityObjects(model.getTunnels(), gmlFactory, model, cModel, val);
writer.write(cModel); writer.write(cModel);
cModel.getCityObjectMembers().clear(); cModel.getCityObjectMembers().clear();
...@@ -169,6 +172,7 @@ public class CityGMLWriterUtils { ...@@ -169,6 +172,7 @@ public class CityGMLWriterUtils {
if (model.isValidated() && val != null) { if (model.isValidated() && val != null) {
QualityADEUtils.writeQualityAde(co, val); QualityADEUtils.writeQualityAde(co, val);
} }
co.reCreateGeometries(gmlFactory, model.getParserConfig()); co.reCreateGeometries(gmlFactory, model.getParserConfig());
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject())); cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject()));
} }
......
...@@ -29,6 +29,9 @@ MainToolBar.wireframe=Show/Hide Wireframe ...@@ -29,6 +29,9 @@ MainToolBar.wireframe=Show/Hide Wireframe
MainToolBar.culling=Enable/Disable Culling MainToolBar.culling=Enable/Disable Culling
MainToolBar.writeReports=Write Reports MainToolBar.writeReports=Write Reports
MainToolBar.executeChecks=Execute Checks MainToolBar.executeChecks=Execute Checks
MainToolBar.showWorld=Show entire city model
MainToolBar.resetCamera=Reset view
MainToolBar.hideRoof=Show/Hide roof BoundarySurfaces
MainWindow.missingConfig=Could not find configuration file. MainWindow.missingConfig=Could not find configuration file.
MainWindow.loadGivenFile=Loading given file, please wait MainWindow.loadGivenFile=Loading given file, please wait
MainWindow.finishedLoading=Finished loading MainWindow.finishedLoading=Finished loading
...@@ -46,9 +49,12 @@ MainWindow.languageChange=For the change in language to apply, restart CityDocto ...@@ -46,9 +49,12 @@ MainWindow.languageChange=For the change in language to apply, restart CityDocto
MainWindow.buildingsTab=Buildings MainWindow.buildingsTab=Buildings
MainWindow.vegetationTab=Vegetation MainWindow.vegetationTab=Vegetation
MainWindow.transportationTab=Transportation MainWindow.transportationTab=Transportation
MainWindow.tunnelTab=Tunnels
MainWindow.bridgeTab=Bridges MainWindow.bridgeTab=Bridges
MainWindow.waterTab=Water MainWindow.waterTab=Water
MainWindow.terrainTab=Terrain MainWindow.terrainTab=Terrain
MainWindow.cityfurnitureTab=CityFurniture
MainWindow.otherObjectsTab=Other
MainWindow.viewLabel=View MainWindow.viewLabel=View
MainWindow.showLabel=Show: MainWindow.showLabel=Show:
MainWindow.searchLabel=Search: MainWindow.searchLabel=Search:
...@@ -58,6 +64,7 @@ MainWindow.errorsTab=Errors ...@@ -58,6 +64,7 @@ MainWindow.errorsTab=Errors
MainWindow.polygonsTab=Polygons MainWindow.polygonsTab=Polygons
MainWindow.edgesTab=Edges MainWindow.edgesTab=Edges
MainWindow.verticesTab=Vertices MainWindow.verticesTab=Vertices
MainWindow.attributeTab=Attributes
MainWindow.logTab=Log MainWindow.logTab=Log
MainWindow.globalErrorsTab=Global Errors MainWindow.globalErrorsTab=Global Errors
OpenFileDialog.fileLabel=File: OpenFileDialog.fileLabel=File:
......
...@@ -27,6 +27,9 @@ MainToolBar.wireframe=Zeige/Verstecke Gitternetz ...@@ -27,6 +27,9 @@ MainToolBar.wireframe=Zeige/Verstecke Gitternetz
MainToolBar.culling=Aktiviere/Deaktiviere Entfernen der R\u00fcckseiten MainToolBar.culling=Aktiviere/Deaktiviere Entfernen der R\u00fcckseiten
MainToolBar.writeReports=Schreibe Reports MainToolBar.writeReports=Schreibe Reports
MainToolBar.executeChecks=F\u00fchre Pr\u00fcfungen aus MainToolBar.executeChecks=F\u00fchre Pr\u00fcfungen aus
MainToolBar.showWorld=Gesamtes Stadtmodell anzeigen
MainToolBar.resetCamera=Ansicht zur\u00fccksetzen
MainToolBar.hideRoof=Zeige/Verstecke Dach BoundarySurfaces
MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden. MainWindow.missingConfig=Konnte Konfigurationsdatei nicht finden.
MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten MainWindow.loadGivenFile=Lade vorhandene Datei, bitte warten
MainWindow.finishedLoading=Fertig geladen MainWindow.finishedLoading=Fertig geladen
...@@ -44,9 +47,12 @@ MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityD ...@@ -44,9 +47,12 @@ MainWindow.languageChange=Um die Spracheinstellung zu \u00fcbernehmen muss CityD
MainWindow.buildingsTab=Geb\u00e4ude MainWindow.buildingsTab=Geb\u00e4ude
MainWindow.vegetationTab=Vegetation MainWindow.vegetationTab=Vegetation
MainWindow.transportationTab=Verkehrsobjekte MainWindow.transportationTab=Verkehrsobjekte
MainWindow.tunnelTab=Tunnel
MainWindow.bridgeTab=Br\u00fccken MainWindow.bridgeTab=Br\u00fccken
MainWindow.waterTab=Gew\u00e4sser MainWindow.waterTab=Gew\u00e4sser
MainWindow.terrainTab=Gel\u00e4nde MainWindow.terrainTab=Gel\u00e4nde
MainWindow.cityfurnitureTab=Stadtm\u00f6bel
MainWindow.otherObjectsTab=Andere
MainWindow.viewLabel=Ansicht MainWindow.viewLabel=Ansicht
MainWindow.showLabel=Zeige: MainWindow.showLabel=Zeige:
MainWindow.searchLabel=Suche: MainWindow.searchLabel=Suche:
...@@ -56,6 +62,7 @@ MainWindow.errorsTab=Fehler ...@@ -56,6 +62,7 @@ MainWindow.errorsTab=Fehler
MainWindow.polygonsTab=Polygone MainWindow.polygonsTab=Polygone
MainWindow.edgesTab=Kanten MainWindow.edgesTab=Kanten
MainWindow.verticesTab=Punkte MainWindow.verticesTab=Punkte
MainWindow.attributeTab=Attribute
MainWindow.logTab=Log MainWindow.logTab=Log
MainWindow.globalErrorsTab=Globale Fehler MainWindow.globalErrorsTab=Globale Fehler
OpenFileDialog.fileLabel=Datei: OpenFileDialog.fileLabel=Datei:
......
...@@ -28,6 +28,7 @@ import java.util.List; ...@@ -28,6 +28,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.citygml4j.core.ade.ADEException; import org.citygml4j.core.ade.ADEException;
import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractFeatureProperty; import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel; import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.xml.writer.CityGMLWriteException; import org.citygml4j.xml.writer.CityGMLWriteException;
...@@ -131,6 +132,7 @@ public class CityDoctorModelTest { ...@@ -131,6 +132,7 @@ public class CityDoctorModelTest {
File f = Mockito.mock(File.class); File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false); ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f); CityDoctorModel model = new CityDoctorModel(config, f);
model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel(); CityModel cModel = new CityModel();
model.setCityModel(cModel); model.setCityModel(cModel);
Building b = new Building(); Building b = new Building();
...@@ -156,6 +158,7 @@ public class CityDoctorModelTest { ...@@ -156,6 +158,7 @@ public class CityDoctorModelTest {
File f = Mockito.mock(File.class); File f = Mockito.mock(File.class);
ParserConfiguration config = new ParserConfiguration(8, false); ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, f); CityDoctorModel model = new CityDoctorModel(config, f);
model.setParsedCityGMLVersion(CityGMLVersion.v2_0);
CityModel cModel = new CityModel(); CityModel cModel = new CityModel();
ValidationPlan plan = new ValidationPlan(); ValidationPlan plan = new ValidationPlan();
plan.setId("CD_PLAN_" + UUID.randomUUID().toString()); plan.setId("CD_PLAN_" + UUID.randomUUID().toString());
......
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.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
public class CompositePolygonTest {
@Test
public void testCompositePolygonParsing() throws CityGmlParseException, InvalidGmlFileException {
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/FZK_haus.gml", config);
Building b = m.getBuildings().get(0);
assertNotNull(b);
assertFalse(b.getBoundarySurfaces().isEmpty());
for (BoundarySurface bs : b.getBoundarySurfaces()) {
assertNotNull(bs);
assertFalse(bs.getGeometries().isEmpty());
for (Geometry geom : bs.getGeometries()) {
assertNotNull(geom);
assertFalse(geom.getPolygons().isEmpty());
}
}
}
}
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.AbstractCheck;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import org.citygml4j.core.model.core.ImplicitGeometry;
import org.citygml4j.core.model.core.TransformationMatrix4x4;
import org.junit.Before;
import org.junit.Test;
import org.xmlobjects.gml.model.geometry.DirectPosition;
import org.xmlobjects.gml.model.geometry.primitives.Point;
import org.xmlobjects.gml.model.geometry.primitives.PointProperty;
import org.xmlobjects.gml.util.jama.Matrix;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.*;
public class ImplicitGeometryTest {
private Path path;
private ParserConfiguration config;
private String pathString = "src/test/resources/ImplicitTestGeom.gml";
private TransformationMatrix4x4 origin;
@Before
public void setUp() {
path = Paths.get(pathString);
config = new ParserConfiguration(8, false);
Matrix og = new Matrix(4, 4);
og.set(0, 0, 1);
og.set(1, 1, 1);
og.set(2, 2, 1);
origin = new TransformationMatrix4x4(og);
}
@Test
public void testLibraryObjectParsing() {
LibraryObject lo = LibraryObject.of(path, config);
assertNotNull(lo);
LibraryObject lo2 = LibraryObject.of(path, config);
assertSame(lo, lo2);
}
@Test
public void testObjectTransform() {
LibraryObject lo = LibraryObject.of(path, config);
assertNotNull(lo);
ImplicitGeometry geom = new ImplicitGeometry();
geom.setTransformationMatrix(origin);
geom.setReferencePoint(new PointProperty(new Point(new DirectPosition(0, 0))));
ImplicitGeometryHolder igh = new ImplicitGeometryHolder(geom, lo);
assertNotNull(igh);
geom.setReferencePoint(new PointProperty(new Point(new DirectPosition(5, 8))));
ImplicitGeometryHolder igh2 = new ImplicitGeometryHolder(geom, lo);
assertNotNull(igh2);
assertNotEquals(igh, igh2);
BoundingBox bb1 = BoundingBox.of(igh.getPolygons());
BoundingBox bb2 = BoundingBox.of(igh2.getPolygons());
assertNotEquals(bb1, bb2);
}
@Test
public void testAccept() {
LibraryObject lib = LibraryObject.of(path, config);
assertNotNull(lib);
ImplicitGeometry geom = new ImplicitGeometry();
geom.setTransformationMatrix(origin);
geom.setReferencePoint(new PointProperty(new Point(new DirectPosition(0, 0))));
int polyCount = lib.getPolygons().size();
ImplicitGeometryHolder igh = new ImplicitGeometryHolder(geom, lib);
AtomicInteger loCounter = new AtomicInteger(0);
AbstractCheck c = new AbstractCheck() {
@Override
public void check(Polygon lo) {
loCounter.incrementAndGet();
}
};
igh.accept(c);
assertEquals("ImplicitGeometryHolder should only check polygons of prototype geometry",
polyCount, loCounter.intValue());
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="utf-8"?>
<core:CityModel xmlns:core='http://www.opengis.net/citygml/2.0' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:gml='http://www.opengis.net/gml' xmlns:xAL='urn:oasis:names:tc:ciq:xsdschema:xAL:2.0' xmlns:app='http://www.opengis.net/citygml/appearance/2.0' xmlns:brid='http://www.opengis.net/citygml/bridge/2.0' xmlns:bldg='http://www.opengis.net/citygml/building/2.0' xmlns:frn='http://www.opengis.net/citygml/cityfurniture/2.0' xmlns:grp='http://www.opengis.net/citygml/cityobjectgroup/2.0' xmlns:gen='http://www.opengis.net/citygml/generics/2.0' xmlns:luse='http://www.opengis.net/citygml/landuse/2.0' xmlns:dem='http://www.opengis.net/citygml/relief/2.0' xmlns:tex='http://www.opengis.net/citygml/texturedsurface/2.0' xmlns:tran='http://www.opengis.net/citygml/transportation/2.0' xmlns:tun='http://www.opengis.net/citygml/tunnel/2.0' xmlns:veg='http://www.opengis.net/citygml/vegetation/2.0' xmlns:wtr='http://www.opengis.net/citygml/waterbody/2.0' xmlns:smil20='http://www.w3.org/2001/SMIL20/' xmlns:smil='http://www.w3.org/2001/SMIL20/Language' xmlns:xml='http://www.w3.org/XML/1998/namespace' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://www.opengis.net/citygml/profiles/base/2.0 http://schemas.opengis.net/citygml/profiles/base/2.0/CityGML.xsd' gml:id='0'>
<core:cityObjectMember>
<frn:CityFurniture gml:id='ImplicitGeometryLod2'>
<gml:name>TestGeometry</gml:name>
<frn:lod2ImplicitRepresentation>
<core:ImplicitGeometry gml:id='ImplicitGeometry'>
<core:transformationMatrix>
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
</core:transformationMatrix>
<core:relativeGMLGeometry>
<gml:CompositeSurface gml:id='1' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:surfaceMember>
<gml:Polygon gml:id='2' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='3' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 -2.193 58.441 4.034 -2.193 58.158 4.034 -1.750 58.441 4.034 -2.193 58.441</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='4' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='5' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 -0.039 100.000 4.034 1.864 58.441 4.034 -1.750 58.441 4.034 -0.039 59.536 4.034 -0.039 100.000</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='6' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='7' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 6.111 -37.093 35.821 6.110 -0.039 59.536 4.034 -0.039 59.536 4.034 -1.750 58.441 4.034 -2.193 58.158 4.035 -37.093 35.821 6.111 -37.093 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='8' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='9' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 6.110 -0.039 100.000 6.110 1.973 56.052 4.034 1.973 56.052 4.034 1.864 58.441 4.034 -0.039 100.000 6.110 -0.039 100.000</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='10' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='11' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.035 -37.093 35.821 4.034 -2.164 55.986 4.034 -2.050 56.052 6.110 -2.050 56.052 6.111 -37.093 35.821 4.035 -37.093 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='12' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='13' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 6.111 -37.093 35.821 6.110 -2.050 56.052 6.110 37.015 35.821 6.110 1.973 56.052 6.110 -0.039 100.000 6.110 -0.039 59.536 6.111 -37.093 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='14' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='15' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.035 -37.093 35.821 4.034 -2.193 58.158 4.034 -2.193 55.986 4.034 -2.164 55.986 4.035 -37.093 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='16' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='17' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 37.015 35.821 4.034 -1.923 55.986 4.034 2.087 55.986 4.034 37.015 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='18' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='19' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 1.696 -0.979 55.986 -0.000 -1.958 55.986 -0.000 -1.958 0.000 1.696 -0.979 0.000 1.696 -0.979 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='20' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='21' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 -2.164 55.986 4.034 -1.923 55.986 4.034 -2.050 56.052 4.034 -2.164 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='22' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='23' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 6.110 37.015 35.821 6.110 -2.050 56.052 4.034 -2.050 56.052 4.034 -1.923 55.986 4.034 37.015 35.821 6.110 37.015 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='24' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='25' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 37.015 35.821 4.034 2.087 55.986 4.034 1.973 56.052 6.110 1.973 56.052 6.110 37.015 35.821 4.034 37.015 35.821</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='26' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='27' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -0.000 1.958 0.000 1.696 0.979 0.000 1.696 -0.979 0.000 -0.000 -1.958 0.000 -1.696 -0.979 0.000 -1.696 0.979 0.000 -0.000 1.958 0.000</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='28' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='29' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -1.696 0.979 55.986 -0.000 1.958 55.986 -0.000 1.958 0.000 -1.696 0.979 0.000 -1.696 0.979 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='30' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='31' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -3.336 -2.193 58.441 4.034 -2.193 58.441 4.034 -1.750 58.441 4.034 1.864 58.441 4.034 2.116 58.441 -3.336 2.116 58.441 -3.336 -2.193 58.441</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='32' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='33' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -3.336 -2.193 55.986 4.034 -2.193 55.986 4.034 -2.193 58.158 4.034 -2.193 58.441 -3.336 -2.193 58.441 -3.336 -2.193 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='34' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='35' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 -0.039 100.000 4.034 -0.039 59.536 6.110 -0.039 59.536 6.110 -0.039 100.000 4.034 -0.039 100.000</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='36' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='37' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -0.000 1.958 55.986 1.696 0.979 55.986 1.696 0.979 0.000 -0.000 1.958 0.000 -0.000 1.958 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='38' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='39' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 4.034 2.116 58.441 4.034 1.864 58.441 4.034 1.973 56.052 4.034 2.087 55.986 4.034 2.116 55.986 4.034 2.116 58.441</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='40' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='41' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> 1.696 0.979 55.986 1.696 -0.979 55.986 1.696 -0.979 0.000 1.696 0.979 0.000 1.696 0.979 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='42' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='43' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -0.000 -1.958 55.986 -1.696 -0.979 55.986 -1.696 -0.979 0.000 -0.000 -1.958 0.000 -0.000 -1.958 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='44' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='45' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -3.336 2.116 55.986 4.034 2.116 55.986 4.034 2.087 55.986 4.034 -1.923 55.986 4.034 -2.164 55.986 4.034 -2.193 55.986 -3.336 -2.193 55.986 -3.336 2.116 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
<gml:interior>
<gml:LinearRing gml:id='46' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -0.000 1.958 55.986 -1.696 0.979 55.986 -1.696 -0.979 55.986 -0.000 -1.958 55.986 1.696 -0.979 55.986 1.696 0.979 55.986 -0.000 1.958 55.986</gml:posList>
</gml:LinearRing>
</gml:interior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='47' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='48' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -1.696 -0.979 55.986 -1.696 0.979 55.986 -1.696 0.979 0.000 -1.696 -0.979 0.000 -1.696 -0.979 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='49' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='50' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -3.336 2.116 55.986 -3.336 -2.193 55.986 -3.336 -2.193 58.441 -3.336 2.116 58.441 -3.336 2.116 55.986</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id='51' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:exterior>
<gml:LinearRing gml:id='52' srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'>
<gml:posList srsName='urn:ogc:def:crs:EPSG::-1' srsDimension='3'> -3.336 2.116 58.441 4.034 2.116 58.441 4.034 2.116 55.986 -3.336 2.116 55.986 -3.336 2.116 58.441</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</core:relativeGMLGeometry>
<core:referencePoint>
<gml:Point><gml:pos srsDimension="3">0.0 0.0 0.0</gml:pos>
</gml:Point></core:referencePoint>
</core:ImplicitGeometry>
</frn:lod2ImplicitRepresentation>
</frn:CityFurniture>
</core:cityObjectMember>
</core:CityModel>
...@@ -22,6 +22,7 @@ import java.util.List; ...@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import de.hft.stuttgart.citydoctor2.datastructure.*;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -34,21 +35,6 @@ import de.hft.stuttgart.citydoctor2.check.Requirement; ...@@ -34,21 +35,6 @@ import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType; import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
...@@ -244,6 +230,24 @@ public class CheckContainer extends Check { ...@@ -244,6 +230,24 @@ public class CheckContainer extends Check {
} }
} }
@Override
public void check(CityFurniture cf){
try {
check.check(cf);
} catch (Exception e) {
handleException(e, cf);
}
}
@Override
public void check(GenericCityObject gco) {
try {
check.check(gco);
} catch (Exception e) {
handleException(e, gco);
}
}
@Override @Override
public RequirementType getType() { public RequirementType getType() {
return check.getType(); return check.getType();
......
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.CityModel;
import org.xml.sax.SAXParseException;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId; import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError; import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface; import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject;
import de.hft.stuttgart.citydoctor2.datastructure.TinObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat; import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBoundarySurfacesNode; import de.hft.stuttgart.citydoctor2.gui.tree.*;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgeConstructiveElementsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgePartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgesNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllInstallationsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingPartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllOpeningsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTerrainNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTransportationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllVegetationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllWaterNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BoundarySurfaceNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeConstructiveElementNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeNode;
import de.hft.stuttgart.citydoctor2.gui.tree.InstallationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingPartNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ButtonRenderable;
import de.hft.stuttgart.citydoctor2.gui.tree.CityObjectNode;
import de.hft.stuttgart.citydoctor2.gui.tree.GeometryNode;
import de.hft.stuttgart.citydoctor2.gui.tree.LandUseNode;
import de.hft.stuttgart.citydoctor2.gui.tree.OpeningNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ReliefNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.TinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.VegetationNode;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.*;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Data;
...@@ -84,1003 +21,1244 @@ import javafx.scene.control.TreeItem; ...@@ -84,1003 +21,1244 @@ import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView; import javafx.scene.control.TreeView;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.FileChooser.ExtensionFilter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.CityModel;
import org.xml.sax.SAXParseException;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
public class CityDoctorController { public class CityDoctorController {
private static final int MAX_FEATURES_PER_CHUNK = 200; private static final int MAX_FEATURES_PER_CHUNK = 200;
private static final Logger logger = LogManager.getLogger(CityDoctorController.class); private static final Logger logger = LogManager.getLogger(CityDoctorController.class);
private MainWindow mainWindow; private MainWindow mainWindow;
private CityDoctorModel model; private CityDoctorModel model;
private ParserConfiguration currentConfig; private ParserConfiguration currentConfig;
private String sourceFile; private String sourceFile;
private Checker currentChecker; private Checker currentChecker;
private HighlightController highlightController; private HighlightController highlightController;
private Renderer renderer; private Renderer renderer;
private BoundingBox originBB = null;
private AtomicInteger buildingChunkNr = new AtomicInteger(0);
private AtomicInteger vegetationChunkNr = new AtomicInteger(0); private AtomicInteger buildingChunkNr = new AtomicInteger(0);
private AtomicInteger transportationChunkNr = new AtomicInteger(0); private AtomicInteger vegetationChunkNr = new AtomicInteger(0);
private AtomicInteger bridgeChunkNr = new AtomicInteger(0); private AtomicInteger transportationChunkNr = new AtomicInteger(0);
private AtomicInteger waterChunkNr = new AtomicInteger(0); private AtomicInteger tunnelChunkNr = new AtomicInteger(0);
private AtomicInteger landChunkNr = new AtomicInteger(0); private AtomicInteger bridgeChunkNr = new AtomicInteger(0);
private AtomicInteger waterChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) { private AtomicInteger landChunkNr = new AtomicInteger(0);
this.mainWindow = mainWindow; private AtomicInteger cityFurnitureChunkNr = new AtomicInteger(0);
this.highlightController = highlightController; private AtomicInteger otherObjectsChunkNr = new AtomicInteger(0);
this.renderer = renderer;
} public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation) this.highlightController = highlightController;
throws CityGmlParseException, InvalidGmlFileException { this.renderer = renderer;
loadCityGml(path, numberOfRoundingPlaces, l, useValidation, false); }
}
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation)
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation, throws CityGmlParseException, InvalidGmlFileException {
boolean lowMemory) throws CityGmlParseException, InvalidGmlFileException { loadCityGml(path, numberOfRoundingPlaces, l, useValidation, false);
try { }
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true); public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation,
mainWindow.getWriteReportButton().setDisable(true); boolean lowMemory) throws CityGmlParseException, InvalidGmlFileException {
mainWindow.getMeshGroup().getChildren().clear(); try {
Platform.runLater(() -> {
clearTrees(); mainWindow.getOpenBtn().setDisable(true);
mainWindow.resetSearchBar(); mainWindow.getWriteReportButton().setDisable(true);
mainWindow.resetFilterComboBox(); mainWindow.getMeshGroup().getChildren().clear();
});
currentChecker = null; clearTrees();
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory); mainWindow.resetSearchBar();
GMLValidationHandler handler = null; mainWindow.resetFilterComboBox();
List<String> validationIssues = new ArrayList<>(); });
if (useValidation) { currentChecker = null;
handler = new GMLValidationHandler() { currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
@Override GMLValidationHandler handler = null;
public void error(SAXParseException exception) { List<String> validationIssues = new ArrayList<>();
if (exception.getLineNumber() >= 0) { if (useValidation) {
String s = "In line " + exception.getLineNumber() + ":"; handler = new GMLValidationHandler() {
validationIssues.add(s); @Override
} public void error(SAXParseException exception) {
validationIssues.add(exception.getMessage()); if (exception.getLineNumber() >= 0) {
} String s = "In line " + exception.getLineNumber() + ":";
validationIssues.add(s);
@Override }
public void warning(SAXParseException exception) { validationIssues.add(exception.getMessage());
error(exception); }
}
@Override
@Override public void warning(SAXParseException exception) {
public void fatalError(SAXParseException exception) { error(exception);
error(exception); }
}
}; @Override
} public void fatalError(SAXParseException exception) {
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler); error(exception);
if (!validationIssues.isEmpty()) { }
StringJoiner sj = new StringJoiner("\n"); };
validationIssues.stream().forEach(sj::add); }
throw new InvalidGmlFileException(sj.toString()); model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler);
} if (!validationIssues.isEmpty()) {
mainWindow.getClickHandler().setConfig(currentConfig); StringJoiner sj = new StringJoiner("\n");
sourceFile = path; validationIssues.stream().forEach(sj::add);
renderer.reset(); throw new InvalidGmlFileException(sj.toString());
Platform.runLater(() -> { }
mainWindow.addFileNameToTitle(path); mainWindow.getClickHandler().setConfig(currentConfig);
mainWindow.getCheckButton().setDisable(false); sourceFile = path;
mainWindow.getLod1Btn().setDisable(false); renderer.reset();
mainWindow.getLod2Btn().setDisable(false); Platform.runLater(() -> {
mainWindow.getLod3Btn().setDisable(false); mainWindow.addFileNameToTitle(path);
mainWindow.getLod4Btn().setDisable(false); mainWindow.getCheckButton().setDisable(false);
mainWindow.getWorldBtn().setDisable(false); mainWindow.getLod1Btn().setDisable(false);
mainWindow.getSaveBtn().setDisable(false); mainWindow.getLod2Btn().setDisable(false);
buildTrees(); mainWindow.getLod3Btn().setDisable(false);
}); mainWindow.getLod4Btn().setDisable(false);
} finally { mainWindow.getWorldBtn().setDisable(false);
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false)); mainWindow.getSaveBtn().setDisable(false);
} mainWindow.getResetCameraBtn().setDisable(false);
} mainWindow.getHideRoofBtn().setDisable(false);
mainWindow.getNorthArrow().setVisible(true);
public void buildTrees() { mainWindow.alignNorthArrow();
resetFeatureChunks(); setupFeatureTabs();
buildBuildings(model); buildTrees();
buildVegetation(model.getVegetation()); });
buildTransportation(model.getTransportation()); } finally {
buildBridges(model); Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
buildWater(model); }
buildLand(model); }
}
private void setupFeatureTabs() {
private void resetFeatureChunks() { mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildings().isEmpty());
buildingChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetation().isEmpty());
vegetationChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportation().isEmpty());
transportationChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnels().isEmpty());
bridgeChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridges().isEmpty());
waterChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWater().isEmpty());
landChunkNr.set(0); mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLand().isEmpty());
} mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurniture().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.GENERIC_CITY_OBJECT, model.getGenericCityObjects().isEmpty());
private void buildLand(CityDoctorModel model) { }
if (model.getLand().isEmpty()) {
return; public void buildTrees() {
} resetFeatureChunks();
TreeView<Renderable> landView = mainWindow.getTerrainView(); buildBuildings(model);
TreeItem<Renderable> landRoot = new TreeItem<>(new AllTerrainNode(model.getLand())); buildVegetation(model.getVegetation());
landRoot.setExpanded(true); buildTransportation(model.getTransportation());
landView.setRoot(landRoot); buildBridges(model);
buildLandFromList(model.getLand(), landView.getRoot()); buildWater(model);
addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr); buildLand(model);
} buildCityFurniture(model);
buildOtherCityObjects(model);
private void buildLandFromList(List<CityObject> list, TreeItem<Renderable> root) { }
int landChunk = landChunkNr.get();
for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK private void resetFeatureChunks() {
&& i < list.size(); i++) { buildingChunkNr.set(0);
CityObject land = list.get(i); vegetationChunkNr.set(0);
Renderable node; transportationChunkNr.set(0);
if (land instanceof ReliefObject relief) { tunnelChunkNr.set(0);
node = new ReliefNode(relief); bridgeChunkNr.set(0);
} else if (land instanceof TinObject tin) { waterChunkNr.set(0);
node = new TinNode(tin); landChunkNr.set(0);
} else { cityFurnitureChunkNr.set(0);
node = new LandUseNode((LandObject) land); otherObjectsChunkNr.set(0);
} }
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true); private void buildLand(CityDoctorModel model) {
root.getChildren().add(item); if (model.getLand().isEmpty()) {
createGeometryNodes(land, item); return;
if (land instanceof ReliefObject relief) { }
createTinNodes(relief, item); TreeView<Renderable> landView = mainWindow.getTerrainView();
} TreeItem<Renderable> landRoot = new TreeItem<>(new AllTerrainNode(model.getLand()));
} landRoot.setExpanded(true);
} landView.setRoot(landRoot);
buildLandFromList(model.getLand(), landView.getRoot());
private void createTinNodes(ReliefObject relief, TreeItem<Renderable> item) { addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr);
if (relief.getComponents().isEmpty()) { }
return;
} private void buildLandFromList(List<CityObject> list, TreeItem<Renderable> root) {
AllTinNode allTinText = new AllTinNode(relief.getComponents()); int landChunk = landChunkNr.get();
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allTinText); for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK
item.getChildren().add(allBpsTextItem); && i < list.size(); i++) {
CityObject land = list.get(i);
for (TinObject tin : relief.getComponents()) { Renderable node;
TinNode tinNode = new TinNode(tin); if (land instanceof ReliefObject relief) {
TreeItem<Renderable> tinNodeItem = new TreeItem<>(tinNode); node = new ReliefNode(relief);
tinNodeItem.setExpanded(true); } else if (land instanceof TinObject tin) {
allBpsTextItem.getChildren().add(tinNodeItem); node = new TinNode(tin);
createGeometryNodes(tin, tinNodeItem); } else {
} node = new LandUseNode((LandObject) land);
} }
TreeItem<Renderable> item = new TreeItem<>(node);
private void buildWater(CityDoctorModel model) { item.setExpanded(true);
if (model.getWater().isEmpty()) { root.getChildren().add(item);
return; createGeometryNodes(land, item);
} if (land instanceof ReliefObject relief) {
TreeView<Renderable> waterView = mainWindow.getWaterView(); createTinNodes(relief, item);
TreeItem<Renderable> waterRoot = new TreeItem<>(new AllWaterNode(model.getWater())); }
waterRoot.setExpanded(true); }
waterView.setRoot(waterRoot); }
buildTreeFromList(model.getWater(), waterView.getRoot(), waterChunkNr);
addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr); private void createTinNodes(ReliefObject relief, TreeItem<Renderable> item) {
} if (relief.getComponents().isEmpty()) {
return;
private void buildBridges(CityDoctorModel model) { }
if (model.getBridges().isEmpty()) { AllTinNode allTinText = new AllTinNode(relief.getComponents());
return; TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allTinText);
} item.getChildren().add(allBpsTextItem);
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new AllBridgesNode(model.getBridges())); for (TinObject tin : relief.getComponents()) {
bridgeRoot.setExpanded(true); TinNode tinNode = new TinNode(tin);
bridgeView.setRoot(bridgeRoot); TreeItem<Renderable> tinNodeItem = new TreeItem<>(tinNode);
buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot()); tinNodeItem.setExpanded(true);
addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr); allBpsTextItem.getChildren().add(tinNodeItem);
} createGeometryNodes(tin, tinNodeItem);
}
private void buildTransportation(List<TransportationObject> trans) { }
if (trans.isEmpty()) {
return; private void buildCityFurniture(CityDoctorModel model) {
} if (model.getCityFurniture().isEmpty()) {
TreeView<Renderable> transView = mainWindow.getTransportationView(); return;
TreeItem<Renderable> transRoot = new TreeItem<>(new AllTransportationNode(model.getTransportation())); }
transRoot.setExpanded(true); TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
transView.setRoot(transRoot); TreeItem<Renderable> cityFurnitureRoot = new TreeItem<>(new AllCityFurnitureNode(model.getCityFurniture()));
buildTreeFromList(trans, transView.getRoot(), transportationChunkNr); cityFurnitureRoot.setExpanded(true);
addMoreButtonIfNecessary(trans, transView, transRoot, transportationChunkNr); cityFurnitureView.setRoot(cityFurnitureRoot);
} buildTreeFromList(model.getCityFurniture(), cityFurnitureView.getRoot(), cityFurnitureChunkNr);
addMoreButtonIfNecessary(model.getCityFurniture(), cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr);
private void buildVegetation(List<Vegetation> veg) { }
if (veg.isEmpty()) {
return; private void buildOtherCityObjects(CityDoctorModel model) {
} if (model.getGenericCityObjects().isEmpty()) {
TreeView<Renderable> vegetationsView = mainWindow.getVegetationView(); return;
TreeItem<Renderable> vegRoot = new TreeItem<>(new AllVegetationNode(model.getVegetation())); }
vegRoot.setExpanded(true); TreeView<Renderable> otherObjectsView = mainWindow.getOtherObjectsView();
vegetationsView.setRoot(vegRoot); TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new AllOtherObjectsNode(model.getGenericCityObjects()));
buildTreeFromListWithProducer(veg, vegetationsView.getRoot(), vegetationChunkNr, VegetationNode::new); otherObjectsRoot.setExpanded(true);
addMoreButtonIfNecessary(veg, vegetationsView, vegRoot, vegetationChunkNr); otherObjectsView.setRoot(otherObjectsRoot);
} buildTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot(), otherObjectsChunkNr);
addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, otherObjectsChunkNr);
private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view, }
TreeItem<Renderable> root, AtomicInteger chunkCounter) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) { private void buildWater(CityDoctorModel model) {
Runnable run = new Runnable() { if (model.getWater().isEmpty()) {
public void run() { return;
// 29 is the height of one item }
int numberOfDisplayedItems = (int) (view.getHeight() / 29); TreeView<Renderable> waterView = mainWindow.getWaterView();
int selectedIndex = view.getSelectionModel().getSelectedIndex(); TreeItem<Renderable> waterRoot = new TreeItem<>(new AllWaterNode(model.getWater()));
// remove button node waterRoot.setExpanded(true);
root.getChildren().remove(root.getChildren().size() - 1); waterView.setRoot(waterRoot);
chunkCounter.incrementAndGet(); buildTreeFromList(model.getWater(), waterView.getRoot(), waterChunkNr);
int visibleFeatures = countVisibleNodes(view); addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr);
buildTreeFromList(list, root, chunkCounter); }
updateTree(root);
if (selectedIndex >= 0) { private void buildBridges(CityDoctorModel model) {
view.getSelectionModel().select(selectedIndex); if (model.getBridges().isEmpty()) {
} return;
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) { }
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this))); TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
} TreeItem<Renderable> bridgeRoot = new TreeItem<>(new AllBridgesNode(model.getBridges()));
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1); bridgeRoot.setExpanded(true);
} bridgeView.setRoot(bridgeRoot);
}; buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot());
// add button for expansion addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr);
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); }
}
} private void buildTransportation(List<TransportationObject> trans) {
if (trans.isEmpty()) {
private void buildBuildings(CityDoctorModel model) { return;
if (model.getBuildings().isEmpty()) { }
return; TreeView<Renderable> transView = mainWindow.getTransportationView();
} TreeItem<Renderable> transRoot = new TreeItem<>(new AllTransportationNode(model.getTransportation()));
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView(); transRoot.setExpanded(true);
TreeItem<Renderable> root = new TreeItem<>(new AllBuildingsNode(model.getBuildings())); transView.setRoot(transRoot);
root.setExpanded(true); buildTreeFromList(trans, transView.getRoot(), transportationChunkNr);
buildBuildingTreeFromList(model.getBuildings(), root); addMoreButtonIfNecessary(trans, transView, transRoot, transportationChunkNr);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr); }
buildingsView.setRoot(root);
} private void buildTunnel(List<Tunnel> tunnels) {
if (tunnels.isEmpty()) {
private void addMoreButtonToBuildingsIfNecessary(List<Building> list, TreeView<Renderable> view, return;
TreeItem<Renderable> root, AtomicInteger chunkCounter) { }
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) { TreeView<Renderable> transView = mainWindow.getTunnelView();
Runnable run = new Runnable() { TreeItem<Renderable> transRoot = new TreeItem<>(new AllTunnelsNode(model.getTunnels()));
public void run() { transRoot.setExpanded(true);
// 29 is the height of one item transView.setRoot(transRoot);
int numberOfDisplayedItems = (int) (view.getHeight() / 29); buildTreeFromList(tunnels, transView.getRoot(), tunnelChunkNr);
int selectedIndex = view.getSelectionModel().getSelectedIndex(); addMoreButtonIfNecessary(tunnels, transView, transRoot, tunnelChunkNr);
// remove button node }
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement(); private void buildVegetation(List<Vegetation> veg) {
int visibleFeatures = countVisibleNodes(view); if (veg.isEmpty()) {
buildBuildingTreeFromList(list, root); return;
updateTree(root); }
if (selectedIndex >= 0) { TreeView<Renderable> vegetationsView = mainWindow.getVegetationView();
view.getSelectionModel().select(selectedIndex); TreeItem<Renderable> vegRoot = new TreeItem<>(new AllVegetationNode(model.getVegetation()));
} vegRoot.setExpanded(true);
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) { vegetationsView.setRoot(vegRoot);
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this))); buildTreeFromListWithProducer(veg, vegetationsView.getRoot(), vegetationChunkNr, VegetationNode::new);
} addMoreButtonIfNecessary(veg, vegetationsView, vegRoot, vegetationChunkNr);
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1); }
}
}; private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view,
// add button for expansion TreeItem<Renderable> root, AtomicInteger chunkCounter) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run))); if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
} Runnable run = new Runnable() {
} public void run() {
// 29 is the height of one item
private static int countVisibleNodes(TreeView<Renderable> view) { int numberOfDisplayedItems = (int) (view.getHeight() / 29);
return countVisibleNodes(view.getRoot()) + 1; int selectedIndex = view.getSelectionModel().getSelectedIndex();
} // remove button node
root.getChildren().remove(root.getChildren().size() - 1);
private static int countVisibleNodes(TreeItem<Renderable> root) { chunkCounter.incrementAndGet();
int visibleFeatures = root.getChildren().size(); int visibleFeatures = countVisibleNodes(view);
for (TreeItem<Renderable> child : root.getChildren()) { buildTreeFromList(list, root, chunkCounter);
if (!child.getChildren().isEmpty() && child.isExpanded()) { updateTree(root);
visibleFeatures += countVisibleNodes(child); if (selectedIndex >= 0) {
} view.getSelectionModel().select(selectedIndex);
} }
return visibleFeatures; if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
} root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
private void buildTreeFromList(List<? extends CityObject> cos, TreeItem<Renderable> root, view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
AtomicInteger chunkCounter) { }
int chunk = chunkCounter.get(); };
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) { // add button for expansion
CityObject co = cos.get(i); root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
CityObjectNode node = new CityObjectNode(co); }
TreeItem<Renderable> nodeItem = new TreeItem<>(node); }
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem); private void buildBuildings(CityDoctorModel model) {
createGeometryNodes(co, nodeItem); if (model.getBuildings().isEmpty()) {
} return;
} }
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
private <T extends CityObject> void buildTreeFromListWithProducer(List<T> cos, TreeItem<Renderable> root, TreeItem<Renderable> root = new TreeItem<>(new AllBuildingsNode(model.getBuildings()));
AtomicInteger chunkCounter, Function<T, Renderable> nodeProducer) { root.setExpanded(true);
int chunk = chunkCounter.get(); buildBuildingTreeFromList(model.getBuildings(), root);
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) { addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr);
T co = cos.get(i); buildingsView.setRoot(root);
Renderable node = nodeProducer.apply(co); }
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true); private void addMoreButtonToBuildingsIfNecessary(List<Building> list, TreeView<Renderable> view,
root.getChildren().add(nodeItem); TreeItem<Renderable> root, AtomicInteger chunkCounter) {
createGeometryNodes(co, nodeItem); if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
} Runnable run = new Runnable() {
} public void run() {
// 29 is the height of one item
private void clearTrees() { int numberOfDisplayedItems = (int) (view.getHeight() / 29);
mainWindow.getBuildingsView().setRoot(null); int selectedIndex = view.getSelectionModel().getSelectedIndex();
mainWindow.getVegetationView().setRoot(null); // remove button node
mainWindow.getTransportationView().setRoot(null); root.getChildren().remove(root.getChildren().size() - 1);
mainWindow.getBridgeView().setRoot(null); chunkCounter.getAndIncrement();
mainWindow.getWaterView().setRoot(null); int visibleFeatures = countVisibleNodes(view);
mainWindow.getTerrainView().setRoot(null); buildBuildingTreeFromList(list, root);
mainWindow.getErrorTree().getRoot().getChildren().clear(); updateTree(root);
mainWindow.getGlobalErrorsView().getItems().clear(); if (selectedIndex >= 0) {
clearGeometryTrees(); view.getSelectionModel().select(selectedIndex);
} }
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
private void clearGeometryTrees() { root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
highlightController.clearHighlights(); }
mainWindow.getPolygonsView().getRoot().getChildren().clear(); view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
mainWindow.getEdgeView().getRoot().getChildren().clear(); }
mainWindow.getVertexView().getRoot().getChildren().clear(); };
} // add button for expansion
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
private void buildBuildingTreeFromList(List<Building> list, TreeItem<Renderable> root) { }
int buildingChunk = buildingChunkNr.get(); }
for (int i = buildingChunk * MAX_FEATURES_PER_CHUNK; i < (buildingChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) { private static int countVisibleNodes(TreeView<Renderable> view) {
Building b = list.get(i); return countVisibleNodes(view.getRoot()) + 1;
BuildingNode node = new BuildingNode(b); }
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true); private static int countVisibleNodes(TreeItem<Renderable> root) {
root.getChildren().add(item); int visibleFeatures = root.getChildren().size();
createGeometryNodes(b, item); for (TreeItem<Renderable> child : root.getChildren()) {
createBoundarySurfaceNodes(b.getBoundarySurfaces(), item); if (!child.getChildren().isEmpty() && child.isExpanded()) {
createBuildingInstallationNodes(b, item); visibleFeatures += countVisibleNodes(child);
createBuildingPartNodes(b, item); }
} }
} return visibleFeatures;
}
private void buildBridgeTreeFromList(List<BridgeObject> list, TreeItem<Renderable> root) {
int bridgeChunk = bridgeChunkNr.get(); private void buildTreeFromList(List<? extends CityObject> cos, TreeItem<Renderable> root,
for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK AtomicInteger chunkCounter) {
&& i < list.size(); i++) { int chunk = chunkCounter.get();
BridgeObject bridge = list.get(i); for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
BridgeNode node = new BridgeNode(bridge); CityObject co = cos.get(i);
TreeItem<Renderable> item = new TreeItem<>(node); CityObjectNode node = new CityObjectNode(co);
item.setExpanded(true); TreeItem<Renderable> nodeItem = new TreeItem<>(node);
root.getChildren().add(item); nodeItem.setExpanded(true);
createGeometryNodes(bridge, item); root.getChildren().add(nodeItem);
createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item); createGeometryNodes(co, nodeItem);
createBridgeInstallationNodes(bridge, item); }
createConstructiveElementsNodes(bridge, item); }
createBridgePartNodes(bridge, item);
} private <T extends CityObject> void buildTreeFromListWithProducer(List<T> cos, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Function<T, Renderable> nodeProducer) {
} int chunk = chunkCounter.get();
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) { T co = cos.get(i);
createInstallationNodes(bridge.getBridgeInstallations(), root); Renderable node = nodeProducer.apply(co);
} TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) { root.getChildren().add(nodeItem);
if (bridge.getConstructiveElements().isEmpty()) { createGeometryNodes(co, nodeItem);
return; }
} }
AllBridgeConstructiveElementsNode allBceNode = new AllBridgeConstructiveElementsNode(
bridge.getConstructiveElements()); private void clearTrees() {
TreeItem<Renderable> allBceNodeTextItem = new TreeItem<>(allBceNode); mainWindow.getBuildingsView().setRoot(null);
item.getChildren().add(allBceNodeTextItem); mainWindow.getVegetationView().setRoot(null);
mainWindow.getTransportationView().setRoot(null);
for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) { mainWindow.getBridgeView().setRoot(null);
BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce); mainWindow.getWaterView().setRoot(null);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bceNode); mainWindow.getTerrainView().setRoot(null);
bpNodeItem.setExpanded(true); mainWindow.getCityFurnitureView().setRoot(null);
allBceNodeTextItem.getChildren().add(bpNodeItem); mainWindow.getOtherObjectsView().setRoot(null);
createGeometryNodes(bce, bpNodeItem); mainWindow.getErrorTree().getRoot().getChildren().clear();
createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bpNodeItem); mainWindow.getAttributeView().getRoot().getChildren().clear();
} mainWindow.getGlobalErrorsView().getItems().clear();
} clearGeometryTrees();
}
private void createBridgePartNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getParts().isEmpty()) { private void clearGeometryTrees() {
return; highlightController.clearHighlights();
} mainWindow.getPolygonsView().getRoot().getChildren().clear();
AllBridgePartsNode allBpsText = new AllBridgePartsNode(bridge.getParts()); mainWindow.getEdgeView().getRoot().getChildren().clear();
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText); mainWindow.getVertexView().getRoot().getChildren().clear();
item.getChildren().add(allBpsTextItem); }
for (BridgeObject bp : bridge.getParts()) { private void buildBuildingTreeFromList(List<Building> list, TreeItem<Renderable> root) {
BridgeNode bpNode = new BridgeNode(bp); int buildingChunk = buildingChunkNr.get();
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode); for (int i = buildingChunk * MAX_FEATURES_PER_CHUNK; i < (buildingChunk + 1) * MAX_FEATURES_PER_CHUNK
bpNodeItem.setExpanded(true); && i < list.size(); i++) {
allBpsTextItem.getChildren().add(bpNodeItem); Building b = list.get(i);
createGeometryNodes(bp, bpNodeItem); BuildingNode node = new BuildingNode(b);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem); TreeItem<Renderable> item = new TreeItem<>(node);
} item.setExpanded(true);
} root.getChildren().add(item);
createGeometryNodes(b, item);
private void createBuildingInstallationNodes(Building ab, TreeItem<Renderable> root) { createBoundarySurfaceNodes(b.getBoundarySurfaces(), item);
createInstallationNodes(ab.getBuildingInstallations(), root); createBuildingInstallationNodes(b, item);
} createBuildingRoomNodes(b, item);
createBuildingFurnitureNodes(b, item);
private void createInstallationNodes(List<Installation> installations, TreeItem<Renderable> root) { createBuildingStoreyNodes(b, item);
if (installations.isEmpty()) { createBuildingUnitNodes(b, item);
return; createBuildingPartNodes(b, item);
} }
}
AllInstallationsNode allBiNode = new AllInstallationsNode(installations);
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBiNode); private void buildBridgeTreeFromList(List<BridgeObject> list, TreeItem<Renderable> root) {
root.getChildren().add(allBpsTextItem); int bridgeChunk = bridgeChunkNr.get();
for (Installation bi : installations) { for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK
InstallationNode biNode = new InstallationNode(bi); && i < list.size(); i++) {
TreeItem<Renderable> biItem = new TreeItem<>(biNode); BridgeObject bridge = list.get(i);
biItem.setExpanded(true); BridgeNode node = new BridgeNode(bridge);
allBpsTextItem.getChildren().add(biItem); TreeItem<Renderable> item = new TreeItem<>(node);
createGeometryNodes(bi, biItem); item.setExpanded(true);
createBoundarySurfaceNodes(bi.getBoundarySurfaces(), biItem); root.getChildren().add(item);
} createGeometryNodes(bridge, item);
} createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item);
createBridgeInstallationNodes(bridge, item);
private void createBoundarySurfaceNodes(List<BoundarySurface> bsList, TreeItem<Renderable> root) { createConstructiveElementsNodes(bridge, item);
if (bsList.isEmpty()) { createBridgePartNodes(bridge, item);
return; }
}
AllBoundarySurfacesNode allBsText = new AllBoundarySurfacesNode(bsList); }
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBsText);
root.getChildren().add(allBpsTextItem); private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createInstallationNodes(bridge.getBridgeInstallations(), root);
allBpsTextItem.getChildren().add(new TreeItem<>()); }
allBpsTextItem.expandedProperty().addListener((obs, old, newV) -> { private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (Boolean.TRUE.equals(newV) && allBpsTextItem.getChildren().size() == 1) { if (bridge.getConstructiveElements().isEmpty()) {
Platform.runLater(() -> { return;
allBpsTextItem.getChildren().clear(); }
for (BoundarySurface bs : bsList) { AllBridgeConstructiveElementsNode allBceNode = new AllBridgeConstructiveElementsNode(
BoundarySurfaceNode bsText = new BoundarySurfaceNode(bs); bridge.getConstructiveElements());
TreeItem<Renderable> bsTextItem = new TreeItem<>(bsText); TreeItem<Renderable> allBceNodeTextItem = new TreeItem<>(allBceNode);
bsTextItem.setExpanded(true); item.getChildren().add(allBceNodeTextItem);
allBpsTextItem.getChildren().add(bsTextItem);
createGeometryNodes(bs, bsTextItem); for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) {
createOpeningNodes(bs.getOpenings(), bsTextItem); BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce);
} TreeItem<Renderable> bpNodeItem = new TreeItem<>(bceNode);
updateTree(allBpsTextItem); bpNodeItem.setExpanded(true);
}); allBceNodeTextItem.getChildren().add(bpNodeItem);
} createGeometryNodes(bce, bpNodeItem);
}); createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bpNodeItem);
} }
}
private void createOpeningNodes(List<Opening> openings, TreeItem<Renderable> root) {
if (openings == null || openings.isEmpty()) { private void createBridgePartNodes(BridgeObject bridge, TreeItem<Renderable> item) {
return; if (bridge.getParts().isEmpty()) {
} return;
AllOpeningsNode allOpeningsNode = new AllOpeningsNode(openings); }
TreeItem<Renderable> allOpeningsItem = new TreeItem<>(allOpeningsNode); AllBridgePartsNode allBpsText = new AllBridgePartsNode(bridge.getParts());
for (Opening o : openings) { TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
OpeningNode openingNode = new OpeningNode(o); item.getChildren().add(allBpsTextItem);
TreeItem<Renderable> openingsItem = new TreeItem<>(openingNode);
allOpeningsItem.getChildren().add(openingsItem); for (BridgeObject bp : bridge.getParts()) {
} BridgeNode bpNode = new BridgeNode(bp);
root.getChildren().add(allOpeningsItem); TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
} bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
private void createBuildingPartNodes(Building ab, TreeItem<Renderable> item) { createGeometryNodes(bp, bpNodeItem);
if (ab.getBuildingParts().isEmpty()) { createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
return; }
} }
AllBuildingPartsNode allBpsText = new AllBuildingPartsNode(ab.getBuildingParts());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText); private void createBuildingInstallationNodes(Building ab, TreeItem<Renderable> root) {
item.getChildren().add(allBpsTextItem); createInstallationNodes(ab.getBuildingInstallations(), root);
}
for (BuildingPart bp : ab.getBuildingParts()) {
BuildingPartNode bpNode = new BuildingPartNode(bp); private void createInstallationNodes(List<Installation> installations, TreeItem<Renderable> root) {
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode); if (installations.isEmpty()) {
bpNodeItem.setExpanded(true); return;
allBpsTextItem.getChildren().add(bpNodeItem); }
createGeometryNodes(bp, bpNodeItem);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem); AllInstallationsNode allBiNode = new AllInstallationsNode(installations);
} TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBiNode);
} root.getChildren().add(allBpsTextItem);
for (Installation bi : installations) {
private void createGeometryNodes(CityObject co, TreeItem<Renderable> item) { InstallationNode biNode = new InstallationNode(bi);
for (Geometry geom : co.getGeometries()) { TreeItem<Renderable> biItem = new TreeItem<>(biNode);
GeometryNode geomNode = new GeometryNode(geom); biItem.setExpanded(true);
TreeItem<Renderable> geomItem = new TreeItem<>(geomNode); allBpsTextItem.getChildren().add(biItem);
item.getChildren().add(geomItem); createGeometryNodes(bi, biItem);
} createBoundarySurfaceNodes(bi.getBoundarySurfaces(), biItem);
} }
}
public void startChecks(ValidationConfiguration config, ProgressListener l) {
if (model == null) { private void createBuildingRoomNodes(Building ab, TreeItem<Renderable> root) {
logger.warn(Localization.getText("CityDoctorController.noDatamodel")); createRoomNodes(ab.getBuildingRooms(), root);
return; }
}
if (sourceFile == null) { private void createRoomNodes(List<? extends AbstractRoom> rooms, TreeItem<Renderable> root) {
logger.warn(Localization.getText("CityDoctorController.noSourceFile")); if (rooms.isEmpty()) {
return; return;
} }
try {
Platform.runLater(() -> { AllRoomsNode allRoNode = new AllRoomsNode(rooms);
mainWindow.getCheckButton().setDisable(true); TreeItem<Renderable> allRoNodeTextItem = new TreeItem<>(allRoNode);
mainWindow.getErrorTree().getRoot().getChildren().clear(); root.getChildren().add(allRoNodeTextItem);
mainWindow.getGlobalErrorsView().getItems().clear(); for (AbstractRoom room : rooms) {
}); RoomNode roomNode = new RoomNode(room);
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces()); TreeItem<Renderable> roomNodeTextItem = new TreeItem<>(roomNode);
config.setParserConfig(currentConfig); roomNodeTextItem.setExpanded(true);
currentChecker = new Checker(config, model); allRoNodeTextItem.getChildren().add(roomNodeTextItem);
currentChecker.runChecks(l); createGeometryNodes(room, roomNodeTextItem);
createBoundarySurfaceNodes(room.getBoundarySurfaces(), roomNodeTextItem);
Platform.runLater(() -> { }
// apply check results to tree views
updateFeatureTrees(); }
updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) { private void createBuildingStoreyNodes(Building ab, TreeItem<Renderable> root) {
if (e instanceof SchematronError se) { List<Storey> storeys = ab.getBuildingStoreys();
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString()); if (storeys.isEmpty()) {
} return;
} }
renderer.refresh(); AllStoreysNode allSNode = new AllStoreysNode(storeys);
mainWindow.getWriteReportButton().setDisable(false); TreeItem<Renderable> allSNodeTextItem = new TreeItem<>(allSNode);
}); root.getChildren().add(allSNodeTextItem);
} finally { for (Storey storey : storeys) {
Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false)); StoreyNode storeyNode = new StoreyNode(storey);
} TreeItem<Renderable> storeyNodeTextItem = new TreeItem<>(storeyNode);
} storeyNodeTextItem.setExpanded(true);
allSNodeTextItem.getChildren().add(storeyNodeTextItem);
void updateFeatureTrees() { createGeometryNodes(storey, storeyNodeTextItem);
updateTree(mainWindow.getBuildingsView().getRoot()); createBoundarySurfaceNodes(storey.getBoundarySurfaces(), storeyNodeTextItem);
updateTree(mainWindow.getVegetationView().getRoot()); }
updateTree(mainWindow.getBridgeView().getRoot()); }
updateTree(mainWindow.getTerrainView().getRoot());
updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot()); public void createBuildingUnitNodes(Building ab, TreeItem<Renderable> root) {
renderer.updateErrors(); List<BuildingUnit> buildingUnits = ab.getBuildingUnits();
} if (buildingUnits.isEmpty()) {
return;
private void updateTree(TreeItem<Renderable> root) { }
if (root == null) { AllBuildingUnitsNode allSNode = new AllBuildingUnitsNode(buildingUnits);
return; TreeItem<Renderable> allSNodeTextItem = new TreeItem<>(allSNode);
} root.getChildren().add(allSNodeTextItem);
for (TreeItem<Renderable> item : root.getChildren()) { for (BuildingUnit buildingUnit : buildingUnits) {
updateItem(item); BuildingUnitNode buildingUnitNode = new BuildingUnitNode(buildingUnit);
} TreeItem<Renderable> storeyNodeTextItem = new TreeItem<>(buildingUnitNode);
} storeyNodeTextItem.setExpanded(true);
allSNodeTextItem.getChildren().add(storeyNodeTextItem);
private void updateItem(TreeItem<Renderable> item) { createGeometryNodes(buildingUnit, storeyNodeTextItem);
if (item.getValue() == null) { createBoundarySurfaceNodes(buildingUnit.getBoundarySurfaces(), storeyNodeTextItem);
return; }
} }
item.getValue().refreshTextColor();
for (TreeItem<Renderable> child : item.getChildren()) { private void createBuildingFurnitureNodes(Building ab, TreeItem<Renderable> root) {
updateItem(child); createFurnitureNodes(ab.getBuildingRoomFurnitureList(), root);
} }
}
private void createFurnitureNodes(List<? extends AbstractFurniture> furniture, TreeItem<Renderable> root) {
public void writePdfReport(File pdfFile) { if (furniture.isEmpty()) {
if (currentChecker == null) { return;
return; }
}
currentChecker.writePdfReport(pdfFile.getAbsolutePath()); AllFurnitureNode allFnNode = new AllFurnitureNode(furniture);
} TreeItem<Renderable> allFnNodeTextItem = new TreeItem<>(allFnNode);
root.getChildren().add(allFnNodeTextItem);
public void writeXmlReport(File xmlFile) { for (AbstractFurniture fn : furniture) {
if (currentChecker == null) { FurnitureNode fnNode = new FurnitureNode(fn);
return; TreeItem<Renderable> fnNodeTextItem = new TreeItem<>(fnNode);
} fnNodeTextItem.setExpanded(true);
currentChecker.writeXmlReport(xmlFile.getAbsolutePath()); allFnNodeTextItem.getChildren().add(fnNodeTextItem);
} createGeometryNodes(fn, fnNodeTextItem);
createBoundarySurfaceNodes(fn.getBoundarySurfaceList(), fnNodeTextItem);
private Map<ErrorId, ErrorStat> getErrorStats() { }
Map<ErrorId, ErrorStat> stats = new HashMap<>(); }
addErrorStats(stats, model.getBridges());
addErrorStats(stats, model.getBuildings()); private void createBoundarySurfaceNodes(List<BoundarySurface> bsList, TreeItem<Renderable> root) {
addErrorStats(stats, model.getLand()); if (bsList.isEmpty()) {
addErrorStats(stats, model.getTransportation()); return;
addErrorStats(stats, model.getVegetation()); }
addErrorStats(stats, model.getWater()); AllBoundarySurfacesNode allBsText = new AllBoundarySurfacesNode(bsList);
return stats; TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBsText);
} root.getChildren().add(allBpsTextItem);
private void addErrorStats(Map<ErrorId, ErrorStat> stats, List<? extends CityObject> cos) { allBpsTextItem.getChildren().add(new TreeItem<>());
List<CheckError> errors = new ArrayList<>();
for (CityObject co : cos) { allBpsTextItem.expandedProperty().addListener((obs, old, newV) -> {
co.collectContainedErrors(errors); if (Boolean.TRUE.equals(newV) && allBpsTextItem.getChildren().size() == 1) {
} Platform.runLater(() -> {
Set<CheckError> filteredErrors = new HashSet<>(errors); allBpsTextItem.getChildren().clear();
for (CheckError error : filteredErrors) { for (BoundarySurface bs : bsList) {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new); BoundarySurfaceNode bsText = new BoundarySurfaceNode(bs);
stat.incrementCount(); TreeItem<Renderable> bsTextItem = new TreeItem<>(bsText);
} bsTextItem.setExpanded(true);
} allBpsTextItem.getChildren().add(bsTextItem);
createGeometryNodes(bs, bsTextItem);
public void export(Building b) { createOpeningNodes(bs.getOpenings(), bsTextItem);
if (model == null) { }
return; updateTree(allBpsTextItem);
} });
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile()); }
newModel.setCityModel(new CityModel()); });
newModel.addBuilding(b); }
FileChooser fc = new FileChooser(); private void createOpeningNodes(List<Opening> openings, TreeItem<Renderable> root) {
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml")); if (openings == null || openings.isEmpty()) {
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off")); return;
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, "")); }
if (dir.exists() && dir.isDirectory()) { AllOpeningsNode allOpeningsNode = new AllOpeningsNode(openings);
fc.setInitialDirectory(dir); TreeItem<Renderable> allOpeningsItem = new TreeItem<>(allOpeningsNode);
} else { for (Opening o : openings) {
Settings.set(Settings.LAST_OPEN_FOLDER, ""); OpeningNode openingNode = new OpeningNode(o);
} TreeItem<Renderable> openingsItem = new TreeItem<>(openingNode);
File f = fc.showSaveDialog(mainWindow.getMainStage()); allOpeningsItem.getChildren().add(openingsItem);
if (f != null) { }
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent()); root.getChildren().add(allOpeningsItem);
try { }
newModel.saveAs(f.getAbsolutePath(), true); private void createBuildingPartNodes(Building ab, TreeItem<Renderable> item) {
} catch (CityDoctorWriteException e) { if (ab.getBuildingParts().isEmpty()) {
logger.error(e); return;
} }
} AllBuildingPartsNode allBpsText = new AllBuildingPartsNode(ab.getBuildingParts());
} TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
item.getChildren().add(allBpsTextItem);
public void showWorld() {
if (model != null) { for (BuildingPart bp : ab.getBuildingParts()) {
renderer.render(model); BuildingPartNode bpNode = new BuildingPartNode(bp);
} TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
} bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
public void storeModel(File f, boolean saveQualityAde) throws CityDoctorWriteException { createGeometryNodes(bp, bpNodeItem);
if (model == null) { createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
return; }
} }
model.saveAs(f.getAbsolutePath(), saveQualityAde);
} private void createGeometryNodes(CityObject co, TreeItem<Renderable> item) {
for (Geometry geom : co.getGeometries()) {
public void searchFeature(String searchString, FeatureType selectedTab) { GeometryNode geomNode = new GeometryNode(geom);
if (model == null || searchString == null || searchString.trim().isEmpty()) { TreeItem<Renderable> geomItem = new TreeItem<>(geomNode);
return; item.getChildren().add(geomItem);
} }
mainWindow.unselectEverything(); }
resetFeatureChunks();
if (selectedTab == FeatureType.BUILDING) { public void startChecks(ValidationConfiguration config, ProgressListener l) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings()); if (model == null) {
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView(); logger.warn(Localization.getText("CityDoctorController.noDatamodel"));
TreeItem<Renderable> root = buildingsView.getRoot(); return;
root.getChildren().clear(); }
buildBuildingTreeFromList(foundBuildings, root); if (sourceFile == null) {
updateTree(root); logger.warn(Localization.getText("CityDoctorController.noSourceFile"));
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr); return;
} else { }
TreeView<Renderable> view; try {
List<? extends CityObject> cos; Platform.runLater(() -> {
AtomicInteger chunkCounter; mainWindow.getCheckButton().setDisable(true);
switch (selectedTab) { mainWindow.getErrorTree().getRoot().getChildren().clear();
case VEGETATION: mainWindow.getGlobalErrorsView().getItems().clear();
view = mainWindow.getVegetationView(); });
cos = filterFeatures(searchString, model.getVegetation()); config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
chunkCounter = vegetationChunkNr; config.setParserConfig(currentConfig);
break; currentChecker = new Checker(config, model);
case BRIDGE: currentChecker.runChecks(l);
view = mainWindow.getBridgeView();
cos = filterFeatures(searchString, model.getBridges()); Platform.runLater(() -> {
chunkCounter = bridgeChunkNr; // apply check results to tree views
break; updateFeatureTrees();
case TRANSPORTATION: updateTree(mainWindow.getPolygonsView().getRoot());
view = mainWindow.getTransportationView(); for (CheckError e : model.getGlobalErrors()) {
cos = filterFeatures(searchString, model.getTransportation()); if (e instanceof SchematronError se) {
chunkCounter = transportationChunkNr; mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString());
break; }
case WATER: }
view = mainWindow.getWaterView(); renderer.refresh();
cos = filterFeatures(searchString, model.getWater()); mainWindow.getWriteReportButton().setDisable(false);
chunkCounter = waterChunkNr; });
break; } finally {
case LAND: Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false));
view = mainWindow.getTerrainView(); }
cos = filterFeatures(searchString, model.getLand()); }
chunkCounter = landChunkNr;
break; void updateFeatureTrees() {
default: updateTree(mainWindow.getBuildingsView().getRoot());
throw new IllegalStateException("Unknown selected feature tab"); updateTree(mainWindow.getVegetationView().getRoot());
} updateTree(mainWindow.getBridgeView().getRoot());
TreeItem<Renderable> root = view.getRoot(); updateTree(mainWindow.getTerrainView().getRoot());
root.getChildren().clear(); updateTree(mainWindow.getCityFurnitureView().getRoot());
buildTreeFromList(cos, root, chunkCounter); updateTree(mainWindow.getTransportationView().getRoot());
updateTree(root); updateTree(mainWindow.getWaterView().getRoot());
addMoreButtonIfNecessary(cos, view, root, chunkCounter); updateTree(mainWindow.getOtherObjectsView().getRoot());
} renderer.updateErrors();
} }
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) { private void updateTree(TreeItem<Renderable> root) {
List<T> foundFeatures = new ArrayList<>(); if (root == null) {
for (T t : features) { return;
if (t.getGmlId().getGmlString().contains(searchString)) { }
foundFeatures.add(t); for (TreeItem<Renderable> item : root.getChildren()) {
} updateItem(item);
} }
return foundFeatures; }
}
private void updateItem(TreeItem<Renderable> item) {
public void resetSearch(FeatureType selectedTab) { if (item.getValue() == null) {
if (model == null) { return;
return; }
} item.getValue().refreshTextColor();
resetFeatureChunks(); for (TreeItem<Renderable> child : item.getChildren()) {
if (selectedTab == FeatureType.BUILDING) { updateItem(child);
// buildings are handled differently, because of surface and building }
// installations }
TreeItem<Renderable> root = mainWindow.getBuildingsView().getRoot();
if (root != null) { public void writePdfReport(File pdfFile) {
root.getChildren().clear(); if (currentChecker == null) {
buildBuildingTreeFromList(model.getBuildings(), root); return;
updateTree(root); }
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), mainWindow.getBuildingsView(), root, currentChecker.writePdfReport(pdfFile.getAbsolutePath());
buildingChunkNr); }
}
} else { public void writeXmlReport(File xmlFile) {
TreeView<Renderable> view; if (currentChecker == null) {
List<? extends CityObject> cos; return;
AtomicInteger chunkCounter; }
switch (selectedTab) { currentChecker.writeXmlReport(xmlFile.getAbsolutePath());
case VEGETATION: }
view = mainWindow.getVegetationView();
cos = model.getVegetation(); private Map<ErrorId, ErrorStat> getErrorStats() {
chunkCounter = vegetationChunkNr; Map<ErrorId, ErrorStat> stats = new HashMap<>();
break; addErrorStats(stats, model.getBridges());
case BRIDGE: addErrorStats(stats, model.getBuildings());
view = mainWindow.getBridgeView(); addErrorStats(stats, model.getLand());
cos = model.getBridges(); addErrorStats(stats, model.getTransportation());
chunkCounter = bridgeChunkNr; addErrorStats(stats, model.getVegetation());
break; addErrorStats(stats, model.getWater());
case TRANSPORTATION: addErrorStats(stats, model.getCityFurniture());
view = mainWindow.getTransportationView(); addErrorStats(stats, model.getGenericCityObjects());
cos = model.getTransportation(); return stats;
chunkCounter = transportationChunkNr; }
break;
case WATER: private void addErrorStats(Map<ErrorId, ErrorStat> stats, List<? extends CityObject> cos) {
view = mainWindow.getWaterView(); List<CheckError> errors = new ArrayList<>();
cos = model.getWater(); for (CityObject co : cos) {
chunkCounter = waterChunkNr; co.collectContainedErrors(errors);
break; }
case LAND: Set<CheckError> filteredErrors = new HashSet<>(errors);
view = mainWindow.getTerrainView(); for (CheckError error : filteredErrors) {
cos = model.getLand(); ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
chunkCounter = landChunkNr; stat.incrementCount();
break; }
default: }
throw new IllegalStateException("Unknown selected feature tab");
} public void export(Building b) {
TreeItem<Renderable> root = view.getRoot(); if (model == null) {
root.getChildren().clear(); return;
buildTreeFromList(cos, root, chunkCounter); }
updateTree(root); CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
addMoreButtonIfNecessary(cos, view, root, chunkCounter); newModel.setCityModel(new CityModel());
} newModel.addBuilding(b);
}
FileChooser fc = new FileChooser();
public Series<String, Number> createErrorSeries() { fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
Series<String, Number> series = new Series<>(); fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
if (model == null) { File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
return series; if (dir.exists() && dir.isDirectory()) {
} fc.setInitialDirectory(dir);
Map<ErrorId, ErrorStat> errorStats = getErrorStats(); } else {
for (ErrorStat es : errorStats.values()) { Settings.set(Settings.LAST_OPEN_FOLDER, "");
series.getData().add(new Data<>(es.getErrorId().toString(), es.getCount())); }
} File f = fc.showSaveDialog(mainWindow.getMainStage());
return series; if (f != null) {
} Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
public String getFileName() {
return model.getFileName(); newModel.saveAs(f.getAbsolutePath(), true);
} } catch (CityDoctorWriteException e) {
logger.error(e);
public void fillTreeViewWithErrorBuildings() { }
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView(); }
TreeItem<Renderable> root = buildingsView.getRoot(); }
if (model == null) {
return; public void showWorld() {
} if (model != null) {
if (root == null) { renderer.render(model);
return; }
} }
mainWindow.resetSearchBar();
root.getChildren().clear(); public void storeModel(File f, boolean saveQualityAde) throws CityDoctorWriteException {
List<Building> errorBuildings = new ArrayList<>(); if (model == null) {
for (Building b : model.getBuildings()) { return;
if (b.containsAnyError()) { }
errorBuildings.add(b); model.saveAs(f.getAbsolutePath(), saveQualityAde);
} }
}
resetFeatureChunks(); public void searchFeature(String searchString, FeatureType selectedTab) {
buildBuildingTreeFromList(errorBuildings, root); if (model == null || searchString == null || searchString.trim().isEmpty()) {
updateTree(root); return;
addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr); }
} mainWindow.unselectEverything();
resetFeatureChunks();
public void fillTreeViewWithErrorVegetation() { if (selectedTab == FeatureType.BUILDING) {
if (model == null) { List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
return; TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
} TreeItem<Renderable> root = buildingsView.getRoot();
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr); root.getChildren().clear();
} buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
public void fillTreeViewWithErrorBridges() { addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
if (model == null) { } else {
return; TreeView<Renderable> view;
} List<? extends CityObject> cos;
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr); AtomicInteger chunkCounter;
} switch (selectedTab) {
case VEGETATION:
public void fillTreeViewWithErrorLand() { view = mainWindow.getVegetationView();
if (model == null) { cos = filterFeatures(searchString, model.getVegetation());
return; chunkCounter = vegetationChunkNr;
} break;
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr); case BRIDGE:
} view = mainWindow.getBridgeView();
cos = filterFeatures(searchString, model.getBridges());
public void fillTreeViewWithErrorTransportation() { chunkCounter = bridgeChunkNr;
if (model == null) { break;
return; case TRANSPORTATION:
} view = mainWindow.getTransportationView();
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(), cos = filterFeatures(searchString, model.getTransportation());
transportationChunkNr); chunkCounter = transportationChunkNr;
} break;
case TUNNEL:
public void fillTreeViewWithErrorWater() { view = mainWindow.getTunnelView();
if (model == null) { cos = model.getTunnels();
return; chunkCounter = tunnelChunkNr;
} break;
fillTreeViewWithErrorCityObjects(mainWindow.getWaterView(), model.getWater(), waterChunkNr); case WATER:
} view = mainWindow.getWaterView();
cos = filterFeatures(searchString, model.getWater());
private void fillTreeViewWithErrorCityObjects(TreeView<Renderable> treeView, List<? extends CityObject> objects, chunkCounter = waterChunkNr;
AtomicInteger chunkCounter) { break;
TreeItem<Renderable> root = treeView.getRoot(); case LAND:
if (root == null) { view = mainWindow.getTerrainView();
return; cos = filterFeatures(searchString, model.getLand());
} chunkCounter = landChunkNr;
mainWindow.resetSearchBar(); break;
root.getChildren().clear(); case CITY_FURNITURE:
List<CityObject> errorObjects = new ArrayList<>(); view = mainWindow.getCityFurnitureView();
for (CityObject co : objects) { cos = filterFeatures(searchString, model.getCityFurniture());
if (co.containsAnyError()) { chunkCounter = cityFurnitureChunkNr;
errorObjects.add(co); break;
} case GENERIC_CITY_OBJECT:
} view = mainWindow.getOtherObjectsView();
buildTreeFromList(errorObjects, root, chunkCounter); cos = filterFeatures(searchString, model.getGenericCityObjects());
updateTree(root); chunkCounter = otherObjectsChunkNr;
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter); break;
} default:
throw new IllegalStateException("Unknown selected feature tab");
public void fillTreeViewFromFeatures(FeatureType selectedTab) { }
if (model == null) { TreeItem<Renderable> root = view.getRoot();
return; root.getChildren().clear();
} buildTreeFromList(cos, root, chunkCounter);
mainWindow.resetSearchBar(); updateTree(root);
switch (selectedTab) { addMoreButtonIfNecessary(cos, view, root, chunkCounter);
case BUILDING: }
buildBuildings(model); }
updateTree(mainWindow.getBuildingsView().getRoot());
break; private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
case VEGETATION: List<T> foundFeatures = new ArrayList<>();
buildVegetation(model.getVegetation()); for (T t : features) {
updateTree(mainWindow.getVegetationView().getRoot()); if (t.getGmlId().getGmlString().contains(searchString)) {
break; foundFeatures.add(t);
case BRIDGE: }
buildBridges(model); }
updateTree(mainWindow.getBridgeView().getRoot()); return foundFeatures;
break; }
case LAND:
buildLand(model); public void resetSearch(FeatureType selectedTab) {
updateTree(mainWindow.getTerrainView().getRoot()); if (model == null) {
break; return;
case TRANSPORTATION: }
buildTransportation(model.getTransportation()); resetFeatureChunks();
updateTree(mainWindow.getTransportationView().getRoot()); if (selectedTab == FeatureType.BUILDING) {
break; // buildings are handled differently, because of surface and building
case WATER: // installations
buildWater(model); TreeItem<Renderable> root = mainWindow.getBuildingsView().getRoot();
updateTree(mainWindow.getWaterView().getRoot()); if (root != null) {
break; root.getChildren().clear();
default: buildBuildingTreeFromList(model.getBuildings(), root);
throw new IllegalStateException(); updateTree(root);
} addMoreButtonToBuildingsIfNecessary(model.getBuildings(), mainWindow.getBuildingsView(), root,
} buildingChunkNr);
}
public CityDoctorModel getModel() { } else {
return model; TreeView<Renderable> view;
} List<? extends CityObject> cos;
AtomicInteger chunkCounter;
public void showView(View v) { switch (selectedTab) {
v.fireOnShowEvent(model, currentChecker, mainWindow); case VEGETATION:
} view = mainWindow.getVegetationView();
cos = model.getVegetation();
public void askAndSave() { chunkCounter = vegetationChunkNr;
boolean saveWithQualityAde = true; break;
if (model.isValidated()) { case BRIDGE:
ButtonType yesBtn = ButtonType.YES; view = mainWindow.getBridgeView();
ButtonType noBtn = ButtonType.NO; cos = model.getBridges();
Dialog<ButtonType> dialog = new Dialog<>(); chunkCounter = bridgeChunkNr;
dialog.setTitle("Save with QualityADE?"); break;
dialog.setContentText("Save with QualityADE information?"); case TRANSPORTATION:
dialog.getDialogPane().getButtonTypes().add(yesBtn); view = mainWindow.getTransportationView();
dialog.getDialogPane().getButtonTypes().add(noBtn); cos = model.getTransportation();
chunkCounter = transportationChunkNr;
Optional<ButtonType> result = dialog.showAndWait(); break;
if (result.isPresent() && result.get() == ButtonType.NO) { case TUNNEL:
saveWithQualityAde = false; view = mainWindow.getTunnelView();
} cos = model.getTunnels();
} chunkCounter = tunnelChunkNr;
break;
FileChooser fc = new FileChooser(); case WATER:
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml")); view = mainWindow.getWaterView();
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off")); cos = model.getWater();
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, "")); chunkCounter = waterChunkNr;
if (dir.exists() && dir.isDirectory()) { break;
fc.setInitialDirectory(dir); case LAND:
} else { view = mainWindow.getTerrainView();
Settings.set(Settings.LAST_OPEN_FOLDER, ""); cos = model.getLand();
} chunkCounter = landChunkNr;
File f = fc.showSaveDialog(mainWindow.getMainStage()); break;
if (f != null) { case CITY_FURNITURE:
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent()); view = mainWindow.getCityFurnitureView();
try { cos = model.getCityFurniture();
storeModel(f, saveWithQualityAde); chunkCounter = cityFurnitureChunkNr;
} catch (CityDoctorWriteException e) { break;
mainWindow.showExceptionDialog(e); case GENERIC_CITY_OBJECT:
} view = mainWindow.getOtherObjectsView();
} cos = model.getGenericCityObjects();
} chunkCounter = otherObjectsChunkNr;
break;
public void delete(TreeItem<Renderable> selectedItem) { default:
if (model == null) { throw new IllegalStateException("Unknown selected feature tab");
return; }
} TreeItem<Renderable> root = view.getRoot();
Renderable render = selectedItem.getValue(); root.getChildren().clear();
if (render instanceof BuildingNode node) { buildTreeFromList(cos, root, chunkCounter);
model.getBuildings().remove(node.getBuilding()); updateTree(root);
mainWindow.getBuildingsView().getRoot().getChildren().remove(selectedItem); addMoreButtonIfNecessary(cos, view, root, chunkCounter);
} }
}
}
public Series<String, Number> createErrorSeries() {
public void errorFilterIndexChanged(Number newV) { Series<String, Number> series = new Series<>();
mainWindow.getMeshGroup().getChildren().clear(); if (model == null) {
mainWindow.unselectEverything(); return series;
if (newV.intValue() == 0) { }
fillTreeViewFromFeatures(mainWindow.getSelectedTab()); Map<ErrorId, ErrorStat> errorStats = getErrorStats();
} else if (newV.intValue() == 1) { for (ErrorStat es : errorStats.values()) {
switch (mainWindow.getSelectedTab()) { series.getData().add(new Data<>(es.getErrorId().toString(), es.getCount()));
case BUILDING: }
fillTreeViewWithErrorBuildings(); return series;
break; }
case VEGETATION:
fillTreeViewWithErrorVegetation(); public String getFileName() {
break; return model.getFileName();
case BRIDGE: }
fillTreeViewWithErrorBridges();
break; public void fillTreeViewWithErrorBuildings() {
case LAND: TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
fillTreeViewWithErrorLand(); TreeItem<Renderable> root = buildingsView.getRoot();
break; if (model == null) {
case TRANSPORTATION: return;
fillTreeViewWithErrorTransportation(); }
break; if (root == null) {
case WATER: return;
fillTreeViewWithErrorWater(); }
break; mainWindow.resetSearchBar();
default: root.getChildren().clear();
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab()); List<Building> errorBuildings = new ArrayList<>();
} for (Building b : model.getBuildings()) {
} else { if (b.containsAnyError()) {
throw new IllegalStateException("Unknown filter index selected: " + newV); errorBuildings.add(b);
} }
} }
resetFeatureChunks();
public ParserConfiguration getCurrentConfig() { buildBuildingTreeFromList(errorBuildings, root);
return currentConfig; updateTree(root);
} addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr);
}
public void fillTreeViewWithErrorVegetation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr);
}
public void fillTreeViewWithErrorBridges() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr);
}
public void fillTreeViewWithErrorLand() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr);
}
public void fillTreeViewWithErrorCityFurniture() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getCityFurnitureView(),
model.getCityFurniture(), cityFurnitureChunkNr);
}
public void fillTreeViewWithErrorOtherObjects() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getOtherObjectsView(),
model.getGenericCityObjects(), otherObjectsChunkNr);
}
public void fillTreeViewWithErrorTransportation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(),
transportationChunkNr);
}
public void fillTreeViewWithErrorTunnel() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTunnelView(), model.getTunnels(), tunnelChunkNr);
}
public void fillTreeViewWithErrorWater() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getWaterView(), model.getWater(), waterChunkNr);
}
private void fillTreeViewWithErrorCityObjects(TreeView<Renderable> treeView, List<? extends CityObject> objects,
AtomicInteger chunkCounter) {
TreeItem<Renderable> root = treeView.getRoot();
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<CityObject> errorObjects = new ArrayList<>();
for (CityObject co : objects) {
if (co.containsAnyError()) {
errorObjects.add(co);
}
}
buildTreeFromList(errorObjects, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter);
}
public void fillTreeViewFromFeatures(FeatureType selectedTab) {
if (model == null) {
return;
}
mainWindow.resetSearchBar();
switch (selectedTab) {
case BUILDING:
buildBuildings(model);
updateTree(mainWindow.getBuildingsView().getRoot());
break;
case VEGETATION:
buildVegetation(model.getVegetation());
updateTree(mainWindow.getVegetationView().getRoot());
break;
case BRIDGE:
buildBridges(model);
updateTree(mainWindow.getBridgeView().getRoot());
break;
case LAND:
buildLand(model);
updateTree(mainWindow.getTerrainView().getRoot());
break;
case TRANSPORTATION:
buildTransportation(model.getTransportation());
updateTree(mainWindow.getTransportationView().getRoot());
break;
case WATER:
buildWater(model);
updateTree(mainWindow.getWaterView().getRoot());
break;
case CITY_FURNITURE:
buildCityFurniture(model);
updateTree(mainWindow.getCityFurnitureView().getRoot());
break;
case GENERIC_CITY_OBJECT:
buildOtherCityObjects(model);
updateTree(mainWindow.getOtherObjectsView().getRoot());
break;
default:
throw new IllegalStateException();
}
}
public CityDoctorModel getModel() {
return model;
}
public void showView(View v) {
v.fireOnShowEvent(model, currentChecker, mainWindow);
}
public void askAndSave() {
boolean saveWithQualityAde = true;
if (model.isValidated()) {
ButtonType yesBtn = ButtonType.YES;
ButtonType noBtn = ButtonType.NO;
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setTitle("Save with QualityADE?");
dialog.setContentText("Save with QualityADE information?");
dialog.getDialogPane().getButtonTypes().add(yesBtn);
dialog.getDialogPane().getButtonTypes().add(noBtn);
Optional<ButtonType> result = dialog.showAndWait();
if (result.isPresent() && result.get() == ButtonType.NO) {
saveWithQualityAde = false;
}
}
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(mainWindow.getMainStage());
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
storeModel(f, saveWithQualityAde);
logger.info("Saving successful");
} catch (CityDoctorWriteException e) {
mainWindow.showExceptionDialog(e);
}
}
}
public void delete(TreeItem<Renderable> selectedItem) {
if (model == null) {
return;
}
Renderable render = selectedItem.getValue();
if (render instanceof BuildingNode node) {
model.getBuildings().remove(node.getBuilding());
mainWindow.getBuildingsView().getRoot().getChildren().remove(selectedItem);
}
}
public void errorFilterIndexChanged(Number newV) {
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.unselectEverything();
if (newV.intValue() == 0) {
fillTreeViewFromFeatures(mainWindow.getSelectedTab());
} else if (newV.intValue() == 1) {
switch (mainWindow.getSelectedTab()) {
case BUILDING:
fillTreeViewWithErrorBuildings();
break;
case VEGETATION:
fillTreeViewWithErrorVegetation();
break;
case BRIDGE:
fillTreeViewWithErrorBridges();
break;
case LAND:
fillTreeViewWithErrorLand();
break;
case TRANSPORTATION:
fillTreeViewWithErrorTransportation();
break;
case WATER:
fillTreeViewWithErrorWater();
break;
case CITY_FURNITURE:
fillTreeViewWithErrorCityFurniture();
break;
case GENERIC_CITY_OBJECT:
fillTreeViewWithErrorOtherObjects();
break;
default:
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab());
}
} else {
throw new IllegalStateException("Unknown filter index selected: " + newV);
}
}
public ParserConfiguration getCurrentConfig() {
return currentConfig;
}
public void setOriginBB(BoundingBox origin) {
this.originBB = origin;
}
public BoundingBox getOriginBB() {
return originBB;
}
} }
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import java.io.IOException;
import java.io.InputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable; import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button; import javafx.scene.control.*;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.Tooltip;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
public class MainToolBar { public class MainToolBar {
private static final Logger logger = LogManager.getLogger(MainToolBar.class); private static final Logger logger = LogManager.getLogger(MainToolBar.class);
@FXML
private Button saveBtn;
@FXML
private ImageView saveView;
@FXML
private Button openBtn;
@FXML
private ImageView openImageView;
@FXML @FXML
private Button saveBtn; private Button checkBtn;
@FXML @FXML
private ImageView saveView; private ImageView checkImageView;
@FXML @FXML
private Button openBtn; private Button showWorldBtn;
@FXML @FXML
private ImageView openImageView; private ImageView showWorldImageView;
@FXML @FXML
private Button checkBtn; private ToggleButton hideRoofBtn;
@FXML @FXML
private ImageView checkImageView; private ImageView hideRoofView;
@FXML @FXML
private Button showWorldBtn; private Button resetCameraBtn;
@FXML @FXML
private ImageView showWorldImageView; private ImageView resetCameraView;
@FXML @FXML
private Button schematronBtn; private Button schematronBtn;
@FXML @FXML
private ImageView schematronImgView; private ImageView schematronImgView;
@FXML @FXML
private ToggleButton lod1Btn; private ToggleButton lod1Btn;
@FXML @FXML
private ImageView lod1View; private ImageView lod1View;
@FXML @FXML
private ToggleButton lod2Btn; private ToggleButton lod2Btn;
@FXML @FXML
private ImageView lod2View; private ImageView lod2View;
@FXML @FXML
private ToggleButton lod3Btn; private ToggleButton lod3Btn;
@FXML @FXML
private ImageView lod3View; private ImageView lod3View;
@FXML @FXML
private ToggleButton lod4Btn; private ToggleButton lod4Btn;
@FXML @FXML
private ImageView lod4View; private ImageView lod4View;
@FXML @FXML
private Button aboutBtn; private Button aboutBtn;
@FXML @FXML
private ImageView aboutImgView; private ImageView aboutImgView;
@FXML @FXML
private ToggleButton gridButton; private ToggleButton gridButton;
@FXML @FXML
private ToggleButton cullingButton; private ToggleButton cullingButton;
@FXML @FXML
private ImageView cullingImageView; private ImageView cullingImageView;
@FXML @FXML
private ImageView gridImageView; private ImageView gridImageView;
@FXML @FXML
private Button reportBtn; private Button reportBtn;
@FXML @FXML
private ImageView reportImageView; private ImageView reportImageView;
private OpenFileDialog fileDialog; private OpenFileDialog fileDialog;
private CheckDialog checkDialog; private CheckDialog checkDialog;
private WriteReportDialog writeDialog; private WriteReportDialog writeDialog;
private AboutDialog aboutDialog; private AboutDialog aboutDialog;
private CityDoctorController controller; private CityDoctorController controller;
private TabPane featurePane; private TabPane featurePane;
private Stage stage; private Stage stage;
private Renderer renderer; private Renderer renderer;
private MainWindow mainWindow; private MainWindow mainWindow;
private HBox toolBar; private HBox toolBar;
public MainToolBar(Stage stage, CityDoctorController controller, TabPane featurePane, Renderer renderer, public MainToolBar(Stage stage, CityDoctorController controller, TabPane featurePane, Renderer renderer,
MainWindow mainWindow) throws IOException { MainWindow mainWindow) throws IOException {
this.controller = controller; this.controller = controller;
this.featurePane = featurePane; this.featurePane = featurePane;
this.renderer = renderer; this.renderer = renderer;
this.stage = stage; this.stage = stage;
this.mainWindow = mainWindow; this.mainWindow = mainWindow;
FXMLLoader loader = new FXMLLoader(MainToolBar.class.getResource("MainToolBar.fxml")); FXMLLoader loader = new FXMLLoader(MainToolBar.class.getResource("MainToolBar.fxml"));
loader.setController(this); loader.setController(this);
toolBar = loader.load(); toolBar = loader.load();
fileDialog = new OpenFileDialog(stage, controller); fileDialog = new OpenFileDialog(stage, controller);
} }
public void initialize() { public void initialize() {
openBtn.setOnAction(ae -> fileDialog.show()); openBtn.setOnAction(ae -> fileDialog.show());
setupSaveBtn(); setupSaveBtn();
setupCheckButton(); setupCheckButton();
setupLodButtons(); setupLodButtons();
setupAboutButton(); setupAboutButton();
setupReportButton(); setupReportButton();
setupResetCameraButton();
loadImages(); setupHideRoofButton();
loadImages();
gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected()));
gridButton.setTooltip(new Tooltip(Localization.getText("MainToolBar.wireframe"))); gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected()));
cullingButton.setOnAction(ae -> renderer.enableCulling(cullingButton.isSelected())); gridButton.setTooltip(new Tooltip(Localization.getText("MainToolBar.wireframe")));
cullingButton.setTooltip(new Tooltip(Localization.getText("MainToolBar.culling"))); cullingButton.setOnAction(ae -> renderer.enableCulling(cullingButton.isSelected()));
cullingButton.setTooltip(new Tooltip(Localization.getText("MainToolBar.culling")));
showWorldBtn.setOnAction(ar -> {
Tab selectedItem = featurePane.getSelectionModel().getSelectedItem(); showWorldBtn.setOnAction(ar -> {
if (selectedItem.getContent() instanceof TreeView) { Tab selectedItem = featurePane.getSelectionModel().getSelectedItem();
@SuppressWarnings("unchecked") if (selectedItem.getContent() instanceof TreeView) {
TreeView<Renderable> content = (TreeView<Renderable>) selectedItem.getContent(); @SuppressWarnings("unchecked")
content.getSelectionModel().clearSelection(); TreeView<Renderable> content = (TreeView<Renderable>) selectedItem.getContent();
} content.getSelectionModel().clearSelection();
controller.showWorld(); }
}); controller.showWorld();
} });
showWorldBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.showWorld")));
private void loadImages() { }
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/openFolderIcon.png")) { private void loadImages() {
Image img = new Image(inStream); try {
openImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/openFolderIcon.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/check32x32.png")) { openImageView.setImage(img);
Image img = new Image(inStream); }
checkImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/check32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/wireframe32x32.png")) { checkImageView.setImage(img);
Image img = new Image(inStream); }
gridImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/wireframe32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Culling.png")) { gridImageView.setImage(img);
Image img = new Image(inStream); }
cullingImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Culling.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/error_stat32x32.png")) { cullingImageView.setImage(img);
Image img = new Image(inStream); }
reportImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/error_stat32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/scene.png")) { reportImageView.setImage(img);
Image img = new Image(inStream); }
showWorldImageView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/scene.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod1_32x32.png")) { showWorldImageView.setImage(img);
Image img = new Image(inStream); }
lod1View.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod1_32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod2_32x32.png")) { lod1View.setImage(img);
Image img = new Image(inStream); }
lod2View.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod2_32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod3_32x32.png")) { lod2View.setImage(img);
Image img = new Image(inStream); }
lod3View.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod3_32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod4_32x32.png")) { lod3View.setImage(img);
Image img = new Image(inStream); }
lod4View.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/lod4_32x32.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/about.png")) { lod4View.setImage(img);
Image img = new Image(inStream); }
aboutImgView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/about.png")) {
} Image img = new Image(inStream);
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) { aboutImgView.setImage(img);
Image img = new Image(inStream); }
saveView.setImage(img); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) {
} Image img = new Image(inStream);
} catch (IOException e) { saveView.setImage(img);
// ignore close exception }
} try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/reset_camera.png")) {
} Image img = new Image(inStream);
resetCameraView.setImage(img);
private void setupReportButton() { }
reportBtn.setDisable(true); try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/hide_roof.png")) {
reportBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.writeReports"))); Image img = new Image(inStream);
reportBtn.setOnAction(ae -> { hideRoofView.setImage(img);
if (writeDialog == null) { }
try { } catch (IOException e) {
writeDialog = new WriteReportDialog(stage, controller, mainWindow); // ignore close exception
} catch (IOException e) { }
logger.catching(e); }
mainWindow.showExceptionDialog(e);
} private void setupReportButton() {
} reportBtn.setDisable(true);
if (writeDialog != null) { reportBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.writeReports")));
// writeDialog can be null if creation of said dialog fails reportBtn.setOnAction(ae -> {
writeDialog.show(); if (writeDialog == null) {
} try {
}); writeDialog = new WriteReportDialog(stage, controller, mainWindow);
} } catch (IOException e) {
logger.catching(e);
private void setupAboutButton() { mainWindow.showExceptionDialog(e);
aboutBtn.setOnAction(ae -> { }
if (aboutDialog == null) { }
try { if (writeDialog != null) {
aboutDialog = new AboutDialog(stage); // writeDialog can be null if creation of said dialog fails
aboutDialog.show(); writeDialog.show();
} catch (IOException e) { }
logger.error("Could not load about dialog.", e); });
} }
} else {
aboutDialog.show(); private void setupAboutButton() {
} aboutBtn.setOnAction(ae -> {
}); if (aboutDialog == null) {
} try {
aboutDialog = new AboutDialog(stage);
private void setupLodButtons() { aboutDialog.show();
lod1Btn.setOnAction(ae -> { } catch (IOException e) {
if (lod1Btn.isSelected()) { logger.error("Could not load about dialog.", e);
renderer.enableLod1(); }
} else { } else {
renderer.disableLod1(); aboutDialog.show();
} }
}); });
lod2Btn.setOnAction(ae -> { }
if (lod2Btn.isSelected()) {
renderer.enableLod2(); private void setupLodButtons() {
} else { lod1Btn.setOnAction(ae -> {
renderer.disableLod2(); if (lod1Btn.isSelected()) {
} renderer.enableLod1();
}); } else {
lod3Btn.setOnAction(ae -> { renderer.disableLod1();
if (lod3Btn.isSelected()) { }
renderer.enableLod3(); });
} else { lod2Btn.setOnAction(ae -> {
renderer.disableLod3(); if (lod2Btn.isSelected()) {
} renderer.enableLod2();
}); } else {
lod4Btn.setOnAction(ae -> { renderer.disableLod2();
if (lod4Btn.isSelected()) { }
renderer.enableLod4(); });
} else { lod3Btn.setOnAction(ae -> {
renderer.disableLod4(); if (lod3Btn.isSelected()) {
} renderer.enableLod3();
}); } else {
} renderer.disableLod3();
}
private void setupSaveBtn() { });
saveBtn.setOnAction(ae -> controller.askAndSave()); lod4Btn.setOnAction(ae -> {
} if (lod4Btn.isSelected()) {
renderer.enableLod4();
private void setupCheckButton() { } else {
checkBtn.setDisable(true); renderer.disableLod4();
checkBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.executeChecks"))); }
checkBtn.setOnAction(ae -> { });
if (checkDialog == null) { }
try {
checkDialog = new CheckDialog(mainWindow, stage, controller); private void setupSaveBtn() {
} catch (IOException e) { saveBtn.setOnAction(ae -> controller.askAndSave());
mainWindow.showExceptionDialog(e); }
logger.catching(e);
} private void setupCheckButton() {
} checkBtn.setDisable(true);
checkDialog.show(); checkBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.executeChecks")));
}); checkBtn.setOnAction(ae -> {
} if (checkDialog == null) {
try {
public Button getCheckButton() { checkDialog = new CheckDialog(mainWindow, stage, controller);
return checkBtn; } catch (IOException e) {
} mainWindow.showExceptionDialog(e);
logger.catching(e);
public ToggleButton getGridButton() { }
return gridButton; }
} checkDialog.show();
});
public ToggleButton getCullingButton() { }
return cullingButton;
} private void setupResetCameraButton() {
resetCameraBtn.setDisable(true);
public Button getWriteReportButton() { resetCameraBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.resetCamera")));
return reportBtn; resetCameraBtn.setOnAction(ae -> mainWindow.resetCamera());
}
}
public ToggleButton getLod1Btn() {
return lod1Btn; private void setupHideRoofButton() {
} hideRoofBtn.setDisable(true);
hideRoofBtn.setSelected(false);
public ToggleButton getLod2Btn() { hideRoofBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.hideRoof")));
return lod2Btn; hideRoofBtn.setOnAction(ae -> {
} if (hideRoofBtn.isSelected()) {
renderer.hideRoofs();
public ToggleButton getLod3Btn() { } else {
return lod3Btn; renderer.showRoofs();
} }
});
public ToggleButton getLod4Btn() {
return lod4Btn; }
}
public Button getCheckButton() {
public Button getWorldBtn() { return checkBtn;
return showWorldBtn; }
}
public ToggleButton getGridButton() {
public Button getSaveBtn() { return gridButton;
return saveBtn; }
}
public ToggleButton getCullingButton() {
public HBox getToolBar() { return cullingButton;
return toolBar; }
}
public Button getSaveButton() {
public Button getOpenBtn() { return saveBtn;
return openBtn; }
}
public Button getWriteReportButton() {
return reportBtn;
}
public ToggleButton getLod1Btn() {
return lod1Btn;
}
public ToggleButton getLod2Btn() {
return lod2Btn;
}
public ToggleButton getLod3Btn() {
return lod3Btn;
}
public ToggleButton getLod4Btn() {
return lod4Btn;
}
public ToggleButton getHideRoofBtn() {
return hideRoofBtn;
}
public Button getWorldBtn() {
return showWorldBtn;
}
public Button getSaveBtn() {
return saveBtn;
}
public Button getResetCameraBtn() {
return resetCameraBtn;
}
public HBox getToolBar() {
return toolBar;
}
public Button getOpenBtn() {
return openBtn;
}
} }
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.CityDoctorValidation; import de.hft.stuttgart.citydoctor2.CityDoctorValidation;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox; import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
...@@ -34,35 +19,9 @@ import javafx.beans.value.ChangeListener; ...@@ -34,35 +19,9 @@ import javafx.beans.value.ChangeListener;
import javafx.embed.swing.SwingFXUtils; import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.AmbientLight; import javafx.scene.*;
import javafx.scene.Group; import javafx.scene.control.*;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.RadioButton;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.ToolBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage; import javafx.scene.image.WritableImage;
...@@ -77,902 +36,1109 @@ import javafx.scene.layout.Priority; ...@@ -77,902 +36,1109 @@ import javafx.scene.layout.Priority;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
public class MainWindow extends Application { public class MainWindow extends Application {
private static final Logger logger = LogManager.getLogger(MainWindow.class); private static final Logger logger = LogManager.getLogger(MainWindow.class);
private static final double CAMERA_TRANSLATE_Z = -100.0;
private static final double CAMERA_INITIAL_X_ANGLE = 20.0;
private static final double CAMERA_INITIAL_Y_ANGLE = 120.0;
@FXML
private TreeView<Renderable> buildingsView;
@FXML
private TreeView<Renderable> vegetationView;
@FXML
private TreeView<Renderable> transView;
@FXML
private TreeView<Renderable> tunnelView;
@FXML
private TreeView<Renderable> bridgeView;
@FXML
private TreeView<Renderable> waterView;
@FXML
private TreeView<Renderable> terrainView;
private static final double CAMERA_TRANSLATE_Z = -100.0; @FXML
private static final double CAMERA_INITIAL_X_ANGLE = 20.0; private TreeView<Renderable> cityFurnitureView;
private static final double CAMERA_INITIAL_Y_ANGLE = 120.0;
@FXML @FXML
private TreeView<Renderable> buildingsView; private TreeView<Renderable> attributeView;
@FXML @FXML
private TreeView<Renderable> vegetationView; TreeView<Renderable> otherObjectsView;
@FXML @FXML
private TreeView<Renderable> transView; private TreeView<Renderable> polygonView;
@FXML @FXML
private TreeView<Renderable> bridgeView; private TreeView<Renderable> edgeView;
@FXML @FXML
private TreeView<Renderable> waterView; private TreeView<Renderable> vertexView;
@FXML @FXML
private TreeView<Renderable> terrainView; private Pane meshView;
@FXML @FXML
private TreeView<Renderable> polygonView; private SplitPane mainContainer;
@FXML @FXML
private TreeView<Renderable> edgeView; private TabPane detailsTabPane;
@FXML @FXML
private TreeView<Renderable> vertexView; private TabPane featurePane;
@FXML @FXML
private Pane meshView; private TextField searchField;
@FXML @FXML
private SplitPane mainContainer; private TreeView<Renderable> errorView;
@FXML @FXML
private TabPane detailsTabPane; private Button clearBtn;
@FXML @FXML
private TabPane featurePane; private Button searchBtn;
@FXML @FXML
private TextField searchField; private ToggleButton allButton;
@FXML @FXML
private TreeView<Renderable> errorView; private ToggleButton errorButton;
@FXML @FXML
private Button clearBtn; private ComboBox<String> showCityObjectsCombo;
@FXML @FXML
private Button searchBtn; private HBox viewPane;
@FXML @FXML
private ToggleButton allButton; private ListView<String> globalErrorsView;
@FXML @FXML
private ToggleButton errorButton; private BorderPane mainPane;
@FXML @FXML
private ComboBox<String> showCityObjectsCombo; private HBox viewButtonBox;
@FXML @FXML
private HBox viewPane; private ComboBox<Locale> languageSelector;
@FXML @FXML
private ListView<String> globalErrorsView; private Tab buildingsTab;
@FXML @FXML
private BorderPane mainPane; private Tab vegetationTab;
@FXML @FXML
private HBox viewButtonBox; private Tab transportationTab;
@FXML @FXML
private ComboBox<Locale> languageSelector; private Tab tunnelTab;
@FXML @FXML
private Tab buildingsTab; private Tab bridgeTab;
@FXML @FXML
private Tab vegetationTab; private Tab waterTab;
@FXML @FXML
private Tab transportationTab; private Tab terrainTab;
@FXML @FXML
private Tab bridgeTab; private Tab cityFurnitureTab;
@FXML @FXML
private Tab waterTab; private Tab otherObjectsTab;
@FXML @FXML
private Tab terrainTab; private Tab errorsTab;
@FXML @FXML
private Tab errorsTab; private Tab polygonsTab;
@FXML @FXML
private Tab polygonsTab; private Tab edgesTab;
@FXML @FXML
private Tab edgesTab; private Tab verticesTab;
@FXML @FXML
private Tab verticesTab; private Tab attributeTab;
@FXML @FXML
private Tab logTab; private Tab logTab;
@FXML @FXML
private Tab globalErrorsTab; private Tab globalErrorsTab;
@FXML @FXML
private Label viewLabel; private Label viewLabel;
@FXML @FXML
private Label showLabel; private Label showLabel;
@FXML @FXML
private Label searchLabel; private Label searchLabel;
@FXML @FXML
private Label memoryLabel; private Label memoryLabel;
@FXML @FXML
private ProgressBar memoryBar; private ProgressBar memoryBar;
@FXML @FXML
private Label memoryConsumptionLabel; private Label memoryConsumptionLabel;
@FXML @FXML
private Label availableLabel; private Label availableLabel;
private Group meshGroup; private Image north;
private Image northFlip;
private Group world; private Group meshGroup;
private PerspectiveCamera camera;
private Rotate cameraXRotation = new Rotate();
private Rotate cameraZRotation = new Rotate();
private double dragX; private Group world;
private double dragY; private PerspectiveCamera camera;
private Rotate cameraXRotation = new Rotate();
private Rotate cameraZRotation = new Rotate();
private double cameraXRot = CAMERA_INITIAL_X_ANGLE; private double dragX;
private double cameraYRot = CAMERA_INITIAL_Y_ANGLE; private double dragY;
private double translateZ = CAMERA_TRANSLATE_Z;
private double[] clickStart = new double[2];
@FXML private double cameraXRot = CAMERA_INITIAL_X_ANGLE;
private TextArea logArea; private double cameraYRot = CAMERA_INITIAL_Y_ANGLE;
private double translateZ = CAMERA_TRANSLATE_Z;
@FXML private double[] clickStart = new double[2];
private ToolBar viewBar;
@FXML
private Stage stage; private TextArea logArea;
private ExceptionDialog exceptionDialog;
@FXML
private Renderer renderer; private ToolBar viewBar;
private CityDoctorController controller;
private HighlightController highlightController; private Stage stage;
private ExceptionDialog exceptionDialog;
private FeatureType selectedTab = FeatureType.BUILDING;
private Renderer renderer;
private MainToolBar mainToolBar; private CityDoctorController controller;
private SubScene geomScene; private HighlightController highlightController;
private static boolean loadFileAtStartup = false; private FeatureType selectedTab = FeatureType.BUILDING;
private static String inputFile;
private static String xmlOutput; private MainToolBar mainToolBar;
private static String pdfOutput; private SubScene geomScene;
private static ValidationConfiguration config; private ImageView northArrow;
private VertexClickHandler clickHandler; private static boolean loadFileAtStartup = false;
private static String inputFile;
private ChangeListener<Number> filterChangeListener; private static String xmlOutput;
private static String pdfOutput;
public static void main(String[] args) { private static ValidationConfiguration config;
setLocaleFromSettings();
ArgumentParser argParser = new ArgumentParser(args); private VertexClickHandler clickHandler;
inputFile = CityDoctorValidation.getInputFile(argParser, true);
if (inputFile != null) { private ChangeListener<Number> filterChangeListener;
loadFileAtStartup = true;
xmlOutput = CityDoctorValidation.getXmlOutput(argParser); public static void main(String[] args) {
pdfOutput = CityDoctorValidation.getPdfOutput(argParser); setLocaleFromSettings();
try { ArgumentParser argParser = new ArgumentParser(args);
config = CityDoctorValidation.getValidationConfig(argParser, true); inputFile = CityDoctorValidation.getInputFile(argParser, true);
} catch (FileNotFoundException e) { if (inputFile != null) {
Platform.runLater(() -> { loadFileAtStartup = true;
List<String> configFiles = argParser.getValues("config"); xmlOutput = CityDoctorValidation.getXmlOutput(argParser);
Alert alert = new Alert(AlertType.ERROR); pdfOutput = CityDoctorValidation.getPdfOutput(argParser);
alert.setContentText(Localization.getText("MainWindow.missingConfig") + configFiles); try {
alert.showAndWait(); config = CityDoctorValidation.getValidationConfig(argParser, true);
}); } catch (FileNotFoundException e) {
System.exit(4); Platform.runLater(() -> {
} List<String> configFiles = argParser.getValues("config");
} Alert alert = new Alert(AlertType.ERROR);
Application.launch(args); alert.setContentText(Localization.getText("MainWindow.missingConfig") + configFiles);
} alert.showAndWait();
});
private static void setLocaleFromSettings() { System.exit(4);
String localeString = Settings.get(Settings.LANGUAGE); }
if (localeString != null) { }
try { Application.launch(args);
Locale loc = new Locale(localeString); }
Locale.setDefault(loc);
} catch (Exception e) { private static void setLocaleFromSettings() {
logger.warn("Could not set language to {}, using system language", localeString); String localeString = Settings.get(Settings.LANGUAGE);
} if (localeString != null) {
} try {
} Locale loc = new Locale(localeString);
Locale.setDefault(loc);
@Override } catch (Exception e) {
public void start(Stage stage) throws IOException { logger.warn("Could not set language to {}, using system language", localeString);
this.stage = stage; }
stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/citydoctor_logo.png"))); }
FXMLLoader loader = new FXMLLoader(MainWindow.class.getResource("MainWindow.fxml")); }
loader.setController(this);
BorderPane bp = loader.load(); @Override
highlightController = new HighlightController(world); public void start(Stage stage) throws IOException {
renderer = new Renderer(this, highlightController); this.stage = stage;
clickHandler = new VertexClickHandler(errorView, renderer, stage); stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/citydoctor_logo.png")));
controller = new CityDoctorController(this, highlightController, renderer); FXMLLoader loader = new FXMLLoader(MainWindow.class.getResource("MainWindow.fxml"));
mainToolBar = new MainToolBar(stage, controller, featurePane, renderer, this); loader.setController(this);
viewPane.getChildren().add(mainToolBar.getToolBar()); BorderPane bp = loader.load();
HBox.setHgrow(mainToolBar.getToolBar(), Priority.ALWAYS); highlightController = new HighlightController(world);
renderer = new Renderer(this, highlightController);
ValidationView valView = new ValidationView(this, controller); clickHandler = new VertexClickHandler(errorView, renderer, stage);
ViewRegistration.registerView(valView); controller = new CityDoctorController(this, highlightController, renderer);
setupViews(valView); mainToolBar = new MainToolBar(stage, controller, featurePane, renderer, this);
viewPane.getChildren().add(mainToolBar.getToolBar());
createLanguageSelector(); HBox.setHgrow(mainToolBar.getToolBar(), Priority.ALWAYS);
setLabelsInCorrectLanguage();
ValidationView valView = new ValidationView(this, controller);
Scene scene = new Scene(bp, 1280, 800); ViewRegistration.registerView(valView);
createDropTarget(scene, valView); setupViews(valView);
String version = Localization.getText(Localization.VERSION);
stage.setTitle("CityDoctor " + version); createLanguageSelector();
stage.setScene(scene); setLabelsInCorrectLanguage();
stage.show();
checkForStartupLoading(); Scene scene = new Scene(bp, 1280, 800);
createDropTarget(scene, valView);
memoryBar.setOnMouseClicked(me -> System.gc()); String version = Localization.getText(Localization.VERSION);
Timer timer = new Timer(true); stage.setTitle("CityDoctor " + version);
// check memory every second stage.setScene(scene);
TimerTask task = new TimerTask() { stage.show();
checkForStartupLoading();
Runtime runtime = Runtime.getRuntime();
memoryBar.setOnMouseClicked(me -> System.gc());
@Override Timer timer = new Timer(true);
public void run() { // check memory every second
long totalMemory = runtime.totalMemory(); TimerTask task = new TimerTask() {
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory; Runtime runtime = Runtime.getRuntime();
double percentage = usedMemory / (double) totalMemory;
if (totalMemory / 1024 / 1024 >= 1024) { @Override
// gb public void run() {
double totalMemoryGb = totalMemory / (1024d * 1024d * 1024d); long totalMemory = runtime.totalMemory();
double usedMemoryGb = usedMemory / (1024d * 1024d * 1024d); long freeMemory = runtime.freeMemory();
String memoryString = String.format("%.1f GB / %.1f GB", usedMemoryGb, totalMemoryGb); long usedMemory = totalMemory - freeMemory;
Platform.runLater(() -> { double percentage = usedMemory / (double) totalMemory;
memoryConsumptionLabel.setText(memoryString); if (totalMemory / 1024 / 1024 >= 1024) {
memoryBar.setProgress(percentage); // gb
}); double totalMemoryGb = totalMemory / (1024d * 1024d * 1024d);
} else if (totalMemory / 1024 >= 1024) { double usedMemoryGb = usedMemory / (1024d * 1024d * 1024d);
// mb String memoryString = String.format("%.1f GB / %.1f GB", usedMemoryGb, totalMemoryGb);
double totalMemoryMb = totalMemory / (1024d * 1024d); Platform.runLater(() -> {
double usedMemoryMb = usedMemory / (1024d * 1024d); memoryConsumptionLabel.setText(memoryString);
String memoryString = String.format("%.1f MB / %.1f MB", usedMemoryMb, totalMemoryMb); memoryBar.setProgress(percentage);
Platform.runLater(() -> { });
memoryConsumptionLabel.setText(memoryString); } else if (totalMemory / 1024 >= 1024) {
memoryBar.setProgress(percentage); // mb
}); double totalMemoryMb = totalMemory / (1024d * 1024d);
} double usedMemoryMb = usedMemory / (1024d * 1024d);
} String memoryString = String.format("%.1f MB / %.1f MB", usedMemoryMb, totalMemoryMb);
}; Platform.runLater(() -> {
timer.schedule(task, 0, 1000); memoryConsumptionLabel.setText(memoryString);
} memoryBar.setProgress(percentage);
});
private void createDropTarget(Scene scene, ValidationView valView) { }
setDragOverInteraction(scene, valView); }
scene.setOnDragDropped(event -> { };
if (ViewRegistration.getCurrentActiveView() != valView) { timer.schedule(task, 0, 1000);
return; }
}
Dragboard db = event.getDragboard(); private void createDropTarget(Scene scene, ValidationView valView) {
boolean success = false; setDragOverInteraction(scene, valView);
if (db.hasFiles() && db.getFiles().size() == 1) { scene.setOnDragDropped(event -> {
File f = db.getFiles().get(0); if (ViewRegistration.getCurrentActiveView() != valView) {
Thread t = new Thread(() -> { return;
try { }
controller.loadCityGml(f.getAbsolutePath(), 8, (ProgressListener) null, false); Dragboard db = event.getDragboard();
} catch (Exception e) { boolean success = false;
if (logger.isErrorEnabled()) { if (db.hasFiles() && db.getFiles().size() == 1) {
logger.error(Localization.getText("OpenFileDialog.loadFailed"), e); File f = db.getFiles().get(0);
} Thread t = new Thread(() -> {
Platform.runLater(() -> { try {
ExceptionDialog exDialog = new ExceptionDialog(); controller.loadCityGml(f.getAbsolutePath(), 8, (ProgressListener) null, false);
exDialog.show(e); } catch (Exception e) {
}); if (logger.isErrorEnabled()) {
} logger.error(Localization.getText("OpenFileDialog.loadFailed"), e);
}); }
t.start(); Platform.runLater(() -> {
success = true; ExceptionDialog exDialog = new ExceptionDialog();
} exDialog.show(e);
// let the source know whether the string was successfully transferred and used });
event.setDropCompleted(success); }
});
event.consume(); t.start();
}); success = true;
} }
// let the source know whether the string was successfully transferred and used
private void setDragOverInteraction(Scene scene, ValidationView valView) { event.setDropCompleted(success);
scene.setOnDragOver(event -> {
if (ViewRegistration.getCurrentActiveView() != valView) { event.consume();
return; });
} }
if (event.getGestureSource() != scene && event.getDragboard().hasFiles()
&& event.getDragboard().getFiles().size() == 1) { private void setDragOverInteraction(Scene scene, ValidationView valView) {
// allow for both copying and moving, whatever user chooses scene.setOnDragOver(event -> {
event.acceptTransferModes(TransferMode.LINK); if (ViewRegistration.getCurrentActiveView() != valView) {
} return;
event.consume(); }
}); if (event.getGestureSource() != scene && event.getDragboard().hasFiles()
} && event.getDragboard().getFiles().size() == 1) {
// allow for both copying and moving, whatever user chooses
private void setLabelsInCorrectLanguage() { event.acceptTransferModes(TransferMode.LINK);
buildingsTab.setText(Localization.getText("MainWindow.buildingsTab")); }
vegetationTab.setText(Localization.getText("MainWindow.vegetationTab")); event.consume();
transportationTab.setText(Localization.getText("MainWindow.transportationTab")); });
bridgeTab.setText(Localization.getText("MainWindow.bridgeTab")); }
waterTab.setText(Localization.getText("MainWindow.waterTab"));
terrainTab.setText(Localization.getText("MainWindow.terrainTab")); private void setLabelsInCorrectLanguage() {
viewLabel.setText(Localization.getText("MainWindow.viewLabel")); buildingsTab.setText(Localization.getText("MainWindow.buildingsTab"));
showLabel.setText(Localization.getText("MainWindow.showLabel")); vegetationTab.setText(Localization.getText("MainWindow.vegetationTab"));
searchLabel.setText(Localization.getText("MainWindow.searchLabel")); transportationTab.setText(Localization.getText("MainWindow.transportationTab"));
searchBtn.setText(Localization.getText("MainWindow.searchBtn")); tunnelTab.setText(Localization.getText("MainWindow.tunnelTab"));
clearBtn.setText(Localization.getText("MainWindow.clearBtn")); bridgeTab.setText(Localization.getText("MainWindow.bridgeTab"));
errorsTab.setText(Localization.getText("MainWindow.errorsTab")); waterTab.setText(Localization.getText("MainWindow.waterTab"));
polygonsTab.setText(Localization.getText("MainWindow.polygonsTab")); terrainTab.setText(Localization.getText("MainWindow.terrainTab"));
edgesTab.setText(Localization.getText("MainWindow.edgesTab")); cityFurnitureTab.setText(Localization.getText("MainWindow.cityfurnitureTab"));
verticesTab.setText(Localization.getText("MainWindow.verticesTab")); otherObjectsTab.setText(Localization.getText("MainWindow.otherObjectsTab"));
logTab.setText(Localization.getText("MainWindow.logTab")); viewLabel.setText(Localization.getText("MainWindow.viewLabel"));
globalErrorsTab.setText(Localization.getText("MainWindow.globalErrorsTab")); showLabel.setText(Localization.getText("MainWindow.showLabel"));
memoryLabel.setText(Localization.getText("MainWindow.memoryLabel")); searchLabel.setText(Localization.getText("MainWindow.searchLabel"));
availableLabel.setText(String.format("%s %.1f GB", Localization.getText("MainWindow.availableLabel"), searchBtn.setText(Localization.getText("MainWindow.searchBtn"));
Runtime.getRuntime().maxMemory() / 1024d / 1024d / 1024d)); clearBtn.setText(Localization.getText("MainWindow.clearBtn"));
} errorsTab.setText(Localization.getText("MainWindow.errorsTab"));
polygonsTab.setText(Localization.getText("MainWindow.polygonsTab"));
private void createLanguageSelector() { edgesTab.setText(Localization.getText("MainWindow.edgesTab"));
languageSelector.setButtonCell(new LanguageSelectorCell()); verticesTab.setText(Localization.getText("MainWindow.verticesTab"));
languageSelector.setCellFactory(view -> new LanguageSelectorCell()); attributeTab.setText(Localization.getText("MainWindow.attributeTab"));
languageSelector.getItems().add(Locale.GERMAN); logTab.setText(Localization.getText("MainWindow.logTab"));
languageSelector.getItems().add(Locale.ENGLISH); globalErrorsTab.setText(Localization.getText("MainWindow.globalErrorsTab"));
if (Locale.getDefault().getLanguage().equals(Locale.GERMAN.getLanguage())) { memoryLabel.setText(Localization.getText("MainWindow.memoryLabel"));
languageSelector.getSelectionModel().select(Locale.GERMAN); availableLabel.setText(String.format("%s %.1f GB", Localization.getText("MainWindow.availableLabel"),
} else if (Locale.getDefault().getLanguage().equals(Locale.ENGLISH.getLanguage())) { Runtime.getRuntime().maxMemory() / 1024d / 1024d / 1024d));
languageSelector.getSelectionModel().select(Locale.ENGLISH); }
} else {
languageSelector.getSelectionModel().select(Locale.ENGLISH); private void createLanguageSelector() {
Settings.set(Settings.LANGUAGE, Locale.ENGLISH.getLanguage()); languageSelector.setButtonCell(new LanguageSelectorCell());
} languageSelector.setCellFactory(view -> new LanguageSelectorCell());
languageSelector.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> { languageSelector.getItems().add(Locale.GERMAN);
Alert alert = new Alert(AlertType.CONFIRMATION, Localization.getText("MainWindow.languageChange"), languageSelector.getItems().add(Locale.ENGLISH);
ButtonType.OK); if (Locale.getDefault().getLanguage().equals(Locale.GERMAN.getLanguage())) {
alert.showAndWait(); languageSelector.getSelectionModel().select(Locale.GERMAN);
Settings.set(Settings.LANGUAGE, newV.getLanguage()); } else if (Locale.getDefault().getLanguage().equals(Locale.ENGLISH.getLanguage())) {
}); languageSelector.getSelectionModel().select(Locale.ENGLISH);
} } else {
languageSelector.getSelectionModel().select(Locale.ENGLISH);
private void checkForStartupLoading() { Settings.set(Settings.LANGUAGE, Locale.ENGLISH.getLanguage());
if (loadFileAtStartup) { }
logger.info(Localization.getText("MainWindow.loadGivenFile")); languageSelector.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> {
Thread t = new Thread(() -> { Alert alert = new Alert(AlertType.CONFIRMATION, Localization.getText("MainWindow.languageChange"),
try { ButtonType.OK);
// wait a bit for the gui to show alert.showAndWait();
Thread.sleep(500); Settings.set(Settings.LANGUAGE, newV.getLanguage());
} catch (InterruptedException e) { });
Thread.currentThread().interrupt(); }
}
try { private void checkForStartupLoading() {
controller.loadCityGml(inputFile, config.getNumberOfRoundingPlaces(), null, if (loadFileAtStartup) {
config.isXmlValidation()); logger.info(Localization.getText("MainWindow.loadGivenFile"));
logger.info(Localization.getText("MainWindow.finishedLoading")); Thread t = new Thread(() -> {
logger.info(Localization.getText("MainWindow.checking")); try {
controller.startChecks(config, null); // wait a bit for the gui to show
if (xmlOutput != null) { Thread.sleep(500);
logger.info(Localization.getText("MainWindow.writeXml")); } catch (InterruptedException e) {
controller.writeXmlReport(new File(xmlOutput)); Thread.currentThread().interrupt();
logger.info(Localization.getText("MainWindow.finishedXml")); }
} try {
if (pdfOutput != null) { controller.loadCityGml(inputFile, config.getNumberOfRoundingPlaces(), null,
logger.info(Localization.getText("MainWindow.writePdf")); config.isXmlValidation());
controller.writePdfReport(new File(pdfOutput)); logger.info(Localization.getText("MainWindow.finishedLoading"));
logger.info(Localization.getText("MainWindow.finishedPdf")); logger.info(Localization.getText("MainWindow.checking"));
} controller.startChecks(config, null);
} catch (CityGmlParseException | InvalidGmlFileException e) { if (xmlOutput != null) {
logger.error(Localization.getText("MainWindow.loadFailed"), e.getMessage()); logger.info(Localization.getText("MainWindow.writeXml"));
} controller.writeXmlReport(new File(xmlOutput));
}); logger.info(Localization.getText("MainWindow.finishedXml"));
t.start(); }
} if (pdfOutput != null) {
} logger.info(Localization.getText("MainWindow.writePdf"));
controller.writePdfReport(new File(pdfOutput));
private void setupViews(ValidationView valView) { logger.info(Localization.getText("MainWindow.finishedPdf"));
ToggleGroup group = new ToggleGroup(); }
for (View v : ViewRegistration.getRegisteredViews()) { } catch (CityGmlParseException | InvalidGmlFileException e) {
logger.error(Localization.getText("MainWindow.loadFailed"), e.getMessage());
RadioButton radioButton = new RadioButton(); }
radioButton.getStyleClass().remove("radio-button"); });
radioButton.getStyleClass().add("toggle-button"); t.start();
ImageView view = new ImageView(v.getViewLogo()); }
view.setFitHeight(32); }
view.setFitWidth(32);
radioButton.setGraphic(view); private void setupViews(ValidationView valView) {
group.getToggles().add(radioButton); ToggleGroup group = new ToggleGroup();
if (v == valView) { for (View v : ViewRegistration.getRegisteredViews()) {
ViewRegistration.setCurrentActiveView(valView);
group.selectToggle(radioButton); RadioButton radioButton = new RadioButton();
} radioButton.getStyleClass().remove("radio-button");
viewButtonBox.getChildren().add(radioButton); radioButton.getStyleClass().add("toggle-button");
radioButton.selectedProperty().addListener((obs, oldV, newV) -> { ImageView view = new ImageView(v.getViewLogo());
if (Boolean.TRUE.equals(newV)) { view.setFitHeight(32);
showView(v); view.setFitWidth(32);
ViewRegistration.setCurrentActiveView(v); radioButton.setGraphic(view);
} else { group.getToggles().add(radioButton);
v.onHide(); if (v == valView) {
} ViewRegistration.setCurrentActiveView(valView);
}); group.selectToggle(radioButton);
} }
} viewButtonBox.getChildren().add(radioButton);
radioButton.selectedProperty().addListener((obs, oldV, newV) -> {
private void showView(View v) { if (Boolean.TRUE.equals(newV)) {
viewPane.getChildren().clear(); showView(v);
controller.showView(v); ViewRegistration.setCurrentActiveView(v);
Optional<HBox> toolbar = v.getToolbar(); } else {
if (toolbar.isPresent()) { v.onHide();
viewPane.getChildren().add(toolbar.get()); }
HBox.setHgrow(toolbar.get(), Priority.ALWAYS); });
} else { }
HBox placeHolderToolbar = new HBox(); }
placeHolderToolbar.setMaxHeight(Double.MAX_VALUE);
viewPane.getChildren().add(placeHolderToolbar); private void showView(View v) {
HBox.setHgrow(placeHolderToolbar, Priority.ALWAYS); viewPane.getChildren().clear();
} controller.showView(v);
mainPane.setCenter(v.getMainScreen()); Optional<HBox> toolbar = v.getToolbar();
} if (toolbar.isPresent()) {
viewPane.getChildren().add(toolbar.get());
public void initialize() { HBox.setHgrow(toolbar.get(), Priority.ALWAYS);
GuiLogger.setTextArea(logArea); } else {
HBox placeHolderToolbar = new HBox();
loadFrameConfig(); placeHolderToolbar.setMaxHeight(Double.MAX_VALUE);
viewPane.getChildren().add(placeHolderToolbar);
setup3dView(); HBox.setHgrow(placeHolderToolbar, Priority.ALWAYS);
setupTrees(); }
mainPane.setCenter(v.getMainScreen());
setupSearchField(); }
setupSearchButtons();
public void initialize() {
setupShowCityComboBox(); GuiLogger.setTextArea(logArea);
detailsTabPane.getSelectionModel().selectedIndexProperty() loadFrameConfig();
.addListener((ov, oldI, newI) -> Platform.runLater(() -> {
if (newI.intValue() == 0 && errorView.getSelectionModel().getSelectedItem() != null) { setup3dView();
// the first tab is selected, meaning the error tab setupTrees();
// redisplay the selected error
errorView.getSelectionModel().getSelectedItem().getValue().visit(renderer); setupSearchField();
} setupSearchButtons();
}));
} setupShowCityComboBox();
private void setupShowCityComboBox() { detailsTabPane.getSelectionModel().selectedIndexProperty()
showCityObjectsCombo.getItems().addAll(Localization.getText("MainWindow.all"), .addListener((ov, oldI, newI) -> Platform.runLater(() -> {
Localization.getText("MainWindow.withErrors")); if (newI.intValue() == 0 && errorView.getSelectionModel().getSelectedItem() != null) {
showCityObjectsCombo.getSelectionModel().selectFirst(); // the first tab is selected, meaning the error tab
// redisplay the selected error
showCityObjectsCombo.setCellFactory(param -> new ListCell<>() { errorView.getSelectionModel().getSelectedItem().getValue().visit(renderer);
@Override }
public void updateItem(String item, boolean empty) { }));
super.updateItem(item, empty); }
if (item != null) {
setText(item); private void setupShowCityComboBox() {
if (item.contentEquals(Localization.getText("MainWindow.withErrors"))) { showCityObjectsCombo.getItems().addAll(Localization.getText("MainWindow.all"),
setTextFill(Color.RED); Localization.getText("MainWindow.withErrors"));
} showCityObjectsCombo.getSelectionModel().selectFirst();
} else {
setText(null); showCityObjectsCombo.setCellFactory(param -> new ListCell<>() {
} @Override
} public void updateItem(String item, boolean empty) {
}); super.updateItem(item, empty);
if (item != null) {
filterChangeListener = setupFilterSelectionListener(); setText(item);
showCityObjectsCombo.getSelectionModel().selectedIndexProperty().addListener(filterChangeListener); if (item.contentEquals(Localization.getText("MainWindow.withErrors"))) {
} setTextFill(Color.RED);
}
public void resetFilterComboBox() { } else {
showCityObjectsCombo.getSelectionModel().selectedIndexProperty().removeListener(filterChangeListener); setText(null);
showCityObjectsCombo.getSelectionModel().selectFirst(); }
showCityObjectsCombo.getSelectionModel().selectedIndexProperty().addListener(filterChangeListener); }
} });
private ChangeListener<Number> setupFilterSelectionListener() { filterChangeListener = setupFilterSelectionListener();
return (obs, oldV, newV) -> controller.errorFilterIndexChanged(newV); showCityObjectsCombo.getSelectionModel().selectedIndexProperty().addListener(filterChangeListener);
} }
private void setupSearchButtons() { public void resetFilterComboBox() {
searchBtn.setOnAction(ae -> controller.searchFeature(searchField.getText(), selectedTab)); showCityObjectsCombo.getSelectionModel().selectedIndexProperty().removeListener(filterChangeListener);
clearBtn.setOnAction(ae -> { showCityObjectsCombo.getSelectionModel().selectFirst();
if (searchField.getText().isEmpty()) { showCityObjectsCombo.getSelectionModel().selectedIndexProperty().addListener(filterChangeListener);
// do not reset search if nothing has bee searched }
return;
} private ChangeListener<Number> setupFilterSelectionListener() {
controller.resetSearch(selectedTab); return (obs, oldV, newV) -> controller.errorFilterIndexChanged(newV);
searchField.setText(""); }
});
} private void setupSearchButtons() {
searchBtn.setOnAction(ae -> controller.searchFeature(searchField.getText(), selectedTab));
private void setupSearchField() { clearBtn.setOnAction(ae -> {
searchField.textProperty().addListener((obs, oldV, newV) -> { if (searchField.getText().isEmpty()) {
if (newV.isEmpty()) { // do not reset search if nothing has bee searched
controller.resetSearch(selectedTab); return;
} }
}); controller.resetSearch(selectedTab);
featurePane.getSelectionModel().selectedIndexProperty().addListener((obs, oldV, newV) -> { searchField.setText("");
if (!searchField.getText().isEmpty()) { });
resetSearchBar(); }
controller.resetSearch(selectedTab);
} private void setupSearchField() {
int index = newV.intValue(); searchField.textProperty().addListener((obs, oldV, newV) -> {
switch (index) { if (newV.isEmpty()) {
case 0: controller.resetSearch(selectedTab);
selectedTab = FeatureType.BUILDING; }
break; });
case 1: featurePane.getSelectionModel().selectedIndexProperty().addListener((obs, oldV, newV) -> {
selectedTab = FeatureType.VEGETATION; if (!searchField.getText().isEmpty()) {
break; resetSearchBar();
case 2: controller.resetSearch(selectedTab);
selectedTab = FeatureType.TRANSPORTATION; }
break; int index = newV.intValue();
case 3: switch (index) {
selectedTab = FeatureType.BRIDGE; case 0:
break; selectedTab = FeatureType.BUILDING;
case 4: break;
selectedTab = FeatureType.WATER; case 1:
break; selectedTab = FeatureType.VEGETATION;
case 5: break;
selectedTab = FeatureType.LAND; case 2:
break; selectedTab = FeatureType.TRANSPORTATION;
default: break;
throw new IllegalStateException("Unknown tab index: " + index); case 3:
} selectedTab = FeatureType.TUNNEL;
}); break;
} case 4:
selectedTab = FeatureType.BRIDGE;
public void resetSearchBar() { break;
searchField.setText(""); case 5:
} selectedTab = FeatureType.WATER;
break;
private void loadFrameConfig() { case 6:
stage.setMaximized(Boolean.valueOf(Settings.get(Settings.MAXIMIZED, Boolean.FALSE.toString()))); selectedTab = FeatureType.LAND;
stage.maximizedProperty() break;
.addListener((obs, oldV, newV) -> Settings.set(Settings.MAXIMIZED, Boolean.toString(newV))); case 7:
selectedTab = FeatureType.CITY_FURNITURE;
String widthString = Settings.get(Settings.FRAME_WIDTH); break;
if (widthString != null) { case 8:
stage.setWidth(Double.parseDouble(widthString)); selectedTab = FeatureType.GENERIC_CITY_OBJECT;
} break;
stage.widthProperty().addListener( default:
(obs, oldV, newV) -> Settings.set(Settings.FRAME_WIDTH, Double.toString(newV.doubleValue()))); throw new IllegalStateException("Unknown tab index: " + index);
}
String heightString = Settings.get(Settings.FRAME_HEIGHT); });
if (heightString != null) { }
stage.setHeight(Double.parseDouble(heightString));
} public void setDisableOfFeatureTab(FeatureType featureType, boolean value) {
stage.heightProperty().addListener( switch (featureType) {
(obs, oldV, newV) -> Settings.set(Settings.FRAME_HEIGHT, Double.toString(newV.doubleValue()))); case BUILDING:
} buildingsTab.setDisable(value);
break;
public void showExceptionDialog(Throwable e) { case VEGETATION:
if (exceptionDialog == null) { vegetationTab.setDisable(value);
exceptionDialog = new ExceptionDialog(); break;
} case TRANSPORTATION:
exceptionDialog.show(e); transportationTab.setDisable(value);
} break;
case TUNNEL:
private void setupTrees() { tunnelTab.setDisable(value);
setupSelectListener(errorView); break;
errorView.setRoot(new TreeItem<>()); case BRIDGE:
errorView.setCellFactory(param -> new RenderableTreeCell()); bridgeTab.setDisable(value);
break;
buildingsView.setShowRoot(true); case WATER:
setupSelectListener(buildingsView); waterTab.setDisable(value);
buildingsView.setCellFactory(param -> new RenderableTreeCell()); break;
ContextMenu cMenu = new ContextMenu(); case LAND:
MenuItem mi = new MenuItem(Localization.getText("MainWindow.export")); terrainTab.setDisable(value);
mi.setOnAction(ea -> { break;
Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue(); case CITY_FURNITURE:
if (render instanceof BuildingNode node) { cityFurnitureTab.setDisable(value);
controller.export(node.getBuilding()); break;
} case GENERIC_CITY_OBJECT:
}); otherObjectsTab.setDisable(value);
cMenu.getItems().add(mi); break;
default:
MenuItem deleteMi = new MenuItem("Delete"); throw new IllegalArgumentException("Unknown feature type: " + featureType);
deleteMi.setOnAction(ae -> controller.delete(buildingsView.getSelectionModel().getSelectedItem()));
cMenu.getItems().add(deleteMi); }
}
buildingsView.setContextMenu(cMenu);
public void activateAllTabs() {
vegetationView.setShowRoot(true); buildingsTab.setDisable(false);
setupSelectListener(vegetationView); vegetationTab.setDisable(false);
vegetationView.setCellFactory(param -> new RenderableTreeCell()); transportationTab.setDisable(false);
tunnelTab.setDisable(false);
transView.setShowRoot(true); bridgeTab.setDisable(false);
setupSelectListener(transView); waterTab.setDisable(false);
transView.setCellFactory(param -> new RenderableTreeCell()); terrainTab.setDisable(false);
cityFurnitureTab.setDisable(false);
bridgeView.setShowRoot(true); otherObjectsTab.setDisable(false);
setupSelectListener(bridgeView);
bridgeView.setCellFactory(param -> new RenderableTreeCell()); }
waterView.setShowRoot(true); public void resetSearchBar() {
setupSelectListener(waterView); searchField.setText("");
waterView.setCellFactory(param -> new RenderableTreeCell()); }
terrainView.setShowRoot(true); private void loadFrameConfig() {
setupSelectListener(terrainView); stage.setMaximized(Boolean.valueOf(Settings.get(Settings.MAXIMIZED, Boolean.FALSE.toString())));
terrainView.setCellFactory(param -> new RenderableTreeCell()); stage.maximizedProperty()
.addListener((obs, oldV, newV) -> Settings.set(Settings.MAXIMIZED, Boolean.toString(newV)));
setupSelectListener(vertexView);
vertexView.setRoot(new TreeItem<>()); String widthString = Settings.get(Settings.FRAME_WIDTH);
vertexView.setCellFactory(param -> new RenderableTreeCell()); if (widthString != null) {
stage.setWidth(Double.parseDouble(widthString));
setupSelectListener(polygonView); }
polygonView.setRoot(new TreeItem<>()); stage.widthProperty().addListener(
polygonView.setCellFactory(param -> new RenderableTreeCell()); (obs, oldV, newV) -> Settings.set(Settings.FRAME_WIDTH, Double.toString(newV.doubleValue())));
setupSelectListener(edgeView); String heightString = Settings.get(Settings.FRAME_HEIGHT);
edgeView.setRoot(new TreeItem<>()); if (heightString != null) {
edgeView.setCellFactory(param -> new RenderableTreeCell()); stage.setHeight(Double.parseDouble(heightString));
} }
stage.heightProperty().addListener(
private void setupSelectListener(TreeView<Renderable> view) { (obs, oldV, newV) -> Settings.set(Settings.FRAME_HEIGHT, Double.toString(newV.doubleValue())));
view.getSelectionModel().selectedItemProperty().addListener((obs, oldI, newI) -> { }
if (newI != null) {
newI.getValue().visit(renderer); public void showExceptionDialog(Throwable e) {
} if (exceptionDialog == null) {
}); exceptionDialog = new ExceptionDialog();
} }
exceptionDialog.show(e);
private void setup3dView() { }
Group root = new Group();
geomScene = new SubScene(root, 500, 300, true, SceneAntialiasing.BALANCED); private void setupTrees() {
geomScene.heightProperty().bind(meshView.heightProperty()); setupSelectListener(errorView);
geomScene.widthProperty().bind(meshView.widthProperty()); errorView.setRoot(new TreeItem<>());
geomScene.setFill(Color.AZURE); errorView.setCellFactory(param -> new RenderableTreeCell());
meshView.getChildren().add(geomScene);
buildingsView.setShowRoot(true);
geomScene.addEventFilter(MouseEvent.MOUSE_PRESSED, me -> { setupSelectListener(buildingsView);
clickStart[0] = me.getScreenX(); buildingsView.setCellFactory(param -> new RenderableTreeCell());
clickStart[1] = me.getScreenY(); ContextMenu cMenu = new ContextMenu();
}); MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
mi.setOnAction(ea -> {
geomScene.addEventFilter(MouseEvent.MOUSE_RELEASED, me -> { Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue();
if (Math.abs(clickStart[0] - me.getScreenX()) > 3 || Math.abs(clickStart[1] - me.getScreenY()) > 3) { if (render instanceof BuildingNode node) {
// skip when mouse moved too much controller.export(node.getBuilding());
return; }
} });
Node node = me.getPickResult().getIntersectedNode(); cMenu.getItems().add(mi);
if (node != null) {
Object o = node.getUserData(); MenuItem deleteMi = new MenuItem("Delete");
if (o instanceof ClickDispatcher cd) { deleteMi.setOnAction(ae -> controller.delete(buildingsView.getSelectionModel().getSelectedItem()));
cd.click(me, clickHandler); cMenu.getItems().add(deleteMi);
}
} buildingsView.setContextMenu(cMenu);
});
vegetationView.setShowRoot(true);
world = new Group(); setupSelectListener(vegetationView);
root.getChildren().add(world); vegetationView.setCellFactory(param -> new RenderableTreeCell());
meshGroup = new Group(); vegetationView.setContextMenu(cMenu);
world.getChildren().add(meshGroup);
transView.setShowRoot(true);
AmbientLight al = new AmbientLight(Color.WHITE); setupSelectListener(transView);
root.getChildren().add(al); transView.setCellFactory(param -> new RenderableTreeCell());
buildCamera(); tunnelView.setShowRoot(true);
cameraXRotation.setAxis(Rotate.X_AXIS); setupSelectListener(tunnelView);
cameraZRotation.setAxis(Rotate.Z_AXIS); tunnelView.setCellFactory(param -> new RenderableTreeCell());
world.getTransforms().add(cameraXRotation);
world.getTransforms().add(cameraZRotation); bridgeView.setShowRoot(true);
root.getChildren().add(camera); setupSelectListener(bridgeView);
geomScene.setCamera(camera); bridgeView.setCellFactory(param -> new RenderableTreeCell());
setupMeshViewControls(); waterView.setShowRoot(true);
} setupSelectListener(waterView);
waterView.setCellFactory(param -> new RenderableTreeCell());
private void setupMeshViewControls() {
meshView.setOnMousePressed(me -> { terrainView.setShowRoot(true);
if (me.getButton() == MouseButton.PRIMARY) { setupSelectListener(terrainView);
dragX = me.getScreenX(); terrainView.setCellFactory(param -> new RenderableTreeCell());
dragY = me.getScreenY();
} cityFurnitureView.setShowRoot(true);
}); setupSelectListener(cityFurnitureView);
cityFurnitureView.setCellFactory(param -> new RenderableTreeCell());
meshView.setOnScroll(se -> {
if (se.getDeltaY() < 0) { otherObjectsView.setShowRoot(true);
translateZ += translateZ * 0.05; setupSelectListener(otherObjectsView);
} else { otherObjectsView.setCellFactory(param -> new RenderableTreeCell());
translateZ -= translateZ * 0.05;
} setupSelectListener(vertexView);
camera.setTranslateZ(translateZ); vertexView.setRoot(new TreeItem<>());
highlightController.changeScaling(translateZ); vertexView.setCellFactory(param -> new RenderableTreeCell());
});
setupSelectListener(polygonView);
meshView.setOnMouseDragged(me -> { polygonView.setRoot(new TreeItem<>());
if (me.getButton() == MouseButton.PRIMARY) { polygonView.setCellFactory(param -> new RenderableTreeCell());
double deltaX = me.getScreenX() - dragX;
double deltaY = me.getScreenY() - dragY; setupSelectListener(edgeView);
dragX = me.getScreenX(); edgeView.setRoot(new TreeItem<>());
dragY = me.getScreenY(); edgeView.setCellFactory(param -> new RenderableTreeCell());
cameraXRot += (deltaX / 3d) % 360; setupSelectListener(attributeView);
cameraYRot += (deltaY / 3d) % 360; attributeView.setRoot(new TreeItem<>());
attributeView.setCellFactory(param -> new RenderableTreeCell());
cameraZRotation.setAngle(cameraXRot); }
cameraXRotation.setAngle(cameraYRot);
} private void setupSelectListener(TreeView<Renderable> view) {
}); view.getSelectionModel().selectedItemProperty().addListener((obs, oldI, newI) -> {
} if (newI != null) {
newI.getValue().visit(renderer);
private void buildCamera() { }
camera = new PerspectiveCamera(true); });
camera.setNearClip(0.1); }
camera.setFarClip(10000d);
camera.setTranslateZ(translateZ); private void setup3dView() {
cameraZRotation.setAngle(cameraXRot); Group root = new Group();
cameraXRotation.setAngle(cameraYRot); geomScene = new SubScene(root, 500, 300, true, SceneAntialiasing.BALANCED);
} geomScene.heightProperty().bind(meshView.heightProperty());
geomScene.widthProperty().bind(meshView.widthProperty());
public void addFileNameToTitle(String fileName) { geomScene.setFill(Color.AZURE);
String version = Localization.getText(Localization.VERSION); meshView.getChildren().add(geomScene);
stage.setTitle("CityDoctor " + version + " - " + fileName);
} geomScene.addEventFilter(MouseEvent.MOUSE_PRESSED, me -> {
clickStart[0] = me.getScreenX();
public TreeView<Renderable> getBuildingsView() { clickStart[1] = me.getScreenY();
return buildingsView; });
}
geomScene.addEventFilter(MouseEvent.MOUSE_RELEASED, me -> {
public TreeView<Renderable> getVegetationView() { if (Math.abs(clickStart[0] - me.getScreenX()) > 3 || Math.abs(clickStart[1] - me.getScreenY()) > 3) {
return vegetationView; // skip when mouse moved too much
} return;
}
public TreeView<Renderable> getTransportationView() { Node node = me.getPickResult().getIntersectedNode();
return transView; if (node != null) {
} Object o = node.getUserData();
if (o instanceof ClickDispatcher cd) {
public TreeView<Renderable> getBridgeView() { cd.click(me, clickHandler);
return bridgeView; }
} }
});
public TreeView<Renderable> getWaterView() {
return waterView; world = new Group();
} root.getChildren().add(world);
meshGroup = new Group();
public TreeView<Renderable> getTerrainView() { world.getChildren().add(meshGroup);
return terrainView;
} north = new Image(getClass().getResourceAsStream("icons/north.png"), 50, 50, true, true);
northFlip = new Image(getClass().getResourceAsStream("icons/north_flip.png"), 50, 50, true, true);
public TreeView<Renderable> getPolygonsView() { northArrow = new ImageView(north);
return polygonView; northArrow.setFitHeight(50);
} northArrow.setFitWidth(50);
northArrow.setX(10);
public TreeView<Renderable> getEdgeView() { northArrow.setY(10);
return edgeView; meshView.getChildren().add(northArrow);
} northArrow.setVisible(false);
public TreeView<Renderable> getVertexView() { AmbientLight al = new AmbientLight(Color.WHITE);
return vertexView; root.getChildren().add(al);
} buildCamera();
cameraXRotation.setAxis(Rotate.X_AXIS);
public Button getCheckButton() { cameraZRotation.setAxis(Rotate.Z_AXIS);
return mainToolBar.getCheckButton(); world.getTransforms().add(cameraXRotation);
} world.getTransforms().add(cameraZRotation);
root.getChildren().add(camera);
public ToggleButton getGridButton() { geomScene.setCamera(camera);
return mainToolBar.getGridButton();
} setupMeshViewControls();
}
public Group getMeshGroup() {
return meshGroup; private void setupMeshViewControls() {
} meshView.setOnMousePressed(me -> {
if (me.getButton() == MouseButton.PRIMARY) {
public ToggleButton getCullingButton() { dragX = me.getScreenX();
return mainToolBar.getCullingButton(); dragY = me.getScreenY();
} }
if (me.getButton() == MouseButton.SECONDARY) {
public Button getWriteReportButton() { dragX = me.getScreenX();
return mainToolBar.getWriteReportButton(); dragY = me.getScreenY();
} }
});
public TreeView<Renderable> getErrorTree() {
return errorView; meshView.setOnScroll(se -> {
} if (se.getDeltaY() < 0) {
translateZ += translateZ * 0.05;
public Stage getMainStage() { } else {
return stage; translateZ -= translateZ * 0.05;
} }
camera.setTranslateZ(translateZ);
public void unselectEverything() { highlightController.changeScaling(translateZ);
buildingsView.getSelectionModel().clearSelection(); });
vegetationView.getSelectionModel().clearSelection();
transView.getSelectionModel().clearSelection(); meshView.setOnMouseDragged(me -> {
waterView.getSelectionModel().clearSelection(); if (me.getButton() == MouseButton.PRIMARY) {
terrainView.getSelectionModel().clearSelection(); double deltaX = me.getScreenX() - dragX;
bridgeView.getSelectionModel().clearSelection(); double deltaY = me.getScreenY() - dragY;
polygonView.getSelectionModel().clearSelection(); dragX = me.getScreenX();
edgeView.getSelectionModel().clearSelection(); dragY = me.getScreenY();
vertexView.getSelectionModel().clearSelection();
errorView.getSelectionModel().clearSelection(); cameraXRot += (deltaX / 3d) % 360;
} cameraYRot += (deltaY / 3d) % 360;
public ToggleButton getLod1Btn() { cameraZRotation.setAngle(cameraXRot);
return mainToolBar.getLod1Btn(); cameraXRotation.setAngle(cameraYRot);
} alignNorthArrow();
}
public ToggleButton getLod2Btn() { if (me.getButton() == MouseButton.SECONDARY) {
return mainToolBar.getLod2Btn(); double translationSpeed = Math.abs(camera.getTranslateZ()) / 1000;
} double deltaX = me.getScreenX() - dragX;
double deltaY = me.getScreenY() - dragY;
public ToggleButton getLod3Btn() { dragX = me.getScreenX();
return mainToolBar.getLod3Btn(); dragY = me.getScreenY();
}
camera.setTranslateX(camera.getTranslateX() - deltaX * translationSpeed);
public ToggleButton getLod4Btn() { camera.setTranslateY(camera.getTranslateY() - deltaY * translationSpeed);
return mainToolBar.getLod4Btn(); }
} });
}
public Button getWorldBtn() {
return mainToolBar.getWorldBtn(); private void buildCamera() {
} camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
public Button getSaveBtn() { camera.setFarClip(10000d);
return mainToolBar.getSaveBtn(); camera.setTranslateZ(translateZ);
} cameraZRotation.setAngle(cameraXRot);
cameraXRotation.setAngle(cameraYRot);
public SplitPane getMainContainer() { }
return mainContainer;
} public void alignNorthArrow() {
double absRotZ = cameraZRotation.getAngle() - 360 * Math.floor(cameraZRotation.getAngle() / 360);
public ListView<String> getGlobalErrorsView() { double absRotX = cameraXRotation.getAngle() - 360 * Math.floor(cameraXRotation.getAngle() / 360);
return globalErrorsView;
} double northRot;
if (80 <= absRotX && absRotX <= 260) {
public void takeViewScreenshot() throws IOException { northRot = 360 - absRotZ;
WritableImage snapshot = geomScene.snapshot(null, null); if (northArrow.getImage() != north) {
File outputFile = new File("img.png"); northArrow.setImage(north);
BufferedImage bImage = SwingFXUtils.fromFXImage(snapshot, null); }
ImageIO.write(bImage, "png", outputFile); } else {
} //Camera is below horizon line -> flip north arrow horizontally
northRot = (absRotZ + 180) % 360;
public void zoomOutForBoundingBox(BoundingBox b) { if (northArrow.getImage() != northFlip) {
double longestSide = b.getDiagonalLength() * 0.4; northArrow.setImage(northFlip);
double d = longestSide / Math.tan(Math.toRadians(30) / 2); }
translateZ = -d; }
camera.setTranslateZ(translateZ); northArrow.setRotate(northRot);
highlightController.changeScaling(-translateZ); }
}
public void resetCamera() {
public MainToolBar getMainToolbar() { cameraXRot = CAMERA_INITIAL_X_ANGLE;
return mainToolBar; cameraYRot = CAMERA_INITIAL_Y_ANGLE;
} cameraZRotation.setAngle(cameraXRot);
cameraXRotation.setAngle(cameraYRot);
public void clearHighlights() { alignNorthArrow();
highlightController.clearHighlights(); camera.setTranslateX(0);
} camera.setTranslateY(0);
if (controller.getOriginBB() != null) {
public CityDoctorController getController() { zoomOutForBoundingBox(controller.getOriginBB());
return controller; }
} }
public Button getOpenBtn() { public void addFileNameToTitle(String fileName) {
return mainToolBar.getOpenBtn(); String version = Localization.getText(Localization.VERSION);
} stage.setTitle("CityDoctor " + version + " - " + fileName);
}
public VertexClickHandler getClickHandler() {
return clickHandler; public TreeView<Renderable> getBuildingsView() {
} return buildingsView;
}
public FeatureType getSelectedTab() {
return selectedTab; public TreeView<Renderable> getVegetationView() {
} return vegetationView;
}
public TreeView<Renderable> getTransportationView() {
return transView;
}
public TreeView<Renderable> getTunnelView() {
return tunnelView;
}
public TreeView<Renderable> getBridgeView() {
return bridgeView;
}
public TreeView<Renderable> getWaterView() {
return waterView;
}
public TreeView<Renderable> getTerrainView() {
return terrainView;
}
public TreeView<Renderable> getCityFurnitureView() {
return cityFurnitureView;
}
public TreeView<Renderable> getAttributeView() {
return attributeView;
}
public TreeView<Renderable> getOtherObjectsView() {
return otherObjectsView;
}
public TreeView<Renderable> getPolygonsView() {
return polygonView;
}
public TreeView<Renderable> getEdgeView() {
return edgeView;
}
public TreeView<Renderable> getVertexView() {
return vertexView;
}
public Button getCheckButton() {
return mainToolBar.getCheckButton();
}
public ToggleButton getGridButton() {
return mainToolBar.getGridButton();
}
public Group getMeshGroup() {
return meshGroup;
}
public ToggleButton getCullingButton() {
return mainToolBar.getCullingButton();
}
public Button getWriteReportButton() {
return mainToolBar.getWriteReportButton();
}
public TreeView<Renderable> getErrorTree() {
return errorView;
}
public Stage getMainStage() {
return stage;
}
public void unselectEverything() {
buildingsView.getSelectionModel().clearSelection();
vegetationView.getSelectionModel().clearSelection();
transView.getSelectionModel().clearSelection();
tunnelView.getSelectionModel().clearSelection();
waterView.getSelectionModel().clearSelection();
terrainView.getSelectionModel().clearSelection();
cityFurnitureView.getSelectionModel().clearSelection();
otherObjectsView.getSelectionModel().clearSelection();
bridgeView.getSelectionModel().clearSelection();
polygonView.getSelectionModel().clearSelection();
edgeView.getSelectionModel().clearSelection();
vertexView.getSelectionModel().clearSelection();
attributeView.getSelectionModel().clearSelection();
errorView.getSelectionModel().clearSelection();
}
public ToggleButton getLod1Btn() {
return mainToolBar.getLod1Btn();
}
public ToggleButton getLod2Btn() {
return mainToolBar.getLod2Btn();
}
public ToggleButton getLod3Btn() {
return mainToolBar.getLod3Btn();
}
public ToggleButton getLod4Btn() {
return mainToolBar.getLod4Btn();
}
public Button getWorldBtn() {
return mainToolBar.getWorldBtn();
}
public Button getResetCameraBtn() {
return mainToolBar.getResetCameraBtn();
}
public ToggleButton getHideRoofBtn() {
return mainToolBar.getHideRoofBtn();
}
public ImageView getNorthArrow() {
return northArrow;
}
public Button getSaveBtn() {
return mainToolBar.getSaveBtn();
}
public SplitPane getMainContainer() {
return mainContainer;
}
public ListView<String> getGlobalErrorsView() {
return globalErrorsView;
}
public void takeViewScreenshot() throws IOException {
WritableImage snapshot = geomScene.snapshot(null, null);
File outputFile = new File("img.png");
BufferedImage bImage = SwingFXUtils.fromFXImage(snapshot, null);
ImageIO.write(bImage, "png", outputFile);
}
public void zoomOutForBoundingBox(BoundingBox b) {
double longestSide = b.getDiagonalLength() * 0.4;
double d = longestSide / Math.tan(Math.toRadians(30) / 2);
translateZ = -d;
camera.setTranslateZ(translateZ);
camera.setTranslateX(0);
camera.setTranslateY(0);
highlightController.changeScaling(-translateZ);
controller.setOriginBB(b);
}
public MainToolBar getMainToolbar() {
return mainToolBar;
}
public void clearHighlights() {
highlightController.clearHighlights();
}
public CityDoctorController getController() {
return controller;
}
public Button getOpenBtn() {
return mainToolBar.getOpenBtn();
}
public VertexClickHandler getClickHandler() {
return clickHandler;
}
public FeatureType getSelectedTab() {
return selectedTab;
}
} }
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checkable; import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding; import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject;
import de.hft.stuttgart.citydoctor2.datastructure.TinObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.gui.filter.ViewFilter; import de.hft.stuttgart.citydoctor2.gui.filter.ViewFilter;
import de.hft.stuttgart.citydoctor2.gui.tree.EdgeNode; import de.hft.stuttgart.citydoctor2.gui.tree.*;
import de.hft.stuttgart.citydoctor2.gui.tree.ErrorItemVisitor;
import de.hft.stuttgart.citydoctor2.gui.tree.ErrorNode;
import de.hft.stuttgart.citydoctor2.gui.tree.LinearRingNode;
import de.hft.stuttgart.citydoctor2.gui.tree.PolygonNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.VertexNode;
import de.hft.stuttgart.citydoctor2.math.Triangle3d; import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.CullFace; import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode; import javafx.scene.shape.DrawMode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.*;
public class Renderer { public class Renderer {
private static final Logger logger = LogManager.getLogger(Renderer.class); private static final Logger logger = LogManager.getLogger(Renderer.class);
private TriangulatedGeometry currentTriGeom; private TriangulatedGeometry currentTriGeom;
private Geometry currentGeometry; private Geometry currentGeometry;
private CullFace currentCulling = CullFace.BACK; private CullFace currentCulling = CullFace.NONE;
private DrawMode currentDrawMode = DrawMode.FILL; private DrawMode currentDrawMode = DrawMode.FILL;
private MainWindow mainWindow; private MainWindow mainWindow;
private HighlightController highlightController; private HighlightController highlightController;
private ListErrorVisitor errVisitor; private ListErrorVisitor errVisitor;
private LoadingInfoDialog loadingDialog; private LoadingInfoDialog loadingDialog;
private List<ViewFilter> lodFilters = new ArrayList<>(); private List<ViewFilter> lodFilters = new ArrayList<>();
private ViewFilter roofFilter;
private Runnable refresher; private Runnable refresher;
private Runnable errorUpdater; private Runnable errorUpdater;
public Renderer(MainWindow mainWindow, HighlightController highlightController) throws IOException { public Renderer(MainWindow mainWindow, HighlightController highlightController) throws IOException {
this.mainWindow = mainWindow; this.mainWindow = mainWindow;
this.highlightController = highlightController; this.highlightController = highlightController;
loadingDialog = new LoadingInfoDialog(mainWindow.getMainStage()); loadingDialog = new LoadingInfoDialog(mainWindow.getMainStage());
errVisitor = new ListErrorVisitor(highlightController); errVisitor = new ListErrorVisitor(highlightController);
setupLodFilters(); setupLodFilters();
} }
private void setupLodFilters() { private void setupLodFilters() {
lodFilters.add(new ViewFilter() { lodFilters.add(new ViewFilter() {
@Override @Override
public boolean useGeometry(CityObject co, Geometry geom) { public boolean useGeometry(CityObject co, Geometry geom) {
return geom.getLod() == Lod.LOD1; return geom.getLod() == Lod.LOD1;
} }
}); });
lodFilters.add(new ViewFilter() { lodFilters.add(new ViewFilter() {
@Override @Override
public boolean useGeometry(CityObject co, Geometry geom) { public boolean useGeometry(CityObject co, Geometry geom) {
return geom.getLod() == Lod.LOD2; return geom.getLod() == Lod.LOD2;
} }
}); });
lodFilters.add(new ViewFilter() { lodFilters.add(new ViewFilter() {
@Override @Override
public boolean useGeometry(CityObject co, Geometry geom) { public boolean useGeometry(CityObject co, Geometry geom) {
return geom.getLod() == Lod.LOD3; return geom.getLod() == Lod.LOD3;
} }
}); });
lodFilters.add(new ViewFilter() { lodFilters.add(new ViewFilter() {
@Override @Override
protected boolean useGeometry(CityObject co, Geometry geom) { protected boolean useGeometry(CityObject co, Geometry geom) {
return geom.getLod() == Lod.LOD0; return geom.getLod() == Lod.LOD0;
} }
}); });
lodFilters.add(new ViewFilter() { lodFilters.add(new ViewFilter() {
@Override @Override
public boolean useGeometry(CityObject co, Geometry geom) { public boolean useGeometry(CityObject co, Geometry geom) {
return geom.getLod() == Lod.LOD4; return geom.getLod() == Lod.LOD4;
} }
}); });
} roofFilter = new ViewFilter() {
@Override
public void enableLod1() { public boolean allowedToUse(CityObject co, Geometry geom) {
lodFilters.get(0).enable(); if (!this.isEnabled()) {
if (refresher != null) { return true;
refresher.run(); }
} return this.useGeometry(co, geom);
} }
public void disableLod1() { @Override
lodFilters.get(0).disable(); public boolean useGeometry(CityObject co, Geometry geom) {
if (refresher != null) { if (co instanceof BoundarySurface bs) {
refresher.run(); return bs.getType() != BoundarySurfaceType.ROOF;
} }
} return true;
}
public void enableLod2() {
lodFilters.get(1).enable(); };
if (refresher != null) { roofFilter.setEnable(false);
refresher.run(); }
}
} public void enableLod1() {
lodFilters.get(0).enable();
public void disableLod2() { if (refresher != null) {
lodFilters.get(1).disable(); refresher.run();
if (refresher != null) { }
refresher.run(); }
}
} public void disableLod1() {
lodFilters.get(0).disable();
public void enableLod3() { if (refresher != null) {
lodFilters.get(2).enable(); refresher.run();
if (refresher != null) { }
refresher.run(); }
}
} public void enableLod2() {
lodFilters.get(1).enable();
public void disableLod3() { if (refresher != null) {
lodFilters.get(2).disable(); refresher.run();
if (refresher != null) { }
refresher.run(); }
}
} public void disableLod2() {
lodFilters.get(1).disable();
public void enableLod4() { if (refresher != null) {
lodFilters.get(3).enable(); refresher.run();
if (refresher != null) { }
refresher.run(); }
}
} public void enableLod3() {
lodFilters.get(2).enable();
public void disableLod4() { if (refresher != null) {
lodFilters.get(3).disable(); refresher.run();
if (refresher != null) { }
refresher.run(); }
}
} public void disableLod3() {
lodFilters.get(2).disable();
public void render(Building building) { if (refresher != null) {
refresher = () -> { refresher.run();
Set<ConcretePolygon> setupBuildingPolygons = setupBuildingPolygons(building); }
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBuildingPolygons)); }
render(setupBuildingPolygons);
Platform.runLater(() -> { public void enableLod4() {
errorUpdater = () -> displayErrors(building); lodFilters.get(3).enable();
errorUpdater.run(); if (refresher != null) {
}); refresher.run();
}; }
refresher.run(); }
}
public void disableLod4() {
private Set<ConcretePolygon> setupBuildingPolygons(Building b) { lodFilters.get(3).disable();
Set<ConcretePolygon> polygons = new HashSet<>(); if (refresher != null) {
addPolygons(b, polygons); refresher.run();
for (BoundarySurface bs : b.getBoundarySurfaces()) { }
addPolygons(bs, polygons); }
for (Opening op : bs.getOpenings()) {
addPolygons(op, polygons); public void hideRoofs() {
} roofFilter.setEnable(true);
} if (refresher != null) {
for (Installation bi : b.getBuildingInstallations()) { refresher.run();
addPolygons(bi, polygons); }
for (BoundarySurface bs : bi.getBoundarySurfaces()) { }
addPolygons(bs, polygons);
for (Opening op : bs.getOpenings()) { public void showRoofs() {
addPolygons(op, polygons); roofFilter.setEnable(false);
} if (refresher != null) {
} refresher.run();
} }
for (BuildingPart bp : b.getBuildingParts()) { }
polygons.addAll(setupBuildingPartPolygons(bp));
} public void render(Building building) {
return polygons; refresher = () -> {
} Set<ConcretePolygon> setupBuildingPolygons = setupBuildingPolygons(building);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBuildingPolygons));
public void render(BuildingPart bp) { render(setupBuildingPolygons);
refresher = () -> { Platform.runLater(() -> {
Set<ConcretePolygon> setupBuildingPartPolygons = setupBuildingPartPolygons(bp); errorUpdater = () -> displayErrors(building);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBuildingPartPolygons)); errorUpdater.run();
render(setupBuildingPartPolygons); addGenericAttributesToView(building);
Platform.runLater(() -> { });
errorUpdater = () -> displayErrors(bp); };
errorUpdater.run(); refresher.run();
}); }
};
refresher.run(); private Set<ConcretePolygon> setupBuildingPolygons(Building b) {
} Set<ConcretePolygon> polygons = new HashSet<>();
addPolygons(b, polygons);
private Set<ConcretePolygon> setupBuildingPartPolygons(BuildingPart bp) { for (BoundarySurface bs : b.getBoundarySurfaces()) {
Set<ConcretePolygon> polygons = new HashSet<>(); addPolygons(bs, polygons);
addPolygons(bp, polygons); for (Opening op : bs.getOpenings()) {
for (BoundarySurface bs : bp.getBoundarySurfaces()) { addPolygons(op, polygons);
addPolygons(bs, polygons); }
for (Opening op : bs.getOpenings()) { }
addPolygons(op, polygons); for (Installation bi : b.getBuildingInstallations()) {
} addPolygons(bi, polygons);
} for (BoundarySurface bs : bi.getBoundarySurfaces()) {
for (Installation bi : bp.getBuildingInstallations()) { addPolygons(bs, polygons);
addPolygons(bi, polygons); for (Opening op : bs.getOpenings()) {
for (BoundarySurface bs : bi.getBoundarySurfaces()) { addPolygons(op, polygons);
addPolygons(bs, polygons); }
for (Opening op : bs.getOpenings()) { }
addPolygons(op, polygons); }
} for (BuildingRoom br : b.getBuildingRooms()) {
} addPolygons(br, polygons);
} for (BoundarySurface bs : br.getBoundarySurfaces()) {
return polygons; addPolygons(bs, polygons);
} }
}
public void render(BridgeObject bridge) { for (BuildingRoomFurniture brf : b.getBuildingRoomFurnitureList()) {
refresher = () -> { addPolygons(brf, polygons);
Set<ConcretePolygon> setupBridgePolygons = setupBridgePolygons(bridge); for (BoundarySurface bs : brf.getBoundarySurfaceList()) {
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBridgePolygons)); addPolygons(bs, polygons);
render(setupBridgePolygons); }
Platform.runLater(() -> { }
errorUpdater = () -> displayErrors(bridge); for (BuildingPart bp : b.getBuildingParts()) {
errorUpdater.run(); polygons.addAll(setupBuildingPartPolygons(bp));
}); }
}; return polygons;
refresher.run(); }
}
public void render(BuildingPart bp) {
private Set<ConcretePolygon> setupBridgePolygons(BridgeObject bridge) { refresher = () -> {
Set<ConcretePolygon> polygons = new HashSet<>(); Set<ConcretePolygon> setupBuildingPartPolygons = setupBuildingPartPolygons(bp);
addPolygons(bridge, polygons); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBuildingPartPolygons));
for (BoundarySurface bs : bridge.getBoundarySurfaces()) { render(setupBuildingPartPolygons);
addPolygons(bs, polygons); Platform.runLater(() -> {
} errorUpdater = () -> displayErrors(bp);
for (BridgeConstructiveElement consElement : bridge.getConstructiveElements()) { errorUpdater.run();
addPolygons(consElement, polygons); addGenericAttributesToView(bp);
for (BoundarySurface bs : consElement.getBoundarySurfaces()) { });
addPolygons(bs, polygons); };
} refresher.run();
} }
for (Installation inst : bridge.getBridgeInstallations()) {
addPolygons(inst, polygons); private Set<ConcretePolygon> setupBuildingPartPolygons(BuildingPart bp) {
for (BoundarySurface bs : inst.getBoundarySurfaces()) { Set<ConcretePolygon> polygons = new HashSet<>();
addPolygons(bs, polygons); addPolygons(bp, polygons);
} for (BoundarySurface bs : bp.getBoundarySurfaces()) {
} addPolygons(bs, polygons);
return polygons; for (Opening op : bs.getOpenings()) {
} addPolygons(op, polygons);
}
public void render(CityObject co) { }
refresher = () -> { for (Installation bi : bp.getBuildingInstallations()) {
Set<ConcretePolygon> setupCityObjectPolygons = setupCityObjectPolygons(co); addPolygons(bi, polygons);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons)); for (BoundarySurface bs : bi.getBoundarySurfaces()) {
render(setupCityObjectPolygons); addPolygons(bs, polygons);
Platform.runLater(() -> { for (Opening op : bs.getOpenings()) {
errorUpdater = () -> displayErrors(co); addPolygons(op, polygons);
errorUpdater.run(); }
}); }
}; }
refresher.run(); return polygons;
} }
public void render(ReliefObject relief) { public void render(AbstractRoom room) {
refresher = () -> { refresher = () -> {
Set<ConcretePolygon> setupCityObjectPolygons = setupReliefPolygons(relief); Set<ConcretePolygon> setupRoomPolygons = setupRoomPolygons(room);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons)); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupRoomPolygons));
render(setupCityObjectPolygons); render(setupRoomPolygons);
Platform.runLater(() -> { Platform.runLater(() -> {
errorUpdater = () -> displayErrors(relief); errorUpdater = () -> displayErrors(room);
errorUpdater.run(); errorUpdater.run();
}); addGenericAttributesToView(room);
}; });
refresher.run(); };
} refresher.run();
}
private Set<ConcretePolygon> setupReliefPolygons(ReliefObject relief) {
Set<ConcretePolygon> polygons = new HashSet<>(); private Set<ConcretePolygon> setupRoomPolygons(AbstractRoom room) {
addPolygons(relief, polygons); Set<ConcretePolygon> polygons = new HashSet<>();
for (TinObject tin : relief.getComponents()) { addPolygons(room, polygons);
addPolygons(tin, polygons); for (BoundarySurface bs : room.getBoundarySurfaces()) {
} addPolygons(bs, polygons);
return polygons; for (Opening op : bs.getOpenings()) {
} addPolygons(op, polygons);
}
public void render(Installation bi) { }
refresher = () -> { return polygons;
Set<ConcretePolygon> setupCityObjectPolygons = setupBuildingInstallationPolygons(bi); }
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons));
render(setupCityObjectPolygons); public void render(AbstractFurniture furniture) {
Platform.runLater(() -> { refresher = () -> {
errorUpdater = () -> displayErrors(bi); Set<ConcretePolygon> setupFurniturePolygons = setupFurniturePolygons(furniture);
errorUpdater.run(); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupFurniturePolygons));
}); render(setupFurniturePolygons);
}; Platform.runLater(() -> {
refresher.run(); errorUpdater = () -> displayErrors(furniture);
} errorUpdater.run();
addGenericAttributesToView(furniture);
private Set<ConcretePolygon> setupBuildingInstallationPolygons(Installation bi) { });
Set<ConcretePolygon> polygons = new HashSet<>(); };
addPolygons(bi, polygons); refresher.run();
for (BoundarySurface bs : bi.getBoundarySurfaces()) { }
addPolygons(bs, polygons);
for (Opening op : bs.getOpenings()) { private Set<ConcretePolygon> setupFurniturePolygons(AbstractFurniture furniture) {
addPolygons(op, polygons); Set<ConcretePolygon> polygons = new HashSet<>();
} addPolygons(furniture, polygons);
} for (BoundarySurface bs : furniture.getBoundarySurfaceList()) {
return polygons; addPolygons(bs, polygons);
} for (Opening op : bs.getOpenings()) {
addPolygons(op, polygons);
public void render(BoundarySurface bs) { }
refresher = () -> { }
Set<ConcretePolygon> setupBoundarySurfacePolygons = setupBoundarySurfacePolygons(bs); return polygons;
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBoundarySurfacePolygons)); }
render(setupBoundarySurfacePolygons);
Platform.runLater(() -> { public void render(Storey storey) {
errorUpdater = () -> displayErrors(bs); refresher = () -> {
errorUpdater.run(); Set<ConcretePolygon> setupStoreyPolygons = setupStoreyPolygons(storey);
}); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupStoreyPolygons));
}; render(setupStoreyPolygons);
refresher.run(); Platform.runLater(() -> {
} errorUpdater = () -> displayErrors(storey);
errorUpdater.run();
private Set<ConcretePolygon> setupBoundarySurfacePolygons(BoundarySurface bs) { addGenericAttributesToView(storey);
Set<ConcretePolygon> polygons = new HashSet<>(); });
addPolygons(bs, polygons); };
for (Opening op : bs.getOpenings()) { refresher.run();
addPolygons(op, polygons); }
}
return polygons; private Set<ConcretePolygon> setupStoreyPolygons(Storey storey) {
} Set<ConcretePolygon> polygons = new HashSet<>();
addPolygons(storey, polygons);
private Set<ConcretePolygon> setupCityObjectPolygons(CityObject co) { for (BoundarySurface bs : storey.getBoundarySurfaces()) {
Set<ConcretePolygon> polygons = new HashSet<>(); addPolygons(bs, polygons);
addPolygons(co, polygons); for (Opening op : bs.getOpenings()) {
return polygons; addPolygons(op, polygons);
} }
}
private void addPolygons(CityObject co, Set<ConcretePolygon> polygons) { return polygons;
for (Geometry geom : co.getGeometries()) { }
boolean used = false;
for (ViewFilter filter : lodFilters) { public void render(BuildingUnit buildingUnit) {
if (filter.allowedToUse(co, geom)) { refresher = () -> {
used = true; Set<ConcretePolygon> setupBuildingUnitPolgons = setupBuildingUnitPolygons(buildingUnit);
break; mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBuildingUnitPolgons));
} render(setupBuildingUnitPolgons);
} Platform.runLater(() -> {
if (used) { errorUpdater = () -> displayErrors(buildingUnit);
addConcretePolygons(polygons, geom); errorUpdater.run();
} addGenericAttributesToView(buildingUnit);
} });
} };
refresher.run();
private void displayErrors(Checkable c) { }
if (!c.isValidated()) {
return; private Set<ConcretePolygon> setupBuildingUnitPolygons(BuildingUnit buildingUnit) {
} Set<ConcretePolygon> polygons = new HashSet<>();
List<CheckError> errors = new ArrayList<>(); addPolygons(buildingUnit, polygons);
c.collectContainedErrors(errors); for (BoundarySurface bs : buildingUnit.getBoundarySurfaces()) {
addPolygons(bs, polygons);
// filter out duplicate errors (polygon can be contained in multiple geometries) for (Opening op : bs.getOpenings()) {
Set<CheckError> errorSet = new HashSet<>(errors); addPolygons(op, polygons);
for (CheckError err : errorSet) { }
ErrorNode node = new ErrorNode(err); }
TreeItem<Renderable> errItem = new TreeItem<>(node); return polygons;
ErrorItemVisitor visitor = new ErrorItemVisitor(errItem); }
err.accept(visitor);
mainWindow.getErrorTree().getRoot().getChildren().add(errItem); public void render(Tunnel tunnel) {
refresher = () -> {
} Set<ConcretePolygon> setupTunnelPolygons = setupTunnelPolygons(tunnel);
} mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupTunnelPolygons));
render(setupTunnelPolygons);
public void render(Geometry geom) { Platform.runLater(() -> {
refresher = () -> { errorUpdater = () -> displayErrors(tunnel);
Platform.runLater(this::clearGeometryTrees); errorUpdater.run();
currentTriGeom = TriangulatedGeometry.of(geom); addGenericAttributesToView(tunnel);
if (geom.getEdges() == null && currentGeometry != null) { });
// if there are no edges available low memory mode is enabled };
// clear the old geometry of all meta information refresher.run();
currentGeometry.clearMetaInformation(); }
}
errVisitor.setGeometry(currentTriGeom); private Set<ConcretePolygon> setupTunnelPolygons(Tunnel tunnel) {
Platform.runLater(() -> { Set<ConcretePolygon> polygons = new HashSet<>();
setupRenderState(); addPolygons(tunnel, polygons);
if (geom.getEdges() == null) { for (BoundarySurface bs : tunnel.getBoundarySurfaces()) {
// create edges and vertices so they can be listed in the gui addPolygons(bs, polygons);
geom.prepareForChecking(); }
// remember the geometry, so it can be cleared if another is displayed for (Installation ti : tunnel.getTunnelInstallations()) {
currentGeometry = geom; addPolygons(ti, polygons);
} for (BoundarySurface bs : ti.getBoundarySurfaces()) {
addGeometryDataToView(geom); addPolygons(bs, polygons);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(geom.getPolygons())); for (Opening op : bs.getOpenings()) {
errorUpdater = () -> displayErrors(geom); addPolygons(op, polygons);
errorUpdater.run(); }
}); }
}; }
refresher.run(); for (TunnelHollow th : tunnel.getTunnelHollows()) {
} addPolygons(th, polygons);
for (BoundarySurface bs : th.getBoundarySurfaces()) {
private void addGeometryDataToView(Geometry geom) { addPolygons(bs, polygons);
for (Polygon p : geom.getPolygons()) { }
addPolygonToView(p); }
} for (TunnelFurniture tf : tunnel.getTunnelFurnitureList()) {
for (Edge e : geom.getEdges()) { addPolygons(tf, polygons);
addEdgeToView(e); for (BoundarySurface bs : tf.getBoundarySurfaceList()) {
} addPolygons(bs, polygons);
for (Vertex v : geom.getVertices()) { }
addVertexToView(v); }
} for (TunnelPart tp : tunnel.getTunnelParts()) {
} polygons.addAll(setupTunnelPartPolygons(tp));
}
private void addVertexToView(Vertex v) { return polygons;
Renderable cf = new VertexNode(v); }
TreeItem<Renderable> ti = new TreeItem<>(cf);
mainWindow.getVertexView().getRoot().getChildren().add(ti); private Set<ConcretePolygon> setupTunnelPartPolygons(TunnelPart tp) {
} Set<ConcretePolygon> polygons = new HashSet<>();
addPolygons(tp, polygons);
private void addEdgeToView(Edge e) { for (BoundarySurface bs : tp.getBoundarySurfaces()) {
EdgeNode cf = new EdgeNode(e); addPolygons(bs, polygons);
TreeItem<Renderable> ti = new TreeItem<>(cf); for (Opening op : bs.getOpenings()) {
mainWindow.getEdgeView().getRoot().getChildren().add(ti); addPolygons(op, polygons);
} }
}
private void addPolygonToView(Polygon p) { for (Installation bi : tp.getTunnelInstallations()) {
CheckStatus cs = determineCheckStatus(p); addPolygons(bi, polygons);
PolygonNode cf = new PolygonNode(p, cs); for (BoundarySurface bs : bi.getBoundarySurfaces()) {
TreeItem<Renderable> ti = new TreeItem<>(cf); addPolygons(bs, polygons);
mainWindow.getPolygonsView().getRoot().getChildren().add(ti); for (Opening op : bs.getOpenings()) {
addPolygons(op, polygons);
// add linear rings }
CheckStatus csRing = determineCheckStatus(p.getExteriorRing()); }
Renderable ccRing = new LinearRingNode(p.getExteriorRing(), csRing); }
TreeItem<Renderable> tiRing = new TreeItem<>(ccRing); return polygons;
ti.getChildren().add(tiRing); }
for (Vertex v : p.getExteriorRing().getVertices()) { public void render(BridgeObject bridge) {
VertexNode vn = new VertexNode(v); refresher = () -> {
TreeItem<Renderable> tiV = new TreeItem<>(vn); Set<ConcretePolygon> setupBridgePolygons = setupBridgePolygons(bridge);
tiRing.getChildren().add(tiV); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBridgePolygons));
} render(setupBridgePolygons);
Platform.runLater(() -> {
for (LinearRing lr : p.getInnerRings()) { errorUpdater = () -> displayErrors(bridge);
CheckStatus csInteriorRing = determineCheckStatus(lr); errorUpdater.run();
Renderable ccInteriorRing = new LinearRingNode(lr, csInteriorRing); addGenericAttributesToView(bridge);
TreeItem<Renderable> tiInteriorRing = new TreeItem<>(ccInteriorRing); });
ti.getChildren().add(tiInteriorRing); };
for (Vertex v : lr.getVertices()) { refresher.run();
VertexNode vn = new VertexNode(v); }
TreeItem<Renderable> tiV = new TreeItem<>(vn);
tiRing.getChildren().add(tiV); private Set<ConcretePolygon> setupBridgePolygons(BridgeObject bridge) {
} Set<ConcretePolygon> polygons = new HashSet<>();
} addPolygons(bridge, polygons);
} for (BoundarySurface bs : bridge.getBoundarySurfaces()) {
addPolygons(bs, polygons);
private CheckStatus determineCheckStatus(Checkable c) { }
if (!c.isValidated()) { for (BridgeConstructiveElement consElement : bridge.getConstructiveElements()) {
return CheckStatus.NOT_CHECKED; addPolygons(consElement, polygons);
} for (BoundarySurface bs : consElement.getBoundarySurfaces()) {
if (c.containsAnyError()) { addPolygons(bs, polygons);
return CheckStatus.ERROR; }
} }
return CheckStatus.OK; for (Installation inst : bridge.getBridgeInstallations()) {
} addPolygons(inst, polygons);
for (BoundarySurface bs : inst.getBoundarySurfaces()) {
private void render(Collection<? extends Polygon> polygons) { addPolygons(bs, polygons);
Platform.runLater(this::clearGeometryTrees); }
currentTriGeom = TriangulatedGeometry.of(polygons); }
errVisitor.setGeometry(currentTriGeom); return polygons;
setupRenderState(); }
}
public void render(CityObject co) {
private void clearGeometryTrees() { refresher = () -> {
highlightController.clearHighlights(); Set<ConcretePolygon> setupCityObjectPolygons = setupCityObjectPolygons(co);
mainWindow.getErrorTree().getRoot().getChildren().clear(); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons));
mainWindow.getPolygonsView().getRoot().getChildren().clear(); render(setupCityObjectPolygons);
mainWindow.getEdgeView().getRoot().getChildren().clear(); Platform.runLater(() -> {
mainWindow.getVertexView().getRoot().getChildren().clear(); errorUpdater = () -> displayErrors(co);
} errorUpdater.run();
addGenericAttributesToView(co);
public void renderBuildings(List<Building> objects) { });
errorUpdater = null; };
refresher = () -> { refresher.run();
Platform.runLater(() -> { }
loadingDialog.show();
clearGeometryTrees(); public void render(ReliefObject relief) {
}); refresher = () -> {
Thread t = new Thread(() -> { Set<ConcretePolygon> setupCityObjectPolygons = setupReliefPolygons(relief);
Set<ConcretePolygon> polygons = new HashSet<>(); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons));
for (Building b : objects) { render(setupCityObjectPolygons);
collectPolygons(polygons, b); Platform.runLater(() -> {
for (BuildingPart bp : b.getBuildingParts()) { errorUpdater = () -> displayErrors(relief);
collectPolygons(polygons, bp); errorUpdater.run();
} addGenericAttributesToView(relief);
} });
currentTriGeom = TriangulatedGeometry.of(polygons); };
errVisitor.setGeometry(currentTriGeom); refresher.run();
Platform.runLater(() -> { }
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons)); private Set<ConcretePolygon> setupReliefPolygons(ReliefObject relief) {
loadingDialog.hide(); Set<ConcretePolygon> polygons = new HashSet<>();
}); addPolygons(relief, polygons);
}); for (TinObject tin : relief.getComponents()) {
t.setUncaughtExceptionHandler((thread, e) -> { addPolygons(tin, polygons);
Platform.runLater(() -> loadingDialog.hide()); }
logger.catching(e); return polygons;
}); }
t.start();
}; public void render(Installation bi) {
refresher.run(); refresher = () -> {
} Set<ConcretePolygon> setupCityObjectPolygons = setupBuildingInstallationPolygons(bi);
mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityObjectPolygons));
public void render(CityDoctorModel model) { render(setupCityObjectPolygons);
errorUpdater = null; Platform.runLater(() -> {
refresher = () -> { errorUpdater = () -> displayErrors(bi);
Platform.runLater(() -> { errorUpdater.run();
loadingDialog.show(); addGenericAttributesToView(bi);
clearGeometryTrees(); });
}); };
Thread t = new Thread(() -> { refresher.run();
currentTriGeom = TriangulatedGeometry.of(model, lodFilters); }
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> { private Set<ConcretePolygon> setupBuildingInstallationPolygons(Installation bi) {
setupRenderState(); Set<ConcretePolygon> polygons = new HashSet<>();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(model)); addPolygons(bi, polygons);
loadingDialog.hide(); for (BoundarySurface bs : bi.getBoundarySurfaces()) {
}); addPolygons(bs, polygons);
}); for (Opening op : bs.getOpenings()) {
t.setUncaughtExceptionHandler((thread, e) -> { addPolygons(op, polygons);
Platform.runLater(() -> loadingDialog.hide()); }
logger.catching(e); }
}); return polygons;
t.start(); }
};
refresher.run(); public void render(CityFurniture cf) {
} refresher = () -> {
Set<ConcretePolygon> setupCityFurniturePolygons = setupCityFurniturePolygons(cf);
public void renderVegetation(List<Vegetation> vegetation) { mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupCityFurniturePolygons));
renderCityObjects(vegetation, Color.LIGHTGREEN); render(setupCityFurniturePolygons);
} Platform.runLater(() -> {
errorUpdater = () -> displayErrors(cf);
public void renderTransportation(List<TransportationObject> transportation) { errorUpdater.run();
renderCityObjects(transportation, Color.YELLOW); addGenericAttributesToView(cf);
} });
};
public void renderBridges(List<BridgeObject> bridges) { refresher.run();
renderCityObjects(bridges, Color.CORAL); }
}
private Set<ConcretePolygon> setupCityFurniturePolygons(CityFurniture cf) {
public void renderWater(List<WaterObject> water) { Set<ConcretePolygon> polygons = new HashSet<>();
renderCityObjects(water, Color.LIGHTSKYBLUE); addPolygons(cf, polygons);
} return polygons;
}
public void renderTerrain(List<CityObject> land) {
renderLandObjects(land, Color.BROWN); public void render(GenericCityObject gco) {
} refresher = () -> {
Set<ConcretePolygon> setupGenericCityObjectPolygons = setupGenericCityObjectPolygons(gco);
private void renderLandObjects(List<CityObject> cos, Color baseColor) { mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupGenericCityObjectPolygons));
errorUpdater = null; render(setupGenericCityObjectPolygons);
refresher = () -> { Platform.runLater(() -> {
Platform.runLater(() -> { errorUpdater = () -> displayErrors(gco);
loadingDialog.show(); errorUpdater.run();
clearGeometryTrees(); addGenericAttributesToView(gco);
}); });
Thread t = new Thread(() -> { };
Set<ConcretePolygon> polygons = new HashSet<>(); refresher.run();
for (CityObject co : cos) { }
addPolygons(co, polygons);
if (co instanceof ReliefObject) { private Set<ConcretePolygon> setupGenericCityObjectPolygons(GenericCityObject gco) {
ReliefObject relief = (ReliefObject) co; Set<ConcretePolygon> polygons = new HashSet<>();
for (TinObject tin : relief.getComponents()) { addPolygons(gco, polygons);
addPolygons(tin, polygons); for (BoundarySurface bs : gco.getBoundarySurfaces()) {
} addPolygons(bs, polygons);
} for (Opening op : bs.getOpenings()) {
} addPolygons(op, polygons);
currentTriGeom = TriangulatedGeometry.of(polygons, baseColor); }
errVisitor.setGeometry(currentTriGeom); }
Platform.runLater(() -> { return polygons;
setupRenderState(); }
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide(); public void render(BoundarySurface bs) {
}); refresher = () -> {
}); Set<ConcretePolygon> setupBoundarySurfacePolygons = setupBoundarySurfacePolygons(bs);
t.setUncaughtExceptionHandler((thread, e) -> Platform.runLater(() -> loadingDialog.hide())); mainWindow.zoomOutForBoundingBox(BoundingBox.of(setupBoundarySurfacePolygons));
t.start(); render(setupBoundarySurfacePolygons);
}; Platform.runLater(() -> {
refresher.run(); errorUpdater = () -> displayErrors(bs);
} errorUpdater.run();
addGenericAttributesToView(bs);
public void renderCityObjects(List<? extends CityObject> cos, Color baseColor) { });
errorUpdater = null; };
refresher = () -> { refresher.run();
Platform.runLater(() -> { }
loadingDialog.show();
clearGeometryTrees(); private Set<ConcretePolygon> setupBoundarySurfacePolygons(BoundarySurface bs) {
}); Set<ConcretePolygon> polygons = new HashSet<>();
Thread t = new Thread(() -> { addPolygons(bs, polygons);
Set<ConcretePolygon> polygons = new HashSet<>(); for (Opening op : bs.getOpenings()) {
for (CityObject co : cos) { addPolygons(op, polygons);
addPolygons(co, polygons); }
} return polygons;
currentTriGeom = TriangulatedGeometry.of(polygons, baseColor); }
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> { private Set<ConcretePolygon> setupCityObjectPolygons(CityObject co) {
setupRenderState(); Set<ConcretePolygon> polygons = new HashSet<>();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons)); addPolygons(co, polygons);
loadingDialog.hide(); return polygons;
}); }
});
t.setUncaughtExceptionHandler((thread, e) -> Platform.runLater(() -> loadingDialog.hide())); private void addPolygons(CityObject co, Set<ConcretePolygon> polygons) {
t.start(); for (Geometry geom : co.getGeometries()) {
}; boolean used = false;
refresher.run(); for (ViewFilter filter : lodFilters) {
} if (filter.allowedToUse(co, geom)) {
used = true;
private void collectPolygons(Set<ConcretePolygon> polygons, AbstractBuilding ab) { break;
addPolygons(ab, polygons); }
for (Installation bi : ab.getBuildingInstallations()) { }
addPolygons(bi, polygons); if (used) {
for (BoundarySurface bs : bi.getBoundarySurfaces()) { if (roofFilter.allowedToUse(co, geom)) {
addPolygons(bs, polygons); addConcretePolygons(polygons, geom);
for (Opening o : bs.getOpenings()) { }
addPolygons(o, polygons); }
} }
} }
}
for (BoundarySurface bs : ab.getBoundarySurfaces()) { private void displayErrors(Checkable c) {
addPolygons(bs, polygons); if (!c.isValidated()) {
for (Opening o : bs.getOpenings()) { return;
addPolygons(o, polygons); }
} List<CheckError> errors = new ArrayList<>();
} c.collectContainedErrors(errors);
}
// filter out duplicate errors (polygon can be contained in multiple geometries)
private void addConcretePolygons(Set<ConcretePolygon> polygons, Geometry geom) { Set<CheckError> errorSet = new HashSet<>(errors);
for (Polygon p : geom.getPolygons()) { for (CheckError err : errorSet) {
polygons.add(p.getOriginal()); ErrorNode node = new ErrorNode(err);
} TreeItem<Renderable> errItem = new TreeItem<>(node);
} ErrorItemVisitor visitor = new ErrorItemVisitor(errItem);
err.accept(visitor);
private void setupRenderState() { mainWindow.getErrorTree().getRoot().getChildren().add(errItem);
currentTriGeom.setCullFace(currentCulling);
currentTriGeom.setDrawMode(currentDrawMode); }
Platform.runLater(() -> { }
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.getMeshGroup().getChildren().addAll(currentTriGeom.getMeshes()); public void render(Geometry geom) {
}); refresher = () -> {
mainWindow.getGridButton().setDisable(false); Platform.runLater(this::clearGeometryTrees);
mainWindow.getCullingButton().setDisable(false); currentTriGeom = TriangulatedGeometry.of(geom);
} if (geom.getEdges() == null && currentGeometry != null) {
// if there are no edges available low memory mode is enabled
public void showWireFrame(boolean show) { // clear the old geometry of all meta information
if (currentTriGeom != null) { currentGeometry.clearMetaInformation();
if (show) { }
currentDrawMode = DrawMode.LINE; errVisitor.setGeometry(currentTriGeom);
} else { Platform.runLater(() -> {
currentDrawMode = DrawMode.FILL; setupRenderState();
} if (geom.getEdges() == null) {
currentTriGeom.setDrawMode(currentDrawMode); // create edges and vertices so they can be listed in the gui
} geom.prepareForChecking();
} // remember the geometry, so it can be cleared if another is displayed
currentGeometry = geom;
public void enableCulling(boolean enable) { }
if (currentTriGeom != null) { addGeometryDataToView(geom);
if (enable) { addGenericAttributesToView(geom.getParent());
currentCulling = CullFace.BACK; mainWindow.zoomOutForBoundingBox(BoundingBox.of(geom.getPolygons()));
} else { errorUpdater = () -> displayErrors(geom);
currentCulling = CullFace.NONE; errorUpdater.run();
} });
currentTriGeom.setCullFace(currentCulling); };
} refresher.run();
} }
public void clearCurrentRender() { private void addGeometryDataToView(Geometry geom) {
// don't render anything for (Polygon p : geom.getPolygons()) {
Platform.runLater(() -> { addPolygonToView(p);
mainWindow.getMeshGroup().getChildren().clear(); }
clearGeometryTrees(); for (Edge e : geom.getEdges()) {
}); addEdgeToView(e);
} }
for (Vertex v : geom.getVertices()) {
public void highlight(Polygon p) { addVertexToView(v);
highlightController.highlight(p, currentTriGeom); }
} }
public void highlight(LinearRing lr) { private void addGenericAttributesToView(CityObject co) {
highlightController.highlight(lr, currentTriGeom); clearAttributes();
} for (GenericAttribute gen : co.getGenericAttributes()) {
addGenericAttributeToView(gen);
public void highlight(Edge e) { }
highlightController.highlight(e, currentTriGeom); }
}
private void addVertexToView(Vertex v) {
public void highlight(Vertex v) { Renderable cf = new VertexNode(v);
highlightController.highlight(v, currentTriGeom); TreeItem<Renderable> ti = new TreeItem<>(cf);
} mainWindow.getVertexView().getRoot().getChildren().add(ti);
}
public void highlight(List<LinearRing> highlightedRings) {
highlightController.highlight(highlightedRings, currentTriGeom); private void addEdgeToView(Edge e) {
} EdgeNode cf = new EdgeNode(e);
TreeItem<Renderable> ti = new TreeItem<>(cf);
public void highlightEdges(List<Edge> edges) { mainWindow.getEdgeView().getRoot().getChildren().add(ti);
highlightController.highlightEdges(edges, currentTriGeom); }
}
private void addPolygonToView(Polygon p) {
public void highlightPolygons(List<List<Polygon>> components) { CheckStatus cs = determineCheckStatus(p);
highlightController.highlightPolygons(components, currentTriGeom); PolygonNode cf = new PolygonNode(p, cs);
} TreeItem<Renderable> ti = new TreeItem<>(cf);
mainWindow.getPolygonsView().getRoot().getChildren().add(ti);
public void addHighlight(Vertex vertex, Color c) {
highlightController.addHighlight(vertex, currentTriGeom, c); // add linear rings
} CheckStatus csRing = determineCheckStatus(p.getExteriorRing());
Renderable ccRing = new LinearRingNode(p.getExteriorRing(), csRing);
public void highlight(CheckError err) { TreeItem<Renderable> tiRing = new TreeItem<>(ccRing);
err.accept(errVisitor); ti.getChildren().add(tiRing);
}
for (Vertex v : p.getExteriorRing().getVertices()) {
public void refresh() { VertexNode vn = new VertexNode(v);
if (refresher != null) { TreeItem<Renderable> tiV = new TreeItem<>(vn);
refresher.run(); tiRing.getChildren().add(tiV);
} }
}
for (LinearRing lr : p.getInnerRings()) {
public void updateErrors() { CheckStatus csInteriorRing = determineCheckStatus(lr);
if (errorUpdater != null) { Renderable ccInteriorRing = new LinearRingNode(lr, csInteriorRing);
errorUpdater.run(); TreeItem<Renderable> tiInteriorRing = new TreeItem<>(ccInteriorRing);
} ti.getChildren().add(tiInteriorRing);
} for (Vertex v : lr.getVertices()) {
VertexNode vn = new VertexNode(v);
public void clearHighlights() { TreeItem<Renderable> tiV = new TreeItem<>(vn);
highlightController.clearHighlights(); tiRing.getChildren().add(tiV);
} }
}
public void addHighlight(Polygon p) { }
highlightController.addHighlight(p, currentTriGeom);
} private void addGenericAttributeToView(GenericAttribute gen) {
GenericAttributeNode genNode = new GenericAttributeNode(gen);
public void addHighlight(Triangle3d t) { TreeItem<Renderable> ti = new TreeItem<>(genNode);
highlightController.highlight(t, currentTriGeom); mainWindow.getAttributeView().getRoot().getChildren().add(ti);
} }
public void reset() { private CheckStatus determineCheckStatus(Checkable c) {
errorUpdater = null; if (!c.isValidated()) {
refresher = null; return CheckStatus.NOT_CHECKED;
} }
if (c.containsAnyError()) {
return CheckStatus.ERROR;
}
return CheckStatus.OK;
}
private void render(Collection<? extends Polygon> polygons) {
Platform.runLater(this::clearGeometryTrees);
currentTriGeom = TriangulatedGeometry.of(polygons);
errVisitor.setGeometry(currentTriGeom);
setupRenderState();
}
private void clearGeometryTrees() {
highlightController.clearHighlights();
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getPolygonsView().getRoot().getChildren().clear();
mainWindow.getEdgeView().getRoot().getChildren().clear();
mainWindow.getVertexView().getRoot().getChildren().clear();
}
public void renderBuildings(List<Building> objects) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (Building b : objects) {
collectBuildingPolygons(polygons, b);
for (BuildingPart bp : b.getBuildingParts()) {
collectBuildingPolygons(polygons, bp);
}
}
currentTriGeom = TriangulatedGeometry.of(polygons);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> {
Platform.runLater(() -> loadingDialog.hide());
logger.catching(e);
});
t.start();
};
refresher.run();
}
public void render(CityDoctorModel model) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
currentTriGeom = TriangulatedGeometry.of(model, lodFilters);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(model));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> {
Platform.runLater(() -> loadingDialog.hide());
logger.catching(e);
});
t.start();
};
refresher.run();
}
public void renderVegetation(List<Vegetation> vegetation) {
renderCityObjects(vegetation, Color.LIGHTGREEN);
}
public void renderTransportation(List<TransportationObject> transportation) {
renderCityObjects(transportation, Color.YELLOW);
}
public void renderBridges(List<BridgeObject> bridges) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (BridgeObject b : bridges) {
collectBridgePolygons(polygons, b);
for (BridgeObject bp : b.getParts()) {
collectBridgePolygons(polygons, bp);
}
}
currentTriGeom = TriangulatedGeometry.of(polygons, Color.CORAL);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> {
Platform.runLater(() -> loadingDialog.hide());
logger.catching(e);
});
t.start();
};
refresher.run();
}
public void renderWater(List<WaterObject> water) {
renderCityObjects(water, Color.LIGHTSKYBLUE);
}
public void renderCityFurniture(List<CityFurniture> cityFurniture) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (CityFurniture cf : cityFurniture) {
collectCityFurniture(polygons, cf);
}
currentTriGeom = TriangulatedGeometry.of(polygons, Color.BLUEVIOLET);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> {
Platform.runLater(() -> loadingDialog.hide());
logger.catching(e);
});
t.start();
};
refresher.run();
}
public void renderTerrain(List<CityObject> land) {
renderLandObjects(land, Color.BROWN);
}
private void renderLandObjects(List<CityObject> cos, Color baseColor) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (CityObject co : cos) {
addPolygons(co, polygons);
if (co instanceof ReliefObject) {
ReliefObject relief = (ReliefObject) co;
for (TinObject tin : relief.getComponents()) {
addPolygons(tin, polygons);
}
}
}
currentTriGeom = TriangulatedGeometry.of(polygons, baseColor);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> Platform.runLater(() -> loadingDialog.hide()));
t.start();
};
refresher.run();
}
public void renderCityObjects(List<? extends CityObject> cos, Color baseColor) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (CityObject co : cos) {
addPolygons(co, polygons);
}
currentTriGeom = TriangulatedGeometry.of(polygons, baseColor);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> Platform.runLater(() -> loadingDialog.hide()));
t.start();
};
refresher.run();
}
public void renderTunnels(List<Tunnel> objects) {
errorUpdater = null;
refresher = () -> {
Platform.runLater(() -> {
loadingDialog.show();
clearGeometryTrees();
clearAttributes();
});
Thread t = new Thread(() -> {
Set<ConcretePolygon> polygons = new HashSet<>();
for (Tunnel tunnel : objects) {
collectTunnelPolygons(polygons, tunnel);
for (TunnelPart tp : tunnel.getTunnelParts()) {
collectTunnelPolygons(polygons, tp);
}
}
currentTriGeom = TriangulatedGeometry.of(polygons);
errVisitor.setGeometry(currentTriGeom);
Platform.runLater(() -> {
setupRenderState();
mainWindow.zoomOutForBoundingBox(BoundingBox.of(polygons));
loadingDialog.hide();
});
});
t.setUncaughtExceptionHandler((thread, e) -> {
Platform.runLater(() -> loadingDialog.hide());
logger.catching(e);
});
t.start();
};
refresher.run();
}
private void collectBuildingPolygons(Set<ConcretePolygon> polygons, AbstractBuilding ab) {
addPolygons(ab, polygons);
for (Installation bi : ab.getBuildingInstallations()) {
addPolygons(bi, polygons);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
for (BuildingRoom br : ab.getBuildingRooms()) {
addPolygons(br, polygons);
for (BoundarySurface bs : br.getBoundarySurfaces()) {
addPolygons(bs, polygons);
}
}
for (BoundarySurface bs : ab.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
private void collectBridgePolygons(Set<ConcretePolygon> polygons, BridgeObject br) {
addPolygons(br, polygons);
for (Installation bi : br.getBridgeInstallations()) {
addPolygons(bi, polygons);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
for (BridgeRoom r : br.getBridgeRooms()) {
addPolygons(r, polygons);
for (BoundarySurface bs : r.getBoundarySurfaces()) {
addPolygons(bs, polygons);
}
}
for (BridgeConstructiveElement bce : br.getConstructiveElements()) {
addPolygons(bce, polygons);
for (BoundarySurface bs : bce.getBoundarySurfaces()) {
addPolygons(bs, polygons);
}
}
for (BoundarySurface bs : br.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
public void collectTunnelPolygons(Set<ConcretePolygon> polygons, AbstractTunnel at) {
addPolygons(at, polygons);
for (Installation ti : at.getTunnelInstallations()) {
addPolygons(ti, polygons);
for (BoundarySurface bs : ti.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
for (TunnelHollow th : at.getTunnelHollows()) {
addPolygons(th, polygons);
for (BoundarySurface bs : th.getBoundarySurfaces()) {
addPolygons(bs, polygons);
}
}
for (TunnelConstructiveElement tce : at.getTunnelConstructiveElements()) {
addPolygons(tce, polygons);
for (BoundarySurface bs : tce.getBoundarySurfaces()) {
addPolygons(bs, polygons);
}
}
for (BoundarySurface bs : at.getBoundarySurfaces()) {
addPolygons(bs, polygons);
for (Opening o : bs.getOpenings()) {
addPolygons(o, polygons);
}
}
}
private void collectCityFurniture(Set<ConcretePolygon> polygons, CityFurniture cf) {
addPolygons(cf, polygons);
}
private void addConcretePolygons(Set<ConcretePolygon> polygons, Geometry geom) {
for (Polygon p : geom.getPolygons()) {
if (p.getOriginal().getPartOfSurface() != null &&
!roofFilter.allowedToUse(p.getOriginal().getPartOfSurface(), p.getParent())) continue;
polygons.add(p.getOriginal());
}
}
private void setupRenderState() {
currentTriGeom.setCullFace(currentCulling);
currentTriGeom.setDrawMode(currentDrawMode);
Platform.runLater(() -> {
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.getMeshGroup().getChildren().addAll(currentTriGeom.getMeshes());
});
mainWindow.getGridButton().setDisable(false);
mainWindow.getCullingButton().setDisable(false);
}
public void showWireFrame(boolean show) {
if (currentTriGeom != null) {
if (show) {
currentDrawMode = DrawMode.LINE;
} else {
currentDrawMode = DrawMode.FILL;
}
currentTriGeom.setDrawMode(currentDrawMode);
}
}
public void enableCulling(boolean enable) {
if (currentTriGeom != null) {
if (enable) {
currentCulling = CullFace.BACK;
} else {
currentCulling = CullFace.NONE;
}
currentTriGeom.setCullFace(currentCulling);
}
}
public void clearCurrentRender() {
// don't render anything
Platform.runLater(() -> {
mainWindow.getMeshGroup().getChildren().clear();
clearGeometryTrees();
clearAttributes();
});
}
private void clearAttributes() {
mainWindow.getAttributeView().getRoot().getChildren().clear();
}
public void highlight(Polygon p) {
highlightController.highlight(p, currentTriGeom);
}
public void highlight(LinearRing lr) {
highlightController.highlight(lr, currentTriGeom);
}
public void highlight(Edge e) {
highlightController.highlight(e, currentTriGeom);
}
public void highlight(Vertex v) {
highlightController.highlight(v, currentTriGeom);
}
public void highlight(List<LinearRing> highlightedRings) {
highlightController.highlight(highlightedRings, currentTriGeom);
}
public void highlightEdges(List<Edge> edges) {
highlightController.highlightEdges(edges, currentTriGeom);
}
public void highlightPolygons(List<List<Polygon>> components) {
highlightController.highlightPolygons(components, currentTriGeom);
}
public void addHighlight(Vertex vertex, Color c) {
highlightController.addHighlight(vertex, currentTriGeom, c);
}
public void highlight(CheckError err) {
err.accept(errVisitor);
}
public void refresh() {
if (refresher != null) {
refresher.run();
}
}
public void updateErrors() {
if (errorUpdater != null) {
errorUpdater.run();
}
}
public void clearHighlights() {
highlightController.clearHighlights();
}
public void addHighlight(Polygon p) {
highlightController.addHighlight(p, currentTriGeom);
}
public void addHighlight(Triangle3d t) {
highlightController.highlight(t, currentTriGeom);
}
public void reset() {
errorUpdater = null;
refresher = null;
}
} }
package de.hft.stuttgart.citydoctor2.gui; package de.hft.stuttgart.citydoctor2.gui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.OpeningType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.*;
import de.hft.stuttgart.citydoctor2.gui.filter.ViewFilter; import de.hft.stuttgart.citydoctor2.gui.filter.ViewFilter;
import de.hft.stuttgart.citydoctor2.math.Triangle3d; import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.UnitVector3d; import de.hft.stuttgart.citydoctor2.math.UnitVector3d;
...@@ -24,11 +9,9 @@ import de.hft.stuttgart.citydoctor2.math.Vector3d; ...@@ -24,11 +9,9 @@ import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial; import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace; import javafx.scene.shape.*;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView; import java.util.*;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.shape.VertexFormat;
public class TriangulatedGeometry { public class TriangulatedGeometry {
...@@ -105,11 +88,13 @@ public class TriangulatedGeometry { ...@@ -105,11 +88,13 @@ public class TriangulatedGeometry {
triGeom.movedBy = triGeom.findCenter(points); triGeom.movedBy = triGeom.findCenter(points);
addPolygonDataFromBuildings(model.getBuildings(), triGeom, filters); addPolygonDataFromBuildings(model.getBuildings(), triGeom, filters);
addPolygonDataFromCityObjects(model.getBridges(), triGeom, Color.CORAL, filters); addPolygonDataFromBridges(model.getBridges(), triGeom, filters);
addPolygonDataFromCityObjects(model.getLand(), triGeom, Color.BROWN, filters); addPolygonDataFromCityObjects(model.getLand(), triGeom, Color.BROWN, filters);
addPolygonDataFromCityObjects(model.getTransportation(), triGeom, Color.YELLOW, filters); addPolygonDataFromCityObjects(model.getTransportation(), triGeom, Color.YELLOW, filters);
addPolygonDataFromCityObjects(model.getVegetation(), triGeom, Color.LIGHTGREEN, filters); addPolygonDataFromCityObjects(model.getVegetation(), triGeom, Color.LIGHTGREEN, filters);
addPolygonDataFromCityObjects(model.getWater(), triGeom, Color.LIGHTSKYBLUE, filters); addPolygonDataFromCityObjects(model.getWater(), triGeom, Color.LIGHTSKYBLUE, filters);
addPolygonDataFromCityObjects(model.getCityFurniture(), triGeom, Color.BLUEVIOLET, filters);
addPolygonDataFromCityObjects(model.getGenericCityObjects(), triGeom, Color.DARKGRAY, filters);
return triGeom; return triGeom;
} }
...@@ -130,6 +115,23 @@ public class TriangulatedGeometry { ...@@ -130,6 +115,23 @@ public class TriangulatedGeometry {
} }
} }
private static void addPolygonDataFromBridges(List<BridgeObject> bridges, TriangulatedGeometry triGeom, List<ViewFilter> filters) {
for (BridgeObject b : bridges) {
addPolygonData(b, triGeom, Color.CORAL, filters);
addPolygonDataFromBoundarySurfaces(b.getBoundarySurfaces(), triGeom, filters);
addPolygonDataFromCityObjects(b.getBridgeInstallations(), triGeom, Color.CORAL, filters);
for (Installation bi : b.getBridgeInstallations()) {
addPolygonData(bi, triGeom, Color.CORAL, filters);
addPolygonDataFromCityObjects(bi.getBoundarySurfaces(), triGeom, Color.CORAL, filters);
}
for (BridgeConstructiveElement bce : b.getConstructiveElements()) {
addPolygonData(bce, triGeom, Color.CORAL, filters);
addPolygonDataFromCityObjects(bce.getBoundarySurfaces(), triGeom, Color.CORAL, filters);
}
addPolygonDataFromBridges(b.getParts(), triGeom, filters);
}
}
private static void addPolygonDataFromBoundarySurfaces(List<BoundarySurface> boundarySurfaces, private static void addPolygonDataFromBoundarySurfaces(List<BoundarySurface> boundarySurfaces,
TriangulatedGeometry triGeom, List<ViewFilter> filters) { TriangulatedGeometry triGeom, List<ViewFilter> filters) {
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
......
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingUnit;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer;
import java.util.List;
public class AllBuildingUnitsNode extends Renderable{
private final List<BuildingUnit> buildingUnits;
public AllBuildingUnitsNode(List<BuildingUnit> buildingUnits) {
this.buildingUnits = buildingUnits;
}
@Override
public String getText() {
return "Building Units";
}
@Override
public void visit(Renderer renderer) {
renderer.clearCurrentRender();
}
@Override
public void refreshTextColor() {
boolean wasChecked = false;
for (BuildingUnit buildingUnit : buildingUnits) {
if (buildingUnit.isValidated()) {
wasChecked = true;
if (buildingUnit.containsAnyError()) {
setStatus(CheckStatus.ERROR);
return;
}
}
}
if (wasChecked) {
setStatus(CheckStatus.OK);
} else {
setStatus(CheckStatus.NOT_CHECKED);
}
}
}
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.gui.Renderer;
import java.util.List;
public class AllCityFurnitureNode extends Renderable{
private final List<CityFurniture> cityFurnitures;
public AllCityFurnitureNode(List<CityFurniture> cityFurnitures) {
this.cityFurnitures = cityFurnitures;
}
@Override
public void refreshTextColor() {
// no color changes
}
@Override
public String getText() {
return "CityFurniture";
}
@Override
public void visit(Renderer renderer) {
renderer.clearCurrentRender();
renderer.renderCityFurniture(cityFurnitures);
}
}
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractFurniture;
import de.hft.stuttgart.citydoctor2.gui.CheckStatus;
import de.hft.stuttgart.citydoctor2.gui.Renderer;
import java.util.List;
public class AllFurnitureNode extends Renderable{
private final List<? extends AbstractFurniture> furniture;
public AllFurnitureNode(List<? extends AbstractFurniture> furniture) {
this.furniture = furniture;
}
@Override
public String getText() {
return "Furniture";
}
@Override
public void visit(Renderer renderer) {
renderer.clearCurrentRender();
}
@Override
public void refreshTextColor() {
boolean wasChecked = false;
for (AbstractFurniture af : furniture) {
if (af.isValidated()) {
wasChecked = true;
if (af.containsAnyError()) {
setStatus(CheckStatus.ERROR);
return;
}
}
}
if (wasChecked) {
setStatus(CheckStatus.OK);
} else {
setStatus(CheckStatus.NOT_CHECKED);
}
}
}
...@@ -16,13 +16,21 @@ public class AllOpeningsNode extends Renderable { ...@@ -16,13 +16,21 @@ public class AllOpeningsNode extends Renderable {
@Override @Override
public void refreshTextColor() { public void refreshTextColor() {
for (Opening bp : openings) { boolean wasChecked = false;
if (bp.containsAnyError()) { for (Opening op : openings) {
setStatus(CheckStatus.ERROR); if (op.isValidated()) {
return; wasChecked = true;
if (op.containsAnyError()) {
setStatus(CheckStatus.ERROR);
return;
}
} }
} }
setStatus(CheckStatus.OK); if (wasChecked) {
setStatus(CheckStatus.OK);
} else {
setStatus(CheckStatus.NOT_CHECKED);
}
} }
@Override @Override
......
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