Commit 28c42d2d authored by Luna Riegel's avatar Luna Riegel
Browse files

!Feature: Implement GeoDB and FeatureCache

BREAKING CHANGE: Implements the saving and loading of CityObjects to a
GeoDB with in-memory caching. This allows reading of bigger CityGml
files and serves as basis for the implementation of Topological Checks.

CityDoctorModel will now return Streams instead of Lists for the
CityObject-getters (like getBuildings()). This requires a rework of all
methods calling them.
parent 286d394c
Pipeline #11965 failed with stage
in 1 minute and 3 seconds
......@@ -52,7 +52,7 @@ public abstract class Checkable implements Serializable {
private final Map<CheckId, CheckResult> checkResults = new HashMap<>();
private boolean isValidated = false;
protected void setValidated(boolean validated) {
public void setValidated(boolean validated) {
isValidated = validated;
}
......
package de.hft.stuttgart.citydoctor2.database;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.utils.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.lang.ref.SoftReference;
import java.util.concurrent.ConcurrentHashMap;
/**
* Cache for CityObjects
*/
public class CityObjectCache {
private final LoadingCache<GmlId, CityObject> cache;
public CityObjectCache() {
cache = Caffeine.newBuilder().maximumSize(1000).build(DatabaseHandler::unmarshallCityObject);
}
public void put(CityObject cityObject) {
DatabaseHandler.marshallCityObject(cityObject);
cache.put(cityObject.getGmlId(), cityObject);
}
public CityObject get(GmlId id) {
return cache.get(id);
}
public List<CityObject> get(List<GmlId> ids) {
List<CityObject> features = new ArrayList<>();
for (GmlId id : ids) {
features.add(cache.get(id));
}
return features;
}
}
package de.hft.stuttgart.citydoctor2.database;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.utils.visitors.CityObjectCollector;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* Cache for CityObjects
*/
public class FeatureCache{
private final LoadingCache<GmlId, CityObject> cache;
private final Cache<GmlId, CityObject> subCache;
public FeatureCache() {
cache = Caffeine.newBuilder().maximumSize(3000).removalListener((GmlId key, CityObject value, RemovalCause cause) -> {
if (value != null && cause.wasEvicted()) {
DatabaseHandler.marshallCityObject(value);
}
}).build(DatabaseHandler::unmarshallCityObject);
subCache = Caffeine.newBuilder().maximumSize(250).build();
DatabaseHandler.setupDatabase();
}
public void put(CityObject cityObject) {
DatabaseHandler.marshallCityObject(cityObject);
cache.put(cityObject.getGmlId(), cityObject);
}
public CityObject get(GmlId id) {
return cache.get(id);
}
public void replace(GmlId id, CityObject cityObject) {
cache.invalidate(id);
put(cityObject);
}
public Stream<CityObject> getStream(List<GmlId> gmlIds) {
return gmlIds.stream().map(this::get);
}
/**
* Gets a non-top-level CityObject directly. Only use this in situations where directly accessing the object is required
* and access via the top-level CityObject is impossible or highly inefficient, e.g. rendering the associated object
* of a CityObjectNode.
* @param coa the adapter object of the subpart
* @return the associated CityObject
*/
public CityObject getSubPart(SubPartAdapter coa) {
CityObject co = subCache.getIfPresent(coa.getFeatureId());
if (co == null) {
return buildAndGetSubPart(coa);
}
else return co;
}
/**
*
* @param coa
* @return
*/
private CityObject buildAndGetSubPart(SubPartAdapter coa) {
CityObject parent = cache.get(coa.getTopLevelId());
if (parent == null) {
throw new IllegalStateException("CityObjectAdapter has non-existent parent - GmlId: " + coa.getTopLevelId());
}
CityObjectCollector collector = new CityObjectCollector();
parent.accept(collector);
collector.getCityObjects().forEach(cityObject -> subCache.put(cityObject.getGmlId(), cityObject));
CityObject co = subCache.getIfPresent(coa.getFeatureId());
if (co == null) {
throw new IllegalStateException("CityObjectAdapter has non-existent feature - GmlId: " + coa.getFeatureId() +
", parent GmlId: " + coa.getTopLevelId());
}
return co;
}
public List<CityObject> get(List<GmlId> ids) {
List<CityObject> features = new ArrayList<>();
for (GmlId id : ids) {
features.add(cache.get(id));
}
return features;
}
}
package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
/**
* Adapter class for Lists. All function calls on objects of this
* class get passed to their respective CityObjects.
*/
public class SubPartAdapter {
// TODO: Remove CO extension and change model to stream and map objects to their respective classes
private final GmlId featureId;
private final GmlId topLevelId;
private FeatureCache cache;
public SubPartAdapter(CityObject co, FeatureCache cache) {
this.featureId = co.getGmlId();
this.topLevelId = co.getTopLevelCityObject().getGmlId();
this.cache = cache;
}
public boolean isValidated(){
return cache.get(featureId).isValidated();
}
public GmlId getFeatureId() {
return featureId;
}
public GmlId getTopLevelId() {
return topLevelId;
}
}
package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
public class TopLevelCityObjectAdapter {
private final GmlId featureId;
private FeatureCache cache;
public TopLevelCityObjectAdapter(CityObject co, FeatureCache cache) {
this.featureId = co.getGmlId();
this.cache = cache;
}
public boolean isValidated(){
return cache.get(featureId).isValidated();
}
}
......@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.database.FeatureCache;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.writer.CityGMLWriterUtils;
......@@ -46,15 +47,15 @@ import java.util.stream.Stream;
public class CityDoctorModel {
private static final String COULD_NOT_FIND_FEATURE = "Could not find feature: ";
private final List<Building> buildings;
private final List<Vegetation> vegetation;
private final List<BridgeObject> bridges;
private final List<CityFurniture> cityfurniture;
private final List<GenericCityObject> genericObjects;
private final List<CityObject> land;
private final List<TransportationObject> roads;
private final List<Tunnel> tunnels;
private final List<WaterObject> water;
private final List<GmlId> buildings;
private final List<GmlId> vegetation;
private final List<GmlId> bridges;
private final List<GmlId> cityfurniture;
private final List<GmlId> genericObjects;
private final List<GmlId> land;
private final List<GmlId> roads;
private final List<GmlId> tunnels;
private final List<GmlId> water;
private CityModel cModel;
private final ParserConfiguration config;
private final String fileName;
......@@ -63,6 +64,7 @@ public class CityDoctorModel {
private boolean isValidated = false;
private ValidationPlan plan;
private CityGMLVersion cityGMLVersion;
private final FeatureCache cache;
public CityDoctorModel(ParserConfiguration config, File file) {
if (config == null) {
......@@ -81,6 +83,7 @@ public class CityDoctorModel {
cityfurniture = new ArrayList<>();
genericObjects = new ArrayList<>();
globalErrors = new ArrayList<>();
cache = new FeatureCache();
}
public boolean isValidated() {
......@@ -118,20 +121,12 @@ public class CityDoctorModel {
}
public Stream<CityObject> createFeatureStream() {
return Stream.of(buildings.stream(), vegetation.stream(), bridges.stream(), land.stream(), roads.stream(),
tunnels.stream(), water.stream(), cityfurniture.stream(), genericObjects.stream()).flatMap(co -> co);
return Stream.of(getBuildings(), getVegetation(), getBridges(), getLand(), getTransportation(),
getTunnels(), getWater(), getCityFurniture(), getGenericCityObjects()).flatMap(co -> co);
}
public void accept(CheckableVisitor visitor) {
buildings.forEach(co -> co.accept(visitor));
vegetation.forEach(co -> co.accept(visitor));
bridges.forEach(co -> co.accept(visitor));
land.forEach(co -> co.accept(visitor));
roads.forEach(co -> co.accept(visitor));
tunnels.forEach(co -> co.accept(visitor));
water.forEach(co -> co.accept(visitor));
cityfurniture.forEach(co -> co.accept(visitor));
genericObjects.forEach(co -> co.accept(visitor));
createFeatureStream().forEach(cityObject -> cityObject.accept(visitor));
}
public void saveAs(String file, boolean saveQualityAde) throws CityDoctorWriteException {
......@@ -228,106 +223,153 @@ public class CityDoctorModel {
public Set<CheckError> collectErrors() {
List<CheckError> errors = new ArrayList<>();
collectErrorsFromList(errors, buildings);
collectErrorsFromList(errors, vegetation);
collectErrorsFromList(errors, bridges);
collectErrorsFromList(errors, land);
collectErrorsFromList(errors, roads);
collectErrorsFromList(errors, tunnels);
collectErrorsFromList(errors, water);
collectErrorsFromList(errors, cityfurniture);
collectErrorsFromList(errors, genericObjects);
createFeatureStream().forEach(cityObject -> cityObject.collectErrors(errors));
return new HashSet<>(errors);
}
private void collectErrorsFromList(List<CheckError> errors, List<? extends CityObject> cos) {
for (CityObject co : cos) {
co.collectContainedErrors(errors);
}
}
public String getFileName() {
return fileName;
}
public void addBridge(BridgeObject coBridge) {
bridges.add(coBridge);
}
public void addBuilding(Building coBuilding) {
buildings.add(coBuilding);
buildings.add(coBuilding.getGmlId());
cache.put(coBuilding);
}
public List<Building> getBuildings() {
return buildings;
public Stream<Building> getBuildings() {
return buildings.stream().map(co -> (Building) cache.get(co));
}
public List<BridgeObject> getBridges() {
return bridges;
public int getBuildingCount(){
return buildings.size();
}
public void addBridge(BridgeObject coBridge) {
bridges.add(coBridge.getGmlId());
cache.put(coBridge);
}
public List<CityFurniture> getCityFurniture() {
return cityfurniture;
public Stream<BridgeObject> getBridges() {
return bridges.stream().map(co -> (BridgeObject) cache.get(co));
}
public int getBridgeCount(){
return bridges.size();
}
public void addCityFurniture(CityFurniture coFurniture) {
cityfurniture.add(coFurniture);
cityfurniture.add(coFurniture.getGmlId());
cache.put(coFurniture);
}
public Stream<CityFurniture> getCityFurniture() {
return cityfurniture.stream().map(co -> (CityFurniture) cache.get(co));
}
public List<GenericCityObject> getGenericCityObjects() {
return genericObjects;
public int getCityFurnitureCount(){
return cityfurniture.size();
}
public void addGenericCityObject(GenericCityObject coGenericCityObject) {
genericObjects.add(coGenericCityObject);
genericObjects.add(coGenericCityObject.getGmlId());
cache.put(coGenericCityObject);
}
public void setCityModel(CityModel cModel) {
this.cModel = cModel;
public Stream<GenericCityObject> getGenericCityObjects() {
return genericObjects.stream().map(co -> (GenericCityObject) cache.get(co));
}
public CityModel getCityModel() {
return cModel;
public int getGenericCityObjectCount(){
return genericObjects.size();
}
public void addTransportation(TransportationObject to) {
roads.add(to.getGmlId());
cache.put(to);
}
public List<TransportationObject> getTransportation() {
return roads;
public Stream<TransportationObject> getTransportation() {
return roads.stream().map(co -> (TransportationObject) cache.get(co));
}
public List<Tunnel> getTunnels() {
return tunnels;
public int getTransportationCount(){
return roads.size();
}
public List<WaterObject> getWater() {
return water;
public void addTunnel(Tunnel tunnel) {
tunnels.add(tunnel.getGmlId());
cache.put(tunnel);
}
public List<CityObject> getLand() {
return land;
public Stream<Tunnel> getTunnels() {
return tunnels.stream().map(co -> (Tunnel) cache.get(co));
}
public List<Vegetation> getVegetation() {
return vegetation;
public int getTunnelCount(){
return tunnels.size();
}
public void addWater(WaterObject wo) {
water.add(wo);
water.add(wo.getGmlId());
cache.put(wo);
}
public Stream<WaterObject> getWater() {
return water.stream().map(co -> (WaterObject) cache.get(co));
}
public int getWaterCount(){
return water.size();
}
public void addLand(LandObject lo) {
land.add(lo);
land.add(lo.getGmlId());
cache.put(lo);
}
public void addRelief(ReliefObject relief) {
land.add(relief.getGmlId());
cache.put(relief);
}
public void addTin(TinObject tin) {
land.add(tin.getGmlId());
cache.put(tin);
}
public Stream<CityObject> getLand() {
return land.stream().map(cache::get);
}
public int getLandCount(){
return land.size();
}
public void addVegetation(Vegetation veg) {
vegetation.add(veg);
vegetation.add(veg.getGmlId());
cache.put(veg);
}
public void addTransportation(TransportationObject to) {
roads.add(to);
public Stream<Vegetation> getVegetation() {
return vegetation.stream().map(co -> (Vegetation) cache.get(co));
}
public void addTunnel(Tunnel tunnel) {
tunnels.add(tunnel);
public int getVegetationCount(){
return vegetation.size();
}
public void setCityModel(CityModel cModel) {
this.cModel = cModel;
}
public CityModel getCityModel() {
return cModel;
}
public FeatureCache getCache(){
return cache;
}
public int getNumberOfFeatures() {
......@@ -362,100 +404,105 @@ public class CityDoctorModel {
}
private void replaceWaterObject(CityObject currentFeature, CityObject nextFeature) {
int index = water.indexOf(currentFeature);
int index = water.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in water objects");
}
water.set(index, (WaterObject) nextFeature);
cache.replace(currentFeature.getGmlId(), nextFeature);
water.set(index, nextFeature.getGmlId());
}
private void replaceLandObject(CityObject currentFeature, CityObject nextFeature) {
int index = land.indexOf(currentFeature);
int index = land.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in land objects");
}
land.set(index, nextFeature);
cache.replace(currentFeature.getGmlId(), nextFeature);
land.set(index, nextFeature.getGmlId());
}
private void replaceVegetation(CityObject currentFeature, CityObject nextFeature) {
int index = vegetation.indexOf(currentFeature);
int index = vegetation.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation");
}
vegetation.set(index, (Vegetation) nextFeature);
cache.replace(currentFeature.getGmlId(), nextFeature);
vegetation.set(index, nextFeature.getGmlId());
}
private void replaceCityFurniture(CityObject currentFeature, CityObject nextFeature) {
int index = cityfurniture.indexOf(currentFeature);
int index = cityfurniture.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation");
}
cityfurniture.set(index, (CityFurniture) nextFeature);
cache.replace(currentFeature.getGmlId(), nextFeature);
cityfurniture.set(index, nextFeature.getGmlId());
}
private void replaceGenericCityObject(CityObject currentFeature, CityObject nextFeature) {
int index = genericObjects.indexOf(currentFeature);
int index = genericObjects.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in generic city objects");
}
genericObjects.set(index, (GenericCityObject) nextFeature);
cache.replace(currentFeature.getGmlId(), nextFeature);
genericObjects.set(index, nextFeature.getGmlId());
}
private void replaceTransportationObject(CityObject currentFeature, CityObject nextFeature) {
int index = roads.indexOf(currentFeature);
int index = roads.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in transportation objects");
}
roads.set(index, (TransportationObject) nextFeature);
roads.set(index, nextFeature.getGmlId());
}
private void replaceTunnel(CityObject currentFeature, CityObject nextFeature) {
int index = tunnels.indexOf(currentFeature);
int index = tunnels.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in tunnels");
}
tunnels.set(index, (Tunnel) nextFeature);
tunnels.set(index, nextFeature.getGmlId());
}
private void replaceBridge(CityObject currentFeature, CityObject nextFeature) {
int index = bridges.indexOf(currentFeature);
int index = bridges.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in bridges");
}
bridges.set(index, (BridgeObject) nextFeature);
bridges.set(index, nextFeature.getGmlId());
}
private void replaceBuilding(CityObject currentFeature, CityObject nextFeature) {
int index = buildings.indexOf(currentFeature);
int index = buildings.indexOf(currentFeature.getGmlId());
if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in buildings");
}
buildings.set(index, (Building) nextFeature);
buildings.set(index, nextFeature.getGmlId());
}
public void addCityObject(CityObject co) {
if (co instanceof Building b) {
buildings.add(b);
buildings.add(b.getGmlId());
} else if (co instanceof BridgeObject bo) {
bridges.add(bo);
bridges.add(bo.getGmlId());
} else if (co instanceof TransportationObject to) {
roads.add(to);
roads.add(to.getGmlId());
} else if (co instanceof Tunnel tu) {
tunnels.add(tu);
tunnels.add(tu.getGmlId());
} else if (co instanceof Vegetation veg) {
vegetation.add(veg);
vegetation.add(veg.getGmlId());
} else if (co instanceof LandObject lo) {
land.add(lo);
land.add(lo.getGmlId());
} else if (co instanceof WaterObject wo) {
water.add(wo);
water.add(wo.getGmlId());
} else if (co instanceof ReliefObject) {
land.add(co);
land.add(co.getGmlId());
} else if (co instanceof TinObject) {
land.add(co);
land.add(co.getGmlId());
} else if (co instanceof CityFurniture cf) {
cityfurniture.add(cf);
cityfurniture.add(cf.getGmlId());
} else if (co instanceof GenericCityObject gco) {
genericObjects.add(gco);
genericObjects.add(gco.getGmlId());
}
}
......@@ -467,11 +514,4 @@ public class CityDoctorModel {
return cityGMLVersion;
}
public void addRelief(ReliefObject relief) {
addCityObject(relief);
}
public void addTin(TinObject tin) {
addCityObject(tin);
}
}
......@@ -759,22 +759,9 @@ public class CityGmlParser {
}
private static void drainCityModel(CityDoctorModel model, CityGmlConsumer cityObjectConsumer) {
drainCityObjectList(model.getBuildings(), cityObjectConsumer);
drainCityObjectList(model.getBridges(), cityObjectConsumer);
drainCityObjectList(model.getVegetation(), cityObjectConsumer);
drainCityObjectList(model.getLand(), cityObjectConsumer);
drainCityObjectList(model.getTransportation(), cityObjectConsumer);
drainCityObjectList(model.getWater(), cityObjectConsumer);
drainCityObjectList(model.getTunnels(), cityObjectConsumer);
drainCityObjectList(model.getCityFurniture(), cityObjectConsumer);
drainCityObjectList(model.getGenericCityObjects(), cityObjectConsumer);
}
private static void drainCityObjectList(List<? extends CityObject> objects, CityGmlConsumer cityObjectConsumer) {
for (CityObject co : objects) {
cityObjectConsumer.accept(co);
}
objects.clear();
model.createFeatureStream().forEach(cityObjectConsumer::accept);
}
}
......@@ -22,12 +22,12 @@ import java.io.File;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -141,6 +141,7 @@ public class CityGMLWriterUtils {
stats.setName(adeId);
statistics.getErrors().add(new ErrorProperty(stats));
}
// TODO: Quality ADE update to CityGML 3.0
statistics.setNumErrorBuildings(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBuildings())));
statistics.setNumErrorBridgeObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBridges())));
statistics.setNumErrorLandObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getLand())));
......@@ -152,29 +153,30 @@ public class CityGMLWriterUtils {
return val;
}
private static FeatureStatistics countValidatedCityObjects(List<? extends CityObject> cos) {
int numChecked = 0;
int numError = 0;
for (CityObject co : cos) {
private static FeatureStatistics countValidatedCityObjects(Stream<? extends CityObject> cos) {
AtomicInteger numChecked = new AtomicInteger();
AtomicInteger numError = new AtomicInteger();
cos.forEach(co -> {
if (co.isValidated()) {
numChecked++;
numChecked.getAndIncrement();
if (co.containsAnyError()) {
numError++;
numError.getAndIncrement();
}
}
}
return new FeatureStatistics(numChecked, numError);
});
return new FeatureStatistics(numChecked.get(), numError.get());
}
private static void storeCityObjects(List<? extends CityObject> cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) {
for (CityObject co : cos) {
private static void storeCityObjects(Stream<? extends CityObject> cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) {
cos.forEach(co -> {
if (model.isValidated() && val != null) {
QualityADEUtils.writeQualityAde(co, val);
}
co.reCreateGeometries(gmlFactory, model.getParserConfig());
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject()));
}
});
}
}
......@@ -13,7 +13,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
public class CityObjectCacheTest {
public class FeatureCacheTest {
@BeforeClass
public static void setUpBeforeClass() {
......@@ -36,7 +36,7 @@ public class CityObjectCacheTest {
b.addGeometry(GeometryTestUtils.createDummyGeometry(GeometryType.SOLID, Lod.LOD0));
assertEquals(0, DatabaseHandler.getFeatureCount());
CityObjectCache cache = new CityObjectCache();
FeatureCache cache = new FeatureCache();
cache.put(b);
assertEquals(1, DatabaseHandler.getFeatureCount());
}
......
......@@ -45,33 +45,8 @@ public class XmlValidationReporter implements Reporter {
@Override
public void writeReport(Checks checks, OutputStream filePath, CityDoctorModel model, ValidationConfiguration config) throws CheckReportWriteException {
StreamReporter streamReporter = new XmlStreamReporter(filePath, model.getFileName(), config);
for (BridgeObject bo : model.getBridges()) {
streamReporter.report(bo);
}
for (Building b : model.getBuildings()) {
streamReporter.report(b);
}
for (TransportationObject to : model.getTransportation()) {
streamReporter.report(to);
}
for (CityObject lo : model.getLand()) {
streamReporter.report(lo);
}
for (Vegetation v : model.getVegetation()) {
streamReporter.report(v);
}
for (WaterObject wo : model.getWater()) {
streamReporter.report(wo);
}
for (Tunnel tunnel : model.getTunnels()) {
streamReporter.report(tunnel);
}
for (CityFurniture cf : model.getCityFurniture()) {
streamReporter.report(cf);
}
for (GenericCityObject gco : model.getGenericCityObjects()) {
streamReporter.report(gco);
}
model.createFeatureStream().forEach(streamReporter::report);
for (CheckError err : model.getGlobalErrors()) {
streamReporter.reportGlobalError(err);
}
......
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
......@@ -48,6 +49,8 @@ import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class CityDoctorController {
......@@ -79,6 +82,8 @@ public class CityDoctorController {
private AtomicInteger cityFurnitureChunkNr = new AtomicInteger(0);
private AtomicInteger genericCityObjectsChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
this.highlightController = highlightController;
......@@ -205,6 +210,10 @@ public class CityDoctorController {
return zipArchive;
}
public static int getMaxFeaturesPerChunk(){
return MAX_FEATURES_PER_CHUNK;
}
public void loadZipEntry(CityGmlZipEntry entry) {
if (!entry.isLoaded()) {
entry.loadEntry(currentConfig);
......@@ -260,15 +269,15 @@ public class CityDoctorController {
}
private void setupFeatureTabs() {
mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildings().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetation().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportation().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnels().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridges().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWater().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLand().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurniture().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.GENERIC_CITY_OBJECT, model.getGenericCityObjects().isEmpty());
mainWindow.setDisableOfFeatureTab(FeatureType.BUILDING, model.getBuildingCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.VEGETATION, model.getVegetationCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.TRANSPORTATION, model.getTransportationCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.TUNNEL, model.getTunnelCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.BRIDGE, model.getBridgeCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.WATER, model.getWaterCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.LAND, model.getLandCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.CITY_FURNITURE, model.getCityFurnitureCount() == 0);
mainWindow.setDisableOfFeatureTab(FeatureType.GENERIC_CITY_OBJECT, model.getGenericCityObjectCount() == 0);
}
public void buildTrees() {
......@@ -281,7 +290,7 @@ public class CityDoctorController {
buildWater(model);
buildLand(model);
buildCityFurniture(model);
buildOtherCityObjects(model);
buildGenericCityObjects(model);
buildTunnel(model);
}
......@@ -298,122 +307,130 @@ public class CityDoctorController {
}
private void buildLand(CityDoctorModel model) {
if (model.getLand().isEmpty()) {
if (model.getLandCount() == 0) {
return;
}
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> landRoot = new TreeItem<>(new CityObjectGroupNode(model.getLand(), "Land",
TreeItem<Renderable> landRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Land",
Color.BROWN));
landRoot.setExpanded(true);
landView.setRoot(landRoot);
buildLandFromList(model.getLand(), landView.getRoot());
addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr);
Supplier<Stream<CityObject>> supply = model::getLand;
buildLandTreeFromList(supply, landView.getRoot());
addMoreButtonForLand(landView, landRoot, landChunkNr, supply, model.getLandCount());
}
private void buildLandFromList(List<CityObject> list, TreeItem<Renderable> root) {
private void buildLandTreeFromList(Supplier<Stream<CityObject>> supply, TreeItem<Renderable> root) {
int landChunk = landChunkNr.get();
for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
CityObject land = list.get(i);
supply.get().skip((long) landChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(land ->{
CityObjectNode node = new CityObjectNode(land);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(land, item);
}
});
}
private void buildCityFurniture(CityDoctorModel model) {
if (model.getCityFurniture().isEmpty()) {
if (model.getCityFurnitureCount() == 0) {
return;
}
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(model.getCityFurniture(),
TreeItem<Renderable> cityFurnitureRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"City Furniture", Color.BLUEVIOLET));
cityFurnitureRoot.setExpanded(true);
cityFurnitureView.setRoot(cityFurnitureRoot);
buildCityFurnitureTreeFromList(model.getCityFurniture(), cityFurnitureView.getRoot());
addMoreButtonIfNecessary(model.getCityFurniture(), cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr);
Supplier<Stream<CityFurniture>> supply = model::getCityFurniture;
buildCityFurnitureTreeFromList(supply, cityFurnitureView.getRoot());
addMoreButtonForCityFurniture(cityFurnitureView, cityFurnitureRoot, cityFurnitureChunkNr, supply,
model.getCityFurnitureCount());
}
private void buildOtherCityObjects(CityDoctorModel model) {
if (model.getGenericCityObjects().isEmpty()) {
private void buildGenericCityObjects(CityDoctorModel model) {
if (model.getGenericCityObjectCount() == 0) {
return;
}
TreeView<Renderable> otherObjectsView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(model.getGenericCityObjects(),
TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Generic CityObjects", Color.DARKGRAY));
otherObjectsRoot.setExpanded(true);
otherObjectsView.setRoot(otherObjectsRoot);
buildGenericCityObjectTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot());
addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, genericCityObjectsChunkNr);
Supplier<Stream<GenericCityObject>> supply = model::getGenericCityObjects;
buildGenericCityObjectTreeFromList(supply, otherObjectsView.getRoot());
addMoreButtonForGenericCityObjects( otherObjectsView, otherObjectsRoot, genericCityObjectsChunkNr, supply,
model.getGenericCityObjectCount());
}
private void buildWater(CityDoctorModel model) {
if (model.getWater().isEmpty()) {
if (model.getWaterCount() == 0) {
return;
}
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> waterRoot = new TreeItem<>(new CityObjectGroupNode(model.getWater(), "Water",
TreeItem<Renderable> waterRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Water",
Color.LIGHTSKYBLUE));
waterRoot.setExpanded(true);
waterView.setRoot(waterRoot);
buildWaterTreeFromList(model.getWater(), waterRoot);
addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr);
Supplier<Stream<WaterObject>> supply = model::getWater;
buildWaterTreeFromList(supply, waterRoot);
addMoreButtonForWater(waterView, waterRoot, waterChunkNr, supply, model.getWaterCount());
}
private void buildBridges(CityDoctorModel model) {
if (model.getBridges().isEmpty()) {
if (model.getBridgeCount() == 0) {
return;
}
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new CityObjectGroupNode(model.getBridges(), "Bridges",
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Bridges",
Color.CORAL));
bridgeRoot.setExpanded(true);
bridgeView.setRoot(bridgeRoot);
buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot());
addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr);
Supplier<Stream<BridgeObject>> supply = model::getBridges;
buildBridgeTreeFromList(supply, bridgeView.getRoot());
addMoreButtonForBridges(bridgeView, bridgeRoot, bridgeChunkNr, supply, model.getBridgeCount());
}
private void buildTransportation(CityDoctorModel model) {
if (model.getTransportation().isEmpty()) {
if (model.getTransportationCount() == 0) {
return;
}
TreeView<Renderable> transView = mainWindow.getTransportationView();
TreeItem<Renderable> transRoot = new TreeItem<>(new CityObjectGroupNode(model.getTransportation(),
TreeItem<Renderable> transRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Transportation", Color.YELLOW));
transRoot.setExpanded(true);
transView.setRoot(transRoot);
buildTransportationTreeFromList(model.getTransportation(), transView.getRoot());
addMoreButtonIfNecessary(model.getTransportation(), transView, transRoot, transportationChunkNr);
Supplier<Stream<TransportationObject>> supply = model::getTransportation;
buildTransportationTreeFromList(supply, transView.getRoot());
addMoreButtonForTransportation(transView, transRoot, transportationChunkNr, supply,
model.getTransportationCount());
}
private void buildTunnel(CityDoctorModel model) {
if (model.getTunnels().isEmpty()) {
if (model.getTunnelCount() == 0) {
return;
}
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> tunnelRoot = new TreeItem<>(new CityObjectGroupNode(model.getTunnels(), "Tunnel",
TreeItem<Renderable> tunnelRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Tunnel",
Color.SLATEGRAY));
tunnelRoot.setExpanded(true);
tunnelView.setRoot(tunnelRoot);
buildTunnelTreeFromList(model.getTunnels(), tunnelRoot);
addMoreButtonIfNecessary(model.getTunnels(), tunnelView, tunnelRoot, tunnelChunkNr);
Supplier<Stream<Tunnel>> supply = model::getTunnels;
buildTunnelTreeFromList(supply, tunnelRoot);
addMoreButtonForTunnel(tunnelView, tunnelRoot, tunnelChunkNr, supply, model.getTunnelCount());
}
private void buildVegetation(CityDoctorModel model) {
if (model.getVegetation().isEmpty()) {
if (model.getVegetationCount() == 0) {
return;
}
TreeView<Renderable> vegetationsView = mainWindow.getVegetationView();
TreeItem<Renderable> vegRoot = new TreeItem<>(new CityObjectGroupNode(model.getVegetation(),
TreeItem<Renderable> vegRoot = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(),
"Vegetation", Color.LIGHTGREEN));
vegRoot.setExpanded(true);
vegetationsView.setRoot(vegRoot);
buildVegetationTreeFromList(model.getVegetation(), vegRoot);
addMoreButtonIfNecessary(model.getVegetation(), vegetationsView, vegRoot, vegetationChunkNr);
Supplier<Stream<Vegetation>> supply = model::getVegetation;
buildVegetationTreeFromList(supply, vegRoot);
addMoreButtonForVegetation(vegetationsView, vegRoot, vegetationChunkNr, supply, model.getVegetationCount());
}
private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view,
......@@ -429,7 +446,7 @@ public class CityDoctorController {
chunkCounter.incrementAndGet();
int visibleFeatures = countVisibleNodes(view);
buildTreeFromList(list, root, chunkCounter);
// buildTreeFromList(list, root, chunkCounter);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
......@@ -445,17 +462,35 @@ public class CityDoctorController {
}
}
private void moreButton(CityDoctorModel model, TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityObject>> streamSupplier){
int featureCount = model.getBuildingCount();
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTreeFromList(streamSupplier, root, chunkCounter);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void buildBuildings(CityDoctorModel model) {
if (model.getBuildings().isEmpty()) {
if (model.getBuildingCount() == 0) {
return;
}
//TODO: Continue Supplier implementation
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = new TreeItem<>(new CityObjectGroupNode(model.getBuildings(), "Buildings",
TreeItem<Renderable> root = new TreeItem<>(new CityObjectGroupNode(Collections.emptyList(), "Buildings",
Color.WHITE));
root.setExpanded(true);
buildingsView.setRoot(root);
buildBuildingTreeFromList(model.getBuildings(), root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr);
Supplier<Stream<Building>> supply = model::getBuildings;
buildBuildingTreeFromList(supply, root);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, model.getBuildingCount());
}
......@@ -471,7 +506,7 @@ public class CityDoctorController {
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement();
int visibleFeatures = countVisibleNodes(view);
buildBuildingTreeFromList(list, root);
// buildBuildingTreeFromList(list, root);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
......@@ -487,6 +522,141 @@ public class CityDoctorController {
}
}
private void addMoreButtonForBuildings(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Building>> supply, int featureCount) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildBuildingTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForBridges(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<BridgeObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildBridgeTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForVegetation(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Vegetation>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildVegetationTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForTunnel(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<Tunnel>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTunnelTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForTransportation(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<TransportationObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildTransportationTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForLand(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildLandTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForWater(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<WaterObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildWaterTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForCityFurniture(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<CityFurniture>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildCityFurnitureTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void addMoreButtonForGenericCityObjects(TreeView<Renderable> view, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Supplier<Stream<GenericCityObject>> supply, int featureCount){
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
AddMoreButtonRunnable run = new AddMoreButtonRunnable(featureCount, view, root, chunkCounter) {
@Override
public void buildNodeTreeCall() {
buildGenericCityObjectTreeFromList(supply, root);
updateTree(root);
}
};
//add button
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private static int countVisibleNodes(TreeView<Renderable> view) {
return countVisibleNodes(view.getRoot()) + 1;
}
......@@ -501,17 +671,16 @@ public class CityDoctorController {
return visibleFeatures;
}
private void buildTreeFromList(List<? extends CityObject> cos, TreeItem<Renderable> root,
private void buildTreeFromList(Supplier<Stream<CityObject>> supply, TreeItem<Renderable> root,
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++) {
CityObject co = cos.get(i);
int buildingChunk = buildingChunkNr.get();
supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(co ->{
CityObjectNode node = new CityObjectNode(co);
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem);
createGeometryNodes(co, nodeItem);
}
});
}
private <T extends CityObject> void buildTreeFromListWithProducer(List<T> cos, TreeItem<Renderable> root,
......@@ -582,11 +751,9 @@ public class CityDoctorController {
return nodeItem;
}
private void buildBuildingTreeFromList(List<Building> list, TreeItem<Renderable> root) {
private void buildBuildingTreeFromList(Supplier<Stream<Building>> supply, 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++) {
Building b = list.get(i);
supply.get().skip((long) buildingChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(b ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(b, root, b.getBoundarySurfaces());
createBuildingInstallationNodes(b, item);
......@@ -596,14 +763,12 @@ public class CityDoctorController {
createBuildingStoreyNodes(b, item);
createBuildingUnitNodes(b, item);
createBuildingPartNodes(b, item);
}
});
}
private void buildBridgeTreeFromList(List<BridgeObject> list, TreeItem<Renderable> root) {
private void buildBridgeTreeFromList(Supplier<Stream<BridgeObject>> supply, TreeItem<Renderable> root) {
int bridgeChunk = bridgeChunkNr.get();
for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
BridgeObject bridge = list.get(i);
supply.get().skip((long) bridgeChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(bridge ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(bridge, root, bridge.getBoundarySurfaces());
createBridgeRoomNodes(bridge, item);
......@@ -611,55 +776,46 @@ public class CityDoctorController {
createBridgeFurnitureNodes(bridge, item);
createBridgeConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item);
}
});
}
private void buildTransportationTreeFromList(List<TransportationObject> list, TreeItem<Renderable> root) {
private void buildTransportationTreeFromList(Supplier<Stream<TransportationObject>> supply, TreeItem<Renderable> root) {
int transportChunk = transportationChunkNr.get();
for (int i = transportChunk * MAX_FEATURES_PER_CHUNK; i < (transportChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
TransportationObject t = list.get(i);
TreeItem<Renderable> item = buildTopLevelCityObjectNode(t, root);
createTransportSectionNodes(t, item);
createTrafficSpacesNodes(t, item);
}
supply.get().skip((long) transportChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(trans ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(trans, root);
createTransportSectionNodes(trans, item);
createTrafficSpacesNodes(trans, item);
});
}
private void buildVegetationTreeFromList(List<Vegetation> list, TreeItem<Renderable> root) {
private void buildVegetationTreeFromList(Supplier<Stream<Vegetation>> supply, TreeItem<Renderable> root) {
int vegetationChunk = vegetationChunkNr.get();
for (int i = vegetationChunk * MAX_FEATURES_PER_CHUNK; i < (vegetationChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
Vegetation v = list.get(i);
buildTopLevelCityObjectNode(v, root);
}
supply.get().skip((long) vegetationChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(veg ->{
buildTopLevelCityObjectNode(veg, root);
});
}
private void buildWaterTreeFromList(List<WaterObject> list, TreeItem<Renderable> root) {
private void buildWaterTreeFromList(Supplier<Stream<WaterObject>> supply, TreeItem<Renderable> root) {
int waterChunk = waterChunkNr.get();
for (int i = waterChunk * MAX_FEATURES_PER_CHUNK; i < (waterChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
WaterObject w = list.get(i);
buildTopLevelCityObjectNode(w, root);
}
supply.get().skip((long) waterChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(wat ->{
buildTopLevelCityObjectNode(wat, root);
});
}
private void buildCityFurnitureTreeFromList(List<CityFurniture> list, TreeItem<Renderable> root) {
private void buildCityFurnitureTreeFromList(Supplier<Stream<CityFurniture>> supply, TreeItem<Renderable> root) {
int cityFurnChunk = cityFurnitureChunkNr.get();
for (int i = cityFurnChunk * MAX_FEATURES_PER_CHUNK; i < (cityFurnChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
CityFurniture cf = list.get(i);
supply.get().skip((long) cityFurnChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(cf ->{
buildTopLevelCityObjectNode(cf, root);
}
});
}
private void buildGenericCityObjectTreeFromList(List<GenericCityObject> list, TreeItem<Renderable> root) {
private void buildGenericCityObjectTreeFromList(Supplier<Stream<GenericCityObject>> supply, TreeItem<Renderable> root) {
int genericObjectChunk = genericCityObjectsChunkNr.get();
for (int i = genericObjectChunk * MAX_FEATURES_PER_CHUNK; i < (genericObjectChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
GenericCityObject goc = list.get(i);
buildTopLevelCityObjectNode(goc, root);
}
supply.get().skip((long) genericObjectChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(gen ->{
buildTopLevelCityObjectNode(gen, root);
});
}
private void createTransportSectionNodes(TransportationObject t, TreeItem<Renderable> root) {
......@@ -733,10 +889,9 @@ public class CityDoctorController {
}
private void buildTunnelTreeFromList(List<Tunnel> list, TreeItem<Renderable> root) {
private void buildTunnelTreeFromList(Supplier<Stream<Tunnel>> supply, TreeItem<Renderable> root) {
int tunnelChunk = tunnelChunkNr.get();
for (int i = tunnelChunk * MAX_FEATURES_PER_CHUNK; i < (tunnelChunk + 1) * MAX_FEATURES_PER_CHUNK && i < list.size(); i++) {
Tunnel tunnel = list.get(i);
supply.get().skip((long) tunnelChunk * MAX_FEATURES_PER_CHUNK).limit(MAX_FEATURES_PER_CHUNK).forEach(tunnel ->{
TreeItem<Renderable> item = buildTopLevelCityObjectNode(tunnel, root);
createTunnelHollowNodes(tunnel, item);
......@@ -744,7 +899,8 @@ public class CityDoctorController {
createTunnelFurnitureNodes(tunnel, item);
createTunnelConstructiveElementsNodes(tunnel, item);
createTunnelPartNodes(tunnel, item);
}
});
}
private void createTunnelInstallationNodes(Tunnel tunnel, TreeItem<Renderable> root) {
......@@ -1236,15 +1392,13 @@ public class CityDoctorController {
private Map<ErrorId, ErrorStat> getErrorStats() {
Map<ErrorId, ErrorStat> stats = new HashMap<>();
addErrorStats(stats, model.getBridges());
addErrorStats(stats, model.getBuildings());
addErrorStats(stats, model.getLand());
addErrorStats(stats, model.getTunnels());
addErrorStats(stats, model.getTransportation());
addErrorStats(stats, model.getVegetation());
addErrorStats(stats, model.getWater());
addErrorStats(stats, model.getCityFurniture());
addErrorStats(stats, model.getGenericCityObjects());
List<CheckError> errors = new ArrayList<>();
model.createFeatureStream().forEach(co -> co.collectContainedErrors(errors));
Set<CheckError> filteredErrors = new HashSet<>(errors);
for (CheckError error : filteredErrors) {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
return stats;
}
......@@ -1258,6 +1412,8 @@ public class CityDoctorController {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
}
public void export(CityObject co) {
......@@ -1326,89 +1482,106 @@ public class CityDoctorController {
}
private void filterBuildingTree(String searchString) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
Supplier<Stream<Building>> foundBuildings = () -> model.getBuildings().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundBuildings.get().count();
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
root.getChildren().clear();
buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, foundBuildings, featureCount);
}
private void filterBridgeTree(String searchString) {
List<BridgeObject> foundBridges = filterFeatures(searchString, model.getBridges());
Supplier<Stream<BridgeObject>> foundBridges = () -> model.getBridges().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundBridges.get().count();
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = bridgeView.getRoot();
root.getChildren().clear();
buildBridgeTreeFromList(foundBridges, root);
updateTree(root);
addMoreButtonIfNecessary(foundBridges, bridgeView, root, bridgeChunkNr);
addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, foundBridges, featureCount);
}
private void filterTunnelTree(String searchString) {
List<Tunnel> foundTunnel = filterFeatures(searchString, model.getTunnels());
Supplier<Stream<Tunnel>> foundTunnel = () -> model.getTunnels().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundTunnel.get().count();
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
root.getChildren().clear();
buildTunnelTreeFromList(foundTunnel, root);
updateTree(root);
addMoreButtonIfNecessary(foundTunnel, tunnelView, root, tunnelChunkNr);
addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, foundTunnel, featureCount);
}
private void filterVegetationTree(String searchString) {
List<Vegetation> foundVegetation = filterFeatures(searchString, model.getVegetation());
Supplier<Stream<Vegetation>> foundVegetation = () -> model.getVegetation().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundVegetation.get().count();
TreeView<Renderable> vegetationView = mainWindow.getVegetationView();
TreeItem<Renderable> root = vegetationView.getRoot();
root.getChildren().clear();
buildVegetationTreeFromList(foundVegetation, root);
updateTree(root);
addMoreButtonIfNecessary(foundVegetation, vegetationView, root, vegetationChunkNr);
addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, foundVegetation, featureCount);
}
private void filterTransportationTree(String searchString) {
List<TransportationObject> foundTransportation = filterFeatures(searchString, model.getTransportation());
Supplier<Stream<TransportationObject>> foundTransportation = () -> model.getTransportation().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundTransportation.get().count();
TreeView<Renderable> transportationView = mainWindow.getTransportationView();
TreeItem<Renderable> root = transportationView.getRoot();
root.getChildren().clear();
buildTransportationTreeFromList(foundTransportation, root);
updateTree(root);
addMoreButtonIfNecessary(foundTransportation, transportationView, root, transportationChunkNr);
addMoreButtonForTransportation(transportationView, root, transportationChunkNr,
foundTransportation, featureCount);
}
private void filterWaterTree(String searchString) {
List<WaterObject> foundWater = filterFeatures(searchString, model.getWater());
Supplier<Stream<WaterObject>> foundWater = () -> model.getWater().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundWater.get().count();
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> root = waterView.getRoot();
root.getChildren().clear();
buildWaterTreeFromList(foundWater, root);
addMoreButtonIfNecessary(foundWater, waterView, root, waterChunkNr);
addMoreButtonForWater(waterView, root, waterChunkNr, foundWater, featureCount);
}
private void filterLandTree(String searchString) {
List<CityObject> foundLand = filterFeatures(searchString, model.getLand());
Supplier<Stream<CityObject>> foundLand = () -> model.getLand().filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundLand.get().count();
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> root = landView.getRoot();
root.getChildren().clear();
buildLandFromList(foundLand, root);
addMoreButtonIfNecessary(foundLand, landView, root, landChunkNr);
buildLandTreeFromList(foundLand, root);
addMoreButtonForLand(landView, root, landChunkNr, foundLand, featureCount);
}
private void filterCityFurnitureTree(String searchString) {
List<CityFurniture> foundCityFurniture = filterFeatures(searchString, model.getCityFurniture());
Supplier<Stream<CityFurniture>> foundCityFurniture = () -> model.getCityFurniture().
filter(co -> featureFilter(co, searchString));
int featureCount = (int) foundCityFurniture.get().count();
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> root = cityFurnitureView.getRoot();
root.getChildren().clear();
buildCityFurnitureTreeFromList(foundCityFurniture, root);
addMoreButtonIfNecessary(foundCityFurniture, cityFurnitureView, root, cityFurnitureChunkNr);
addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, foundCityFurniture, featureCount);
}
private void filterGenericCityObjectTree(String searchString) {
List<GenericCityObject> foundGenericCityObject = filterFeatures(searchString, model.getGenericCityObjects());
Supplier<Stream<GenericCityObject>> foundGenericCityObject = () -> model.getGenericCityObjects().
filter(co ->featureFilter(co, searchString));
int featureCount = (int) foundGenericCityObject.get().count();
TreeView<Renderable> genericCityObjectView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> root = genericCityObjectView.getRoot();
root.getChildren().clear();
buildGenericCityObjectTreeFromList(foundGenericCityObject, root);
addMoreButtonIfNecessary(foundGenericCityObject, genericCityObjectView, root, genericCityObjectsChunkNr);
addMoreButtonForGenericCityObjects(genericCityObjectView, root, genericCityObjectsChunkNr,
foundGenericCityObject, featureCount);
}
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
......@@ -1421,6 +1594,10 @@ public class CityDoctorController {
return foundFeatures;
}
private boolean featureFilter(CityObject co, String searchString) {
return co.getGmlId().getGmlString().contains(searchString);
}
public void resetSearch(FeatureType selectedTab) {
if (model == null) {
return;
......@@ -1455,94 +1632,174 @@ public class CityDoctorController {
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<Building> errorBuildings = new ArrayList<>();
for (Building b : model.getBuildings()) {
if (b.containsAnyError()) {
errorBuildings.add(b);
}
}
resetFeatureChunks();
buildBuildingTreeFromList(errorBuildings, root);
List<GmlId> foundBuildings = new ArrayList<>();
model.getBuildings().filter(Checkable::containsAnyError).forEach(co -> foundBuildings.add(co.getGmlId()));
Supplier<Stream<Building>> supply = () -> model.getCache().getStream(foundBuildings).map(co -> (Building) co);
buildBuildingTreeFromList(supply, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr);
addMoreButtonForBuildings(buildingsView, root, buildingChunkNr, supply, foundBuildings.size());
}
public void fillTreeViewWithErrorVegetation() {
TreeView<Renderable> vegetationView = mainWindow.getVegetationView();
TreeItem<Renderable> root = vegetationView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundVegetation = new ArrayList<>();
model.getVegetation().filter(Checkable::containsAnyError).forEach(co -> foundVegetation.add(co.getGmlId()));
Supplier<Stream<Vegetation>> supply = () -> model.getCache().getStream(foundVegetation).map(co -> (Vegetation) co);
buildVegetationTreeFromList(supply, root);
updateTree(root);
addMoreButtonForVegetation(vegetationView, root, vegetationChunkNr, supply, foundVegetation.size());
}
public void fillTreeViewWithErrorBridges() {
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = bridgeView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundBridge = new ArrayList<>();
model.getBridges().filter(Checkable::containsAnyError).forEach(co -> foundBridge.add(co.getGmlId()));
Supplier<Stream<BridgeObject>> supply = () -> model.getCache().getStream(foundBridge).map(co -> (BridgeObject) co);
buildBridgeTreeFromList(supply, root);
updateTree(root);
addMoreButtonForBridges(bridgeView, root, bridgeChunkNr, supply, foundBridge.size());
}
public void fillTreeViewWithErrorLand() {
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> root = landView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundLand = new ArrayList<>();
model.getLand().filter(Checkable::containsAnyError).forEach(co -> foundLand.add(co.getGmlId()));
Supplier<Stream<CityObject>> supply = () -> model.getCache().getStream(foundLand).map(co -> (CityObject) co);
buildLandTreeFromList(supply, root);
updateTree(root);
addMoreButtonForLand(landView, root, landChunkNr, supply, foundLand.size());
}
public void fillTreeViewWithErrorCityFurniture() {
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> root = cityFurnitureView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getCityFurnitureView(),
model.getCityFurniture(), cityFurnitureChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundCityFurniture = new ArrayList<>();
model.getCityFurniture().filter(Checkable::containsAnyError).forEach(co -> foundCityFurniture.add(co.getGmlId()));
Supplier<Stream<CityFurniture>> supply = () -> model.getCache().getStream(foundCityFurniture).map(co -> (CityFurniture) co);
buildCityFurnitureTreeFromList(supply, root);
updateTree(root);
addMoreButtonForCityFurniture(cityFurnitureView, root, cityFurnitureChunkNr, supply, foundCityFurniture.size());
}
public void fillTreeViewWithErrorGenericCityObjects() {
TreeView<Renderable> genericCityObjectsView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> root = genericCityObjectsView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getGenericCityObjectView(),
model.getGenericCityObjects(), genericCityObjectsChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundGenericCityObjects = new ArrayList<>();
model.getGenericCityObjects().filter(Checkable::containsAnyError).forEach(co -> foundGenericCityObjects.add(co.getGmlId()));
Supplier<Stream<GenericCityObject>> supply = () -> model.getCache().getStream(foundGenericCityObjects).map(co -> (GenericCityObject) co);
buildGenericCityObjectTreeFromList(supply, root);
updateTree(root);
addMoreButtonForGenericCityObjects(genericCityObjectsView, root, genericCityObjectsChunkNr, supply, foundGenericCityObjects.size());
}
public void fillTreeViewWithErrorTransportation() {
TreeView<Renderable> transportationView = mainWindow.getTransportationView();
TreeItem<Renderable> root = transportationView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(),
transportationChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundTransportation = new ArrayList<>();
model.getTransportation().filter(Checkable::containsAnyError).forEach(co -> foundTransportation.add(co.getGmlId()));
Supplier<Stream<TransportationObject>> supply = () -> model.getCache().getStream(foundTransportation).map(co -> (TransportationObject) co);
buildTransportationTreeFromList(supply, root);
updateTree(root);
addMoreButtonForTransportation(transportationView, root, transportationChunkNr, supply, foundTransportation.size());
}
public void fillTreeViewWithErrorTunnel() {
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTunnelView(), model.getTunnels(), tunnelChunkNr);
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
resetFeatureChunks();
List<GmlId> foundTunnel = new ArrayList<>();
model.getTunnels().filter(Checkable::containsAnyError).forEach(co -> foundTunnel.add(co.getGmlId()));
Supplier<Stream<Tunnel>> supply = () -> model.getCache().getStream(foundTunnel).map(co -> (Tunnel) co);
buildTunnelTreeFromList(supply, root);
updateTree(root);
addMoreButtonForTunnel(tunnelView, root, tunnelChunkNr, supply, foundTunnel.size());
}
public void fillTreeViewWithErrorWater() {
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> root = waterView.getRoot();
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);
resetFeatureChunks();
List<GmlId> foundWater = new ArrayList<>();
model.getWater().filter(Checkable::containsAnyError).forEach(co -> foundWater.add(co.getGmlId()));
Supplier<Stream<WaterObject>> supply = () -> model.getCache().getStream(foundWater).map(co -> (WaterObject) co);
buildWaterTreeFromList(supply, root);
updateTree(root);
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter);
addMoreButtonForWater(waterView, root, tunnelChunkNr, supply, foundWater.size());
}
public void fillTreeViewFromFeatures(FeatureType selectedTab) {
......@@ -1584,7 +1841,7 @@ public class CityDoctorController {
updateTree(mainWindow.getCityFurnitureView().getRoot());
break;
case GENERIC_CITY_OBJECT:
buildOtherCityObjects(model);
buildGenericCityObjects(model);
updateTree(mainWindow.getGenericCityObjectView().getRoot());
break;
default:
......@@ -1673,6 +1930,9 @@ public class CityDoctorController {
case TRANSPORTATION:
fillTreeViewWithErrorTransportation();
break;
case TUNNEL:
fillTreeViewWithErrorTunnel();
break;
case WATER:
fillTreeViewWithErrorWater();
break;
......
......@@ -13,6 +13,7 @@ import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.*;
import java.util.*;
import java.util.stream.Stream;
public class TriangulatedGeometry {
......@@ -98,8 +99,8 @@ public class TriangulatedGeometry {
private static void addPolygonDataFromCityObjects(List<? extends CityObject> cos,
TriangulatedGeometry triGeom, Color color, List<ViewFilter> filters) {
private static void addPolygonDataFromCityObjects(Stream<? extends CityObject> cos,
TriangulatedGeometry triGeom, Color color, List<ViewFilter> filters) {
CityObjectCollector collector = new CityObjectCollector();
cos.forEach(cityObject -> cityObject.accept(collector));
collector.getCityObjects().forEach(cityObject -> addPolygonData(cityObject, triGeom, color, filters));
......
package de.hft.stuttgart.citydoctor2.gui.tree;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.gui.CityDoctorController;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AddMoreButtonRunnable implements Runnable{
private int featureCount;
private final TreeView<Renderable> view;
private final TreeItem<Renderable> root;
private final AtomicInteger chunkCounter;
private static final int MAX_FEATURES_PER_CHUNK = CityDoctorController.getMaxFeaturesPerChunk();
protected AddMoreButtonRunnable(int featureCount, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter){
this.featureCount = featureCount;
this.view = view;
this.root = root;
this.chunkCounter = chunkCounter;
}
@Override
public void run() {
// 29 is the height of one item
int numberOfDisplayedItems = (int) (view.getHeight() / 29);
int selectedIndex = view.getSelectionModel().getSelectedIndex();
// remove button node
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement();
int visibleFeatures = countVisibleNodes(view);
buildNodeTreeCall();
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < featureCount) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
/**
* Function hook for the buildTree call of the view
*/
public abstract void buildNodeTreeCall();
private static int countVisibleNodes(TreeView<Renderable> view) {
return countVisibleNodes(view.getRoot()) + 1;
}
private static int countVisibleNodes(TreeItem<Renderable> root) {
int visibleFeatures = root.getChildren().size();
for (TreeItem<Renderable> child : root.getChildren()) {
if (!child.getChildren().isEmpty() && child.isExpanded()) {
visibleFeatures += countVisibleNodes(child);
}
}
return visibleFeatures;
}
}
......@@ -12,9 +12,11 @@ public class CityObjectNode extends Renderable {
private static final Logger logger = LogManager.getLogger(CityObjectNode.class);
private final CityObject co;
private String text;
public CityObjectNode(CityObject co) {
this.co = co;
this.text = co.getDisplayText();
}
@Override
......@@ -30,7 +32,7 @@ public class CityObjectNode extends Renderable {
@Override
public String getText() {
return co.getDisplayText();
return text;
}
@Override
......
......@@ -689,9 +689,7 @@ public class HealerController {
// triangle area is too small, ignore
return;
}
for (Building b : model.getBuildings()) {
MeshGenerator.replaceGeometryWithMeshedGeometry(b, area);
}
model.getBuildings().forEach(building -> MeshGenerator.replaceGeometryWithMeshedGeometry(building, area));
} catch (NumberFormatException e) {
// no real number was inserted, do nothing
}
......
......@@ -329,7 +329,7 @@ public class GeneticsGUI extends View {
parserConfig);
currentChecker = new Checker(model1);
currentChecker.runChecks();
Building building = model1.getBuildings().get(0);
Building building = model1.getBuildings().toList().getFirst();
currentGeometry = building.getGeometries().get(0);
currentFeature = building;
showCurrentGeometry();
......
......@@ -298,7 +298,7 @@
<!--CityDoctor2 Extension Modules-->
<module>Extensions/CityDoctorGUI</module>
<module>Extensions/CityDoctorAutoPro</module>
<!-- <module>Extensions/CityDoctorAutoPro</module>-->
<module>Extensions/CityDoctorHealer</module>
<module>Extensions/CityDoctorHealerGenetic</module>
<module>Extensions/CityDoctorHealerGUI</module>
......
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