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

Merge branch 'dev' into 'master'

Version 3.17.0 Release

See merge request !28
1 merge request!28Version 3.17.0 Release
Pipeline #11012 passed with stage
in 1 minute and 10 seconds
Showing with 1930 additions and 348 deletions
+1930 -348
......@@ -65,23 +65,19 @@ public class SvrlContentHandler implements ContentHandler {
public void setDocumentLocator(Locator locator) {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void startDocument() throws SAXException {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void endDocument() throws SAXException {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void endPrefixMapping(String prefix) throws SAXException {
// not needed
......@@ -133,17 +129,14 @@ public class SvrlContentHandler implements ContentHandler {
buffer.append(ch, start, length);
}
}
@SuppressWarnings("RedundantThrows")
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void processingInstruction(String target, String data) throws SAXException {
// not needed
}
@SuppressWarnings("RedundantThrows")
@Override
public void skippedEntity(String name) throws SAXException {
// not needed
......
......@@ -27,19 +27,16 @@ import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection.IntersectionType;
/**
* Check for self intersecting solids
......@@ -78,7 +75,7 @@ public class SolidSelfIntCheck extends Check {
return;
}
CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.doesSolidSelfIntersect2(g);
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g);
if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null);
} else {
......
......@@ -62,6 +62,7 @@ import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector2d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.EarcutTesselator;
import de.hft.stuttgart.citydoctor2.tesselation.JoglTesselator;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
......@@ -75,15 +76,33 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection.IntersectionType;
*/
public class SelfIntersectionUtil {
private static final Logger logger = LogManager.getLogger(SelfIntersectionUtil.class);
private static final GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));
private SelfIntersectionUtil() {
}
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tesselatedPolygons.add(EarcutTesselator.tesselatePolygon(p));
}
List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
}
}
}
return intersections;
}
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) {
return selfIntersectionJava(g);
}
......@@ -114,14 +133,15 @@ public class SelfIntersectionUtil {
return intersections;
}
private static void performEdgeSelfIntersection(List<PolygonIntersection> intersections, Map<Polygon, EdgePolygon> edgePolyMap,
Polygon p1, Polygon p2) {
private static void performEdgeSelfIntersection(List<PolygonIntersection> intersections,
Map<Polygon, EdgePolygon> edgePolyMap, Polygon p1, Polygon p2) {
EdgePolygon edgeP1 = edgePolyMap.get(p1);
EdgePolygon edgeP2 = edgePolyMap.get(p2);
List<PolygonPolygonIntersection> results = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001, 0.001);
List<PolygonPolygonIntersection> results = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001,
0.001);
if (!results.isEmpty()) {
// at least one intersection happened
for (PolygonPolygonIntersection result: results) {
for (PolygonPolygonIntersection result : results) {
// Ensure that Intersection-Edge is not a Null-Line.
// If it is a Null-Line, detected Intersection is a False-Positive.
if (!result.getPolyLine().isNullLine()) {
......
......@@ -29,6 +29,10 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Tunnel;
import de.hft.stuttgart.citydoctor2.datastructure.TunnelPart;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -153,6 +157,12 @@ public class XmlStreamReporter implements StreamReporter {
reportWater(wo);
} else if (co instanceof LandObject lo) {
reportLand(lo);
} else if (co instanceof Tunnel to) {
reportTunnel(to);
} else if (co instanceof CityFurniture cf) {
reportCityFurniture(cf);
} else if (co instanceof GenericCityObject gco) {
reportGenericCityObject(gco);
} else {
throw new IllegalStateException("Not reportable CityObject found: " + co.getClass().getSimpleName());
}
......@@ -196,6 +206,24 @@ public class XmlStreamReporter implements StreamReporter {
report.getValidationResults().getBuildingReports().add(fr);
}
private void reportTunnel(Tunnel to) {
FeatureReport fr = createCityObjectReportNode(to);
for (TunnelPart tp : to.getTunnelParts()) {
reportMap.put(tp.getGmlId().getGmlString(), fr);
}
report.getValidationResults().getTunnelReports().add(fr);
}
private void reportCityFurniture(CityFurniture cf) {
FeatureReport fr = createCityObjectReportNode(cf);
report.getValidationResults().getCityFurnitureReports().add(fr);
}
private void reportGenericCityObject(GenericCityObject gco) {
FeatureReport fr = createCityObjectReportNode(gco);
report.getValidationResults().getGenericCityObjectReports().add(fr);
}
private FeatureReport createCityObjectReportNode(CityObject co) {
FeatureReport fr = new FeatureReport();
reportMap.put(co.getGmlId().getGmlString(), fr);
......@@ -257,6 +285,9 @@ public class XmlStreamReporter implements StreamReporter {
createStatistics(globalErrorCount, report.getValidationResults().getTransportationReports());
createStatistics(globalErrorCount, report.getValidationResults().getVegetationReports());
createStatistics(globalErrorCount, report.getValidationResults().getWaterReports());
createStatistics(globalErrorCount, report.getValidationResults().getTunnelReports());
createStatistics(globalErrorCount, report.getValidationResults().getCityFurnitureReports());
createStatistics(globalErrorCount, report.getValidationResults().getGenericCityObjectReports());
addStatisticsObjects(stats.getErrorStats(), globalErrorCount);
report.setGlobalStatistics(stats);
......@@ -271,6 +302,9 @@ public class XmlStreamReporter implements StreamReporter {
modelStats.setNumTransportation(report.getValidationResults().getTransportationReports().size());
modelStats.setNumVegetation(report.getValidationResults().getVegetationReports().size());
modelStats.setNumWaterObjects(report.getValidationResults().getWaterReports().size());
modelStats.setNumTunnelObjects(report.getValidationResults().getTunnelReports().size());
modelStats.setNumCityFurniture(report.getValidationResults().getCityFurnitureReports().size());
modelStats.setNumGenericCityObjects(report.getValidationResults().getGenericCityObjectReports().size());
return modelStats;
}
......@@ -285,6 +319,12 @@ public class XmlStreamReporter implements StreamReporter {
globErrStats
.setNumErrorVegetation(getNumberOfErrorFeatures(report.getValidationResults().getVegetationReports()));
globErrStats.setNumErrorWaterObjects(getNumberOfErrorFeatures(report.getValidationResults().getWaterReports()));
globErrStats.setNumErrorTunnelObjects(
getNumberOfErrorFeatures(report.getValidationResults().getTunnelReports()));
globErrStats.setNumErrorCityFurniture(
getNumberOfErrorFeatures(report.getValidationResults().getCityFurnitureReports()));
globErrStats.setNumErrorGenericCityObjects(
getNumberOfErrorFeatures(report.getValidationResults().getGenericCityObjectReports()));
return globErrStats;
}
......
......@@ -27,8 +27,11 @@ import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Tunnel;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
......@@ -60,6 +63,15 @@ public class XmlValidationReporter implements Reporter {
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);
}
for (CheckError err : model.getGlobalErrors()) {
streamReporter.reportGlobalError(err);
}
......
......@@ -29,6 +29,18 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractRoom;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractTunnel;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingUnit;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Storey;
import de.hft.stuttgart.citydoctor2.datastructure.Tunnel;
import de.hft.stuttgart.citydoctor2.datastructure.TunnelConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.TunnelPart;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -105,6 +117,18 @@ public class PdfStreamReporter implements StreamReporter {
private int numErrorLand;
private int numOkLand;
private Section tunnel;
private int numErrorTunnel;
private int numOkTunnel;
private Section cityFurniture;
private int numErrorCityFurniture;
private int numOkCityFurniture;
private Section genericCityObject;
private int numErrorGenericCityObject;
private int numOkGenericCityObject;
private Section globalErrors;
private final Map<String, Section> sectionMap = new HashMap<>();
......@@ -186,6 +210,12 @@ public class PdfStreamReporter implements StreamReporter {
reportWater(co, hasError);
} else if (co instanceof LandObject) {
reportLand(co, hasError);
} else if (co instanceof Tunnel) {
reportTunnel(co, hasError);
} else if (co instanceof CityFurniture) {
reportCityFurniture(co, hasError);
} else if (co instanceof GenericCityObject) {
reportGenericCityObject(co, hasError);
} else {
throw new IllegalStateException("Unknown City Object found: " + co.getClass());
}
......@@ -237,6 +267,8 @@ public class PdfStreamReporter implements StreamReporter {
bSection.setHeadlineColor(OK_COLOR);
}
writeErrorForCityObject(co, bSection);
BridgeObject bo = (BridgeObject) co;
writeCheckResultForBridgeObject(bo, bSection);
}
private void reportTrans(CityObject co, boolean hasError) {
......@@ -254,9 +286,6 @@ public class PdfStreamReporter implements StreamReporter {
}
writeErrorForCityObject(co, tSection);
TransportationObject to = (TransportationObject) co;
for (TransportationObject transO : to.getChildren()) {
writeCheckResultForTransportationObject(transO, tSection);
}
}
private void reportVegetation(CityObject co, boolean hasError) {
......@@ -282,22 +311,74 @@ public class PdfStreamReporter implements StreamReporter {
Section bSection = buildings.createSubSection(co.getGmlId().getGmlString());
sectionMap.put(co.getGmlId().getGmlString(), bSection);
if (hasError) {
numErrorBuildings++;
bSection.setHeadlineColor(ERROR_COLOR);
} else {
numOkBuildings++;
bSection.setHeadlineColor(OK_COLOR);
}
writeErrorForCityObject(co, bSection);
Building b = (Building) co;
for (BuildingPart bp : b.getBuildingParts()) {
if (containsError(bp)) {
numErrorBuildings++;
} else {
numOkBuildings++;
}
sectionMap.put(bp.getGmlId().getGmlString(), bSection);
writeCheckResultForBuildingPart(bp, bSection);
writeCheckResultForAbstractBuilding(bp, bSection);
}
for (BoundarySurface bs : b.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, bSection);
writeCheckResultForAbstractBuilding(b, bSection);
}
private void reportTunnel(CityObject co, boolean hasError) {
if (tunnel == null) {
tunnel = vr.createSubSection("Tunnel");
}
for (Installation bi : b.getBuildingInstallations()) {
writeCheckResultForInstallation(bi, bSection);
Section tSection = tunnel.createSubSection(co.getGmlId().getGmlString());
sectionMap.put(co.getGmlId().getGmlString(), tSection);
if (hasError) {
numErrorTunnel++;
tSection.setHeadlineColor(ERROR_COLOR);
} else {
numOkTunnel++;
tSection.setHeadlineColor(OK_COLOR);
}
writeErrorForCityObject(co, tSection);
Tunnel t = (Tunnel) co;
writeCheckResultForAbstractTunnel(t, tSection);
}
private void reportCityFurniture(CityObject co, boolean hasError) {
if (cityFurniture == null) {
cityFurniture = vr.createSubSection("CityFurniture");
}
Section cfSection = cityFurniture.createSubSection(co.getGmlId().getGmlString());
sectionMap.put(co.getGmlId().getGmlString(), cfSection);
if (hasError) {
numErrorCityFurniture++;
cfSection.setHeadlineColor(ERROR_COLOR);
} else {
numOkCityFurniture++;
cfSection.setHeadlineColor(OK_COLOR);
}
writeErrorForCityObject(co, cfSection);
}
private void reportGenericCityObject(CityObject co, boolean hasError) {
if (genericCityObject == null) {
genericCityObject = vr.createSubSection("GenericCityObject");
}
Section gcSection = genericCityObject.createSubSection(co.getGmlId().getGmlString());
sectionMap.put(co.getGmlId().getGmlString(), gcSection);
if (hasError) {
numErrorGenericCityObject++;
gcSection.setHeadlineColor(ERROR_COLOR);
} else {
numOkGenericCityObject++;
gcSection.setHeadlineColor(OK_COLOR);
}
writeErrorForCityObject(co, gcSection);
}
private void writeCheckResultForInstallation(Installation bi, Section root) {
......@@ -327,6 +408,166 @@ public class PdfStreamReporter implements StreamReporter {
}
}
private void writeCheckResultForAbstractBuilding(AbstractBuilding ab, Section root) {
Map<CheckId, CheckResult> results = ab.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : ab.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (AbstractRoom ar : ab.getBuildingRooms()) {
writeCheckResultForRoom(ar, root);
}
for (AbstractFurniture af : ab.getBuildingRoomFurnitureList()) {
writeCheckResultForAbstractFurniture(af, root);
}
for (Storey s : ab.getBuildingStoreys()) {
writeCheckResultForStorey(s, root);
}
for (BuildingUnit bu : ab.getBuildingUnits()) {
writeCheckResultForBuildingUnit(bu, root);
}
for (BoundarySurface bs : ab.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
for (Installation bi : ab.getBuildingInstallations()) {
writeCheckResultForInstallation(bi, root);
}
}
private void writeCheckResultForBridgeObject(BridgeObject bo, Section root) {
Map<CheckId, CheckResult> results = bo.getAllCheckResults();
writeCheckResults(results.values(), root);
for (BridgeObject part : bo.getParts()) {
if (containsError(part)) {
numErrorBridge++;
} else {
numOkBridge++;
}
sectionMap.put(bo.getGmlId().getGmlString(), root);
writeCheckResultForBridgeObject(part, root);
}
for (Geometry geom : bo.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (AbstractRoom ar : bo.getBridgeRooms()) {
writeCheckResultForRoom(ar, root);
}
for (AbstractFurniture af : bo.getBridgeFurniture()) {
writeCheckResultForAbstractFurniture(af, root);
}
for (BridgeConstructiveElement bce : bo.getConstructiveElements()) {
writeCheckResultForBridgeConstructiveElement(bce, root);
}
for (BoundarySurface bs : bo.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
for (Installation bi : bo.getBridgeInstallations()) {
writeCheckResultForInstallation(bi, root);
}
}
private void writeCheckResultForStorey(Storey s, Section root) {
Map<CheckId, CheckResult> results = s.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : s.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (AbstractRoom ar : s.getBuildingRooms()) {
writeCheckResultForRoom(ar, root);
}
for (BuildingUnit bu : s.getBuildingUnits()) {
writeCheckResultForBuildingUnit(bu, root);
}
for (AbstractFurniture af : s.getBuildingRoomFurnitureList()) {
writeCheckResultForAbstractFurniture(af, root);
}
for (BoundarySurface bs : s.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
for (Installation bi : s.getBuildingInstallations()) {
writeCheckResultForInstallation(bi, root);
}
}
private void writeCheckResultForBuildingUnit(BuildingUnit bu, Section root) {
Map<CheckId, CheckResult> results = bu.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : bu.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (AbstractRoom ar : bu.getBuildingRooms()) {
writeCheckResultForRoom(ar, root);
}
for (Storey s : bu.getStoreys()) {
writeCheckResultForStorey(s, root);
}
for (AbstractFurniture af : bu.getBuildingRoomFurnitureList()) {
writeCheckResultForAbstractFurniture(af, root);
}
for (BoundarySurface bs : bu.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
for (Installation bi : bu.getBuildingInstallations()) {
writeCheckResultForInstallation(bi, root);
}
}
private void writeCheckResultForAbstractTunnel(AbstractTunnel at, Section root) {
Map<CheckId, CheckResult> results = at.getAllCheckResults();
writeCheckResults(results.values(), root);
for (TunnelPart tp : at.getTunnelParts()) {
if (containsError(tp)) {
numErrorTunnel++;
} else {
numOkTunnel++;
}
sectionMap.put(tp.getGmlId().getGmlString(), root);
writeCheckResultForAbstractTunnel(tp, root);
}
for (Geometry geom : at.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (AbstractRoom ar : at.getTunnelHollows()) {
writeCheckResultForRoom(ar, root);
}
for (TunnelConstructiveElement te : at.getTunnelConstructiveElements()) {
writeCheckResultForTunnelConstructiveElement(te, root);
}
for (AbstractFurniture tf : at.getTunnelFurniture()) {
writeCheckResultForAbstractFurniture(tf, root);
}
for (BoundarySurface bs : at.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
for (Installation bi : at.getTunnelInstallations()) {
writeCheckResultForInstallation(bi, root);
}
}
private void writeCheckResultForTunnelConstructiveElement(TunnelConstructiveElement te, Section root) {
Map<CheckId, CheckResult> results = te.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : te.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (BoundarySurface bs : te.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
}
private void writeCheckResultForBridgeConstructiveElement(BridgeConstructiveElement bce, Section root) {
Map<CheckId, CheckResult> results = bce.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : bce.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (BoundarySurface bs : bce.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
}
private void writeErrorForCityObject(CityObject co, Section section) {
Map<CheckId, CheckResult> results = co.getAllCheckResults();
writeCheckResults(results.values(), section);
......@@ -343,6 +584,31 @@ public class PdfStreamReporter implements StreamReporter {
}
}
private void writeCheckResultForAbstractFurniture(AbstractFurniture af, Section root) {
Map<CheckId, CheckResult> results = af.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : af.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (BoundarySurface bs : af.getBoundarySurfaceList()) {
writeCheckResultForBoundarySurface(bs, root);
}
}
private void writeCheckResultForRoom(AbstractRoom ar, Section root) {
Map<CheckId, CheckResult> results = ar.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : ar.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (Installation in : ar.getRoomInstallations()) {
writeCheckResultForInstallation(in, root);
}
for (BoundarySurface bs : ar.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
}
private void writeCheckResultForOpening(Opening o, Section root) {
Map<CheckId, CheckResult> results = o.getAllCheckResults();
writeCheckResults(results.values(), root);
......@@ -392,9 +658,10 @@ public class PdfStreamReporter implements StreamReporter {
@Override
public void finishReport() throws CheckReportWriteException {
if (buildings != null) {
countFinishedReportBuildings();
}
//if (buildings != null) {
// countFinishedReportBuildings();
//}
int numBuildings = numErrorBuildings + numOkBuildings;
if (numBuildings > 0) {
statistics.addDistributionBar("Buildings", numErrorBuildings, numOkBuildings);
......@@ -425,6 +692,21 @@ public class PdfStreamReporter implements StreamReporter {
statistics.addDistributionBar("Land Objects", numErrorLand, numOkLand);
}
int numTunnel = numErrorTunnel + numOkTunnel;
if (numTunnel > 0) {
statistics.addDistributionBar("Tunnel Objects", numErrorTunnel, numOkTunnel);
}
int numCityFurniture = numErrorCityFurniture + numOkCityFurniture;
if (numCityFurniture > 0) {
statistics.addDistributionBar("City Furniture", numErrorCityFurniture, numOkCityFurniture);
}
int numGenericCityObjects = numErrorGenericCityObject + numOkGenericCityObject;
if (numGenericCityObjects > 0) {
statistics.addDistributionBar("Generic City Objects", numErrorGenericCityObject, numOkGenericCityObject);
}
statistics.addTextElement("Error Statistics:");
for (Entry<ErrorId, AtomicInteger> e : errorStatistics.entrySet()) {
statistics.add10PtTextElement(e.getKey().toString() + ": " + e.getValue().intValue(), 10);
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
......@@ -18,100 +18,246 @@
*/
package de.hft.stuttgart.citydoctor2.check;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import de.hft.stuttgart.citydoctor2.CityDoctorValidation;
import de.hft.stuttgart.citydoctor2.checkresult.CheckReport;
import de.hft.stuttgart.citydoctor2.checkresult.GlobalErrorStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.GlobalStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.ModelStatistics;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportParseException;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
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 de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
*
* @author Matthias Betz
*
*/
public class CheckerTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testSchematron() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.getRequirements().get(Requirement.R_SE_BS_ROOF_UNFRAGMENTED.toString()).setEnabled(false);
config.setSchematronFilePathInGlobalParameters("src/test/resources/schematronTest.xml");
CityDoctorModel model = CityGmlParser.parseCityGmlFile(
"src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml", config.getParserConfiguration());
Checker checker = new Checker(config, model);
checker.runChecks();
for (Building b : model.getBuildings()) {
if (b.getGmlId().getGmlString().equals("_Simple_BD.1")) {
assertTrue(b.containsAnyError());
} else {
assertFalse(b.containsAnyError());
}
}
assertFalse(model.getGlobalErrors().isEmpty());
}
@Test
public void testChecker() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile();
File f2 = folder.newFile();
try {
String[] args = new String[6];
args[0] = "-in";
args[1] = "src/test/resources/QA-CS-CONCOMP.gml";
args[2] = "-xmlReport";
args[3] = f.getAbsolutePath();
args[4] = "-pdfReport";
args[5] = f2.getAbsolutePath();
CityDoctorValidation.main(args);
assertTrue(f.exists());
assertTrue(f2.exists());
} finally {
f.delete();
f2.delete();
}
}
@Test
public void testStreaming() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile();
File f2 = folder.newFile();
File f3 = folder.newFile();
try {
String[] args = new String[10];
args[0] = "-in";
args[1] = "src/test/resources/testarea.gml";
args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport";
args[5] = f.getAbsolutePath();
args[6] = "-xmlReport";
args[7] = f2.getAbsolutePath();
args[8] = "-out";
args[9] = f3.getAbsolutePath();
CityDoctorValidation.main(args);
assertTrue(f.exists());
assertTrue(f2.exists());
assertTrue(f3.exists());
} finally {
f.delete();
f2.delete();
f3.delete();
}
}
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testSchematron() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.getRequirements().get(Requirement.R_SE_BS_ROOF_UNFRAGMENTED.toString()).setEnabled(false);
config.setSchematronFilePathInGlobalParameters("src/test/resources/schematronTest.xml");
CityDoctorModel model = CityGmlParser.parseCityGmlFile(
"src/test/resources/SimpleSolid_SrefBS_SchematronTest.gml", config.getParserConfiguration());
Checker checker = new Checker(config, model);
checker.runChecks();
for (Building b : model.getBuildings()) {
if (b.getGmlId().getGmlString().equals("_Simple_BD.1")) {
assertTrue(b.containsAnyError());
} else {
assertFalse(b.containsAnyError());
}
}
assertFalse(model.getGlobalErrors().isEmpty());
}
@Test
public void testChecker() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile();
File f2 = folder.newFile();
try {
String[] args = new String[6];
args[0] = "-in";
args[1] = "src/test/resources/QA-CS-CONCOMP.gml";
args[2] = "-xmlReport";
args[3] = f.getAbsolutePath();
args[4] = "-pdfReport";
args[5] = f2.getAbsolutePath();
CityDoctorValidation.main(args);
assertTrue(f.exists());
assertTrue(f2.exists());
} finally {
f.delete();
f2.delete();
}
}
@Test
public void testStreaming() throws CityGmlParseException, IOException, InvalidGmlFileException, CityDoctorWriteException {
File f = folder.newFile();
File f2 = folder.newFile();
File f3 = folder.newFile();
try {
String[] args = new String[10];
args[0] = "-in";
args[1] = "src/test/resources/testarea.gml";
args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport";
args[5] = f.getAbsolutePath();
args[6] = "-xmlReport";
args[7] = f2.getAbsolutePath();
args[8] = "-out";
args[9] = f3.getAbsolutePath();
CityDoctorValidation.main(args);
assertTrue(f.exists());
assertTrue(f2.exists());
assertTrue(f3.exists());
} finally {
f.delete();
f2.delete();
f3.delete();
}
}
@Test
public void testCliZipChecking() throws IOException, CityDoctorWriteException, CityGmlParseException, InvalidGmlFileException {
String output = folder.getRoot().toPath() + File.separator + "test";
String pdfOutput = folder.getRoot().toPath() + File.separator + "pdf" + File.separator;
String xmlOutput = folder.getRoot().toPath() + File.separator + "xml" + File.separator;
try {
String[] args = new String[10];
args[0] = "-in";
args[1] = "src/test/resources/zipArchive.zip";
args[2] = "-config";
args[3] = "src/test/resources/testConfigWithStreaming.yml";
args[4] = "-pdfReport";
args[5] = pdfOutput;
args[6] = "-xmlReport";
args[7] = xmlOutput;
args[8] = "-out";
args[9] = output + File.separator;
CityDoctorValidation.main(args);
File zipFile = new File(output + ".zip");
File pdfDir = new File(pdfOutput);
File xmlDir = new File(xmlOutput);
assertTrue(zipFile.exists());
assertTrue(pdfDir.exists());
assertTrue(xmlDir.exists());
assertTrue(pdfDir.isDirectory());
assertTrue(xmlDir.isDirectory());
assertEquals(5, pdfDir.listFiles().length);
assertEquals(5, xmlDir.listFiles().length);
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register(output + ".zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, true));
assertEquals(5, cgmlArch.getEntries().size());
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
assertNotNull(entry);
assertNull(entry.getErrorType());
}
} catch (CityGmlParseException | IOException | InvalidGmlFileException | CityDoctorWriteException e) {
throw e;
}
}
@Test
public void testZipEntryChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue("CityObject should be validated", co.isValidated());
};
for (CityGmlZipEntry entry : cgmlArch.getEntries()) {
Checker.streamCheck(entry, null, null, config, l, null);
}
}
@Test
public void testZipArchiveChecking() throws CityGmlParseException, IOException {
CityGmlZipArchive cgmlArch = CityGmlZipArchive.register("src/test/resources/zipArchive.zip");
assertNotNull(cgmlArch);
cgmlArch.mountArchive(new ParserConfiguration(8, false));
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
FeatureCheckedListener l = co -> {
assertTrue(co.isValidated());
};
Checker.streamCheck(cgmlArch, null, null, config, l, null);
}
@Test
public void testReportCreation() throws IOException, CityGmlParseException, InvalidGmlFileException {
Path tmpDir = null;
try {
tmpDir = Files.createTempDirectory("testTmp");
tmpDir.toFile().deleteOnExit();
Path xmlPath = tmpDir.resolve("report.xml");
Path pdfPath = tmpDir.resolve("report.pdf");
File features = new File("src/test/resources/feature_types.gml");
CityDoctorModel model = CityGmlParser.parseCityGmlFileSilently(
features.toString(), new ParserConfiguration(8, false));
assertNotNull(model);
Checker checker = new Checker(model);
checker.runChecks();
checker.writeXmlReport(xmlPath.toString());
checker.writePdfReport(pdfPath.toString());
assertTrue(Files.exists(xmlPath));
assertTrue(Files.exists(pdfPath));
try {
CheckReport report = CheckReport.load(xmlPath.toString());
assertNotNull(report);
GlobalStatistics globalStatistics = report.getGlobalStatistics();
assertNotNull(globalStatistics);
ModelStatistics modelStats = globalStatistics.getModelStats();
assertNotNull(modelStats);
assertEquals(1, modelStats.getNumBuildings());
assertEquals(1, modelStats.getNumVegetation());
assertEquals(1, modelStats.getNumTransportation());
assertEquals(1, modelStats.getNumTunnelObjects());
assertEquals(1, modelStats.getNumBridgeObjects());
assertEquals(1, modelStats.getNumWaterObjects());
assertEquals(1, modelStats.getNumLandObjects());
assertEquals(1, modelStats.getNumCityFurniture());
assertEquals(1, modelStats.getNumGenericCityObjects());
GlobalErrorStatistics globError = globalStatistics.getGlobalErrorStats();
assertNotNull(globError);
assertEquals(0, globError.getNumErrorBuildings());
assertEquals(0, globError.getNumErrorVegetation());
assertEquals(0, globError.getNumErrorTransportation());
assertEquals(0, globError.getNumErrorTunnelObjects());
assertEquals(0, globError.getNumErrorBridgeObjects());
assertEquals(0, globError.getNumErrorWaterObjects());
assertEquals(0, globError.getNumErrorLandObjects());
assertEquals(1, globError.getNumErrorCityFurniture());
assertEquals(1, globError.getNumErrorGenericCityObjects());
} catch (CheckReportParseException e) {
fail("Report should be valid file");
}
} finally {
if (tmpDir != null) {
FileUtils.deleteDirectory(tmpDir.toFile());
}
}
}
}
......@@ -36,7 +36,6 @@ public class SolidSelfIntCheckFalsePositiveBigMeshTest {
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
System.out.println(building.containsAnyError());
/*
* The examples have no actual self-intersections, but can contain other actual model defects.
* If an error is detected, it is thus required to check if the
......
......@@ -86,7 +86,6 @@ public class SolidSelfIntCheckTest {
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
System.out.println(building.containsAnyError());
/*
* The examples have no actual self-intersections, but can contain other actual model defects.
* If an error is detected, it is thus required to check if the
......
......@@ -45,7 +45,6 @@ public class NonManifoldVertexSystemTest {
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS.gml");
Geometry g = c.getBuildings().get(0).getGeometries().get(0);
CheckResult cr = g.getCheckResult(CheckId.C_GE_S_NON_MANIFOLD_VERTEX);
System.out.println(cr);
assertEquals(ResultStatus.OK, cr.getResultStatus());
}
......
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<core:CityModel xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:wtr="http://www.opengis.net/citygml/waterbody/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns:veg="http://www.opengis.net/citygml/vegetation/2.0" xmlns:dem="http://www.opengis.net/citygml/relief/2.0" xmlns:tran="http://www.opengis.net/citygml/transportation/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:tun="http://www.opengis.net/citygml/tunnel/2.0" xmlns:qual="https://transfer.hft-stuttgart.de/pages/citydoctor/qualityade/1.0.0" xmlns:frn="http://www.opengis.net/citygml/cityfurniture/2.0" xmlns:brid="http://www.opengis.net/citygml/bridge/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:luse="http://www.opengis.net/citygml/landuse/2.0" xsi:schemaLocation="http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/cityobjectgroup/2.0 http://schemas.opengis.net/citygml/cityobjectgroup/2.0/cityObjectGroup.xsd http://www.opengis.net/citygml/tunnel/2.0 http://schemas.opengis.net/citygml/tunnel/2.0/tunnel.xsd http://www.opengis.net/citygml/waterbody/2.0 http://schemas.opengis.net/citygml/waterbody/2.0/waterBody.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/cityfurniture/2.0 http://schemas.opengis.net/citygml/cityfurniture/2.0/cityFurniture.xsd http://www.opengis.net/citygml/bridge/2.0 http://schemas.opengis.net/citygml/bridge/2.0/bridge.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd http://www.opengis.net/citygml/vegetation/2.0 http://schemas.opengis.net/citygml/vegetation/2.0/vegetation.xsd http://www.opengis.net/citygml/relief/2.0 http://schemas.opengis.net/citygml/relief/2.0/relief.xsd http://www.opengis.net/citygml/transportation/2.0 http://schemas.opengis.net/citygml/transportation/2.0/transportation.xsd http://www.opengis.net/citygml/landuse/2.0 http://schemas.opengis.net/citygml/landuse/2.0/landUse.xsd">
<core:cityObjectMember>
<brid:Bridge gml:id="bridge">
<brid:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875076_589">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626144167_811">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626144167_810">
<gml:posList srsDimension="3">84816.978 447538.908 1.48 84816.938 447538.659 1.48 84817.016 447538.782 1.48 84816.978 447538.908 1.48</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</brid:lod1MultiSurface>
</brid:Bridge>
</core:cityObjectMember>
<core:cityObjectMember>
<wtr:WaterBody gml:id="water">
<wtr:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875078_592">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626152495_1043">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626152495_1042">
<gml:posList srsDimension="3">85012.343 447455.577 0.88 85010.804 447448.808 0.88 85013.832 447447.447 0.88 85012.343 447455.577 0.88</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</wtr:lod1MultiSurface>
</wtr:WaterBody>
</core:cityObjectMember>
<core:cityObjectMember>
<bldg:Building gml:id="building">
<bldg:lod1Solid>
<gml:Solid gml:id="CityDoctor_1737625875045_1">
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_761">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_760">
<gml:posList srsDimension="3">84967.573 447497.445 0.01 84967.538 447497.33 0.01 84964.343 447494.755 0.01 84962.909 447496.556 0.01 84964.913 447498.161 0.01 84964.969 447498.343 0.01 84967.602 447497.541 0.01 84967.573 447497.445 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_763">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_762">
<gml:posList srsDimension="3">84967.602 447497.541 2.36 84964.969 447498.343 2.36 84964.913 447498.161 2.36 84962.909 447496.556 2.36 84964.343 447494.755 2.36 84967.538 447497.33 2.36 84967.573 447497.445 2.36 84967.602 447497.541 2.36</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_765">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_764">
<gml:posList srsDimension="3">84967.538 447497.33 0.01 84967.573 447497.445 0.01 84967.573 447497.445 2.36 84967.538 447497.33 2.36 84967.538 447497.33 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_767">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_766">
<gml:posList srsDimension="3">84964.343 447494.755 0.01 84967.538 447497.33 0.01 84967.538 447497.33 2.36 84964.343 447494.755 2.36 84964.343 447494.755 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_769">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_768">
<gml:posList srsDimension="3">84962.909 447496.556 0.01 84964.343 447494.755 0.01 84964.343 447494.755 2.36 84962.909 447496.556 2.36 84962.909 447496.556 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_771">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_770">
<gml:posList srsDimension="3">84964.913 447498.161 0.01 84962.909 447496.556 0.01 84962.909 447496.556 2.36 84964.913 447498.161 2.36 84964.913 447498.161 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_773">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_772">
<gml:posList srsDimension="3">84964.969 447498.343 0.01 84964.913 447498.161 0.01 84964.913 447498.161 2.36 84964.969 447498.343 2.36 84964.969 447498.343 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_775">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_774">
<gml:posList srsDimension="3">84967.602 447497.541 0.01 84964.969 447498.343 0.01 84964.969 447498.343 2.36 84967.602 447497.541 2.36 84967.602 447497.541 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626132674_777">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626132674_776">
<gml:posList srsDimension="3">84967.573 447497.445 0.01 84967.602 447497.541 0.01 84967.602 447497.541 2.36 84967.573 447497.445 2.36 84967.573 447497.445 0.01</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</bldg:lod1Solid>
</bldg:Building>
</core:cityObjectMember>
<core:cityObjectMember>
<frn:CityFurniture gml:id="city_furniture">
<frn:lod3Geometry>
<gml:MultiSurface gml:id="CityDoctor_1737378219186_2805">
<gml:surfaceMember>
<gml:CompositeSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyIDGeo19503615">
<gml:exterior>
<gml:LinearRing gml:id="ringID19503615">
<gml:posList srsDimension="3">358506.943 5655399.912 47.06 358507.161 5655401.568 47.06 358506.943 5655403.224 47.06 358506.304 5655404.768 47.06 358505.287 5655406.093 47.06 358503.961 5655407.111 47.06 358502.418 5655407.75 47.06 358500.761 5655407.968 47.06 358499.105 5655407.75 47.06 358497.561 5655407.111 47.06 358496.236 5655406.093 47.06 358495.219 5655404.768 47.06 358494.579 5655403.224 47.06 358494.361 5655401.568 47.06 358494.579 5655399.912 47.06 358495.219 5655398.368 47.06 358496.236 5655397.043 47.06 358497.561 5655396.025 47.06 358499.105 5655395.386 47.06 358500.761 5655395.168 47.06 358502.418 5655395.386 47.06 358503.961 5655396.025 47.06 358505.287 5655397.043 47.06 358506.304 5655398.368 47.06 358506.943 5655399.912 47.06</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:surfaceMember>
</gml:MultiSurface>
</frn:lod3Geometry>
</frn:CityFurniture>
</core:cityObjectMember>
<core:cityObjectMember>
<tran:Road gml:id="transport">
<tran:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875071_446">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626138227_779">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626138227_778">
<gml:posList srsDimension="3">85034.582 447448.556 1.27 85034.916 447449.902 1.36 85030.3 447450.585 1.18 85034.582 447448.556 1.27</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tran:lod1MultiSurface>
</tran:Road>
</core:cityObjectMember>
<core:cityObjectMember>
<veg:PlantCover gml:id="vegetation">
<veg:lod1MultiSurface>
<gml:MultiSurface gml:id="CityDoctor_1737625875066_320">
<gml:surfaceMember>
<gml:Polygon gml:id="CityDoctor_1737626125400_739">
<gml:exterior>
<gml:LinearRing gml:id="CityDoctor_1737626125400_738">
<gml:posList srsDimension="3">84930.097 447481.714 0.04 84930.561 447483.073 -0.07 84929.876 447482.352 0.045 84930.097 447481.714 0.04</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</veg:lod1MultiSurface>
</veg:PlantCover>
</core:cityObjectMember>
<core:cityObjectMember>
<gen:GenericCityObject gml:id="generic_object">
<gen:lod2Geometry>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyIDGeo-5">
<gml:exterior>
<gml:LinearRing gml:id="ringID-5">
<gml:posList srsDimension="3">-0.049000 0.085000 1.162000 -0.098000 0.000000 1.162000 -0.049000 -0.085000 1.162000 0.049000 -0.085000 1.162000 0.098000 0.000000 1.162000 0.049000 0.085000 1.162000 -0.049000 0.085000 1.162000 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</gen:lod2Geometry>
</gen:GenericCityObject>
</core:cityObjectMember>
<core:cityObjectMember>
<tun:Tunnel gml:id="tunnel">
<tun:lod2Solid>
<gml:Solid>
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.1"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.2"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.3"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.4"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.5"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.6"/>
<gml:surfaceMember xlink:href="#_Simple_BD.1_PG.7"/>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</tun:lod2Solid>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.2">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.2_LR.1">
<gml:posList srsDimension="3">
13.0 15.0 0.0
13.0 15.0 3.0
13.0 10.0 3.0
13.0 10.0 0.0
13.0 15.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_2">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.3">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.3_LR.1">
<gml:posList srsDimension="3">
10.0 15.0 0.0
10.0 15.0 3.0
11.5 15.0 4.5
13.0 15.0 3.0
13.0 15.0 0.0
10.0 15.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_3">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.4">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.4_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 3.0
10.0 15.0 3.0
10.0 15.0 0.0
10.0 10.0 0.0
10.0 10.0 3.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:WallSurface gml:id="_Simple_BD.1_WallSurface_4">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.5">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.5_LR.1">
<gml:posList srsDimension="3">
13.0 10.0 0.0
13.0 10.0 3.0
11.5 10.0 4.5
10.0 10.0 3.0
10.0 10.0 0.0
13.0 10.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:WallSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:RoofSurface gml:id="_Simple_BD.1_RoofSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.6">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.6_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 3.0
11.5 10.0 4.5
11.5 15.0 4.5
10.0 15.0 3.0
10.0 10.0 3.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.7">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.7_LR.1">
<gml:posList srsDimension="3">
11.5 10.0 4.5
13.0 10.0 3.0
13.0 15.0 3.0
11.5 15.0 4.5
11.5 10.0 4.5
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:RoofSurface>
</tun:boundedBy>
<tun:boundedBy>
<tun:GroundSurface gml:id="_Simple_BD.1_GroundSurface_1">
<tun:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="_Simple_BD.1_PG.1">
<gml:exterior>
<gml:LinearRing gml:id="_Simple_BD.1_PG.1_LR.1">
<gml:posList srsDimension="3">
10.0 10.0 0.0
10.0 15.0 0.0
13.0 15.0 0.0
13.0 10.0 0.0
10.0 10.0 0.0
</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</tun:lod2MultiSurface>
</tun:GroundSurface>
</tun:boundedBy>
</tun:Tunnel>
</core:cityObjectMember>
<core:cityObjectMember>
<luse:LandUse gml:id="terrain">
<luse:lod1MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:pos>85042.215 447482.383 0.494</gml:pos>
<gml:pos>85042.439 447481.251 0.490</gml:pos>
<gml:pos>85044.905 447482.952 0.490</gml:pos>
<gml:pos>85042.215 447482.383 0.494</gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</luse:lod1MultiSurface>
</luse:LandUse>
</core:cityObjectMember>
</core:CityModel>
\ No newline at end of file
File added
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.16.0</version>
<version>3.17.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>CityDoctorAutoPro</artifactId>
......
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.16.0</version>
<version>3.17.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>CityDoctorGUI</artifactId>
......@@ -45,12 +47,24 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>create-binaries</id>
<properties>
<win-jre>jre-${jre-version-short}-full</win-jre>
<win-jre>jre-${jre-version-short}</win-jre>
<lin-jre>${win-jre}</lin-jre>
<mac-jre>${win-jre}.jre</mac-jre>
</properties>
......@@ -68,9 +82,11 @@
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-windows-amd64-full.zip</uri>
<uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-windows-amd64.zip</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-win</outputDirectory>
<outputDirectory>
${project.build.directory}/jre/jre-win</outputDirectory>
<outputFileName>win-runtime.zip</outputFileName>
</configuration>
</execution>
......@@ -81,9 +97,11 @@
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-linux-amd64-full.tar.gz</uri>
<uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-linux-amd64.tar.gz</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-lin</outputDirectory>
<outputDirectory>
${project.build.directory}/jre/jre-lin</outputDirectory>
<outputFileName>lin-runtime.tar.gz</outputFileName>
</configuration>
</execution>
......@@ -94,9 +112,11 @@
<goal>wget</goal>
</goals>
<configuration>
<uri>https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-macos-amd64-full.zip</uri>
<uri>
https://download.bell-sw.com/java/${jre-version}/bellsoft-jre${jre-version}-macos-amd64.zip</uri>
<unpack>false</unpack>
<outputDirectory>${project.build.directory}/jre/jre-mac</outputDirectory>
<outputDirectory>
${project.build.directory}/jre/jre-mac</outputDirectory>
<outputFileName>mac-runtime.zip</outputFileName>
</configuration>
</execution>
......@@ -112,9 +132,16 @@
<phase>install</phase>
<configuration>
<target name="unpack">
<untar src="${project.build.directory}/jre/jre-lin/lin-runtime.tar.gz" dest="${project.build.directory}/jre/jre-lin/runtime" compression="gzip"></untar>
<unzip src="${project.build.directory}/jre/jre-win/win-runtime.zip" dest="${project.build.directory}/jre/jre-win/runtime"></unzip>
<unzip src="${project.build.directory}/jre/jre-mac/mac-runtime.zip" dest="${project.build.directory}/jre/jre-mac/runtime"></unzip>
<untar
src="${project.build.directory}/jre/jre-lin/lin-runtime.tar.gz"
dest="${project.build.directory}/jre/jre-lin/runtime"
compression="gzip"></untar>
<unzip
src="${project.build.directory}/jre/jre-win/win-runtime.zip"
dest="${project.build.directory}/jre/jre-win/runtime"></unzip>
<unzip
src="${project.build.directory}/jre/jre-mac/mac-runtime.zip"
dest="${project.build.directory}/jre/jre-mac/runtime"></unzip>
</target>
</configuration>
<goals>
......@@ -136,9 +163,11 @@
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-no-runtime</finalName>
<finalName>
${project.artifactId}-${project.version}-no-runtime</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/no_runtime/assembly.xml</descriptor>
<descriptor>
${project.basedir}/src/assembly/no_runtime/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
......@@ -149,9 +178,11 @@
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-win</finalName>
<finalName>
${project.artifactId}-${project.version}-win</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/win/assembly.xml</descriptor>
<descriptor>
${project.basedir}/src/assembly/win/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
......@@ -162,9 +193,11 @@
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-lin</finalName>
<finalName>
${project.artifactId}-${project.version}-lin</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/lin/assembly.xml</descriptor>
<descriptor>
${project.basedir}/src/assembly/lin/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
......@@ -175,9 +208,11 @@
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}-mac</finalName>
<finalName>
${project.artifactId}-${project.version}-mac</finalName>
<descriptors>
<descriptor>${project.basedir}/src/assembly/mac/assembly.xml</descriptor>
<descriptor>
${project.basedir}/src/assembly/mac/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
......
......@@ -3,6 +3,7 @@ package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
......@@ -10,6 +11,13 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Alert;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip;
import javafx.stage.DirectoryChooser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -131,9 +139,29 @@ public class CheckDialog {
@FXML
private Label schematronFileLabel;
@FXML
private VBox zipArchiveOptionsVBox;
@FXML
private CheckBox streamCheckOption;
@FXML
private Label streamCheckLabel;
@FXML
private VBox streamCheckParametersVBox;
@FXML
private Label outputPathLabel;
@FXML
private TextField outputPathTextField;
@FXML
private Button outputPathBtn;
@FXML
private CheckBox pdfReportsOption;
@FXML
private CheckBox xmlReportsOption;
private CityDoctorController controller;
private FilterPane filterPane;
private MainWindow window;
private boolean zipArchiveMode;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window;
......@@ -153,6 +181,8 @@ public class CheckDialog {
}
public void initialize() {
setupZipArchiveOptions();
createEnableColumn(geometricTable);
createNameColumn(geometricTable);
createValueColumn(geometricTable);
......@@ -256,6 +286,47 @@ public class CheckDialog {
});
}
private void setupZipArchiveOptions() {
streamCheckOption.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
streamCheckParametersVBox.setDisable(!streamCheckOption.isSelected());
}
});
outputPathBtn.setOnAction(e -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setInitialDirectory(Path.of(Settings.get(Settings.LAST_OPEN_FOLDER)).getParent().toFile());
File f = directoryChooser.showDialog(stage.getOwner());
if (f != null) {
outputPathTextField.setText(f.getAbsolutePath());
Settings.set(Settings.LAST_OPEN_FOLDER, f.getAbsolutePath());
}
});
streamCheckOption.setText(Localization.getText("CheckDialog.streamCheckOption"));
streamCheckLabel.setTooltip(new Tooltip(Localization.getText("CheckDialog.streamCheckLabel")));
outputPathLabel.setText(Localization.getText("CheckDialog.outputPathLabel"));
outputPathBtn.setText(Localization.getText("CheckDialog.outputPathBtn"));
pdfReportsOption.setText(Localization.getText("CheckDialog.pdfReportsOption"));
xmlReportsOption.setText(Localization.getText("CheckDialog.xmlReportsOption"));
showZipArchiveOptions(false);
}
/**
* Shows the option panel for ZIP-Archive checking and enables the ZIP-Archive checking mode for this dialog.
*
* @param enabled
*/
public void showZipArchiveOptions(boolean enabled) {
zipArchiveOptionsVBox.setDisable(!enabled);
zipArchiveOptionsVBox.setVisible(enabled);
zipArchiveMode = enabled;
}
private void setupSelectButton() {
selectBtn.setOnAction(ae -> {
FileChooser chooser = new FileChooser();
......@@ -416,13 +487,33 @@ public class CheckDialog {
checkBtn.setDisable(true);
cancelBtn.setDisable(true);
stage.setOnCloseRequest(Event::consume);
Thread t = new Thread(() -> {
try {
if (logger.isInfoEnabled()) {
String startingChecks = Localization.getText("CheckDialog.startingChecks");
logger.info(startingChecks);
}
controller.startChecks(config, progress::setProgress);
if (zipArchiveMode) {
Path outputPath = null;
if (streamCheckOption.isSelected()) {
if (outputPathTextField.getText().isEmpty()) {
Alert warning = new Alert(Alert.AlertType.ERROR);
warning.setTitle("Error");
warning.setContentText(Localization.getText("CheckDialog.noPathError"));
warning.showAndWait();
return;
}
outputPath = Path.of(outputPathTextField.getText());
Platform.runLater(() -> progress.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS));
}
controller.startZipFileChecks(config, progress::setProgress, streamCheckOption.isSelected(),
outputPath, pdfReportsOption.isSelected(),
xmlReportsOption.isSelected());
} else {
controller.startChecks(config, progress::setProgress);
}
if (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone");
logger.info(checksDone);
......@@ -574,6 +665,7 @@ public class CheckDialog {
}
}
public void show() {
Platform.runLater(() -> {
if (controller.getCurrentConfig() != null) {
......
......@@ -11,23 +11,35 @@ import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
import de.hft.stuttgart.citydoctor2.gui.tree.*;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.*;
import de.hft.stuttgart.citydoctor2.utils.ArchivePacker;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipArchive;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.zip.MalformedZipFileException;
import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
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.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
......@@ -42,7 +54,9 @@ public class CityDoctorController {
private CityDoctorModel model;
private ParserConfiguration currentConfig;
private String sourceFile;
private CityGmlZipArchive zipArchive;
private ZipEntryManager currentZipEntryManager;
private HashMap<CityDoctorModel, Checker> previousCheckers = null;
private Checker currentChecker;
private HighlightController highlightController;
......@@ -57,7 +71,7 @@ public class CityDoctorController {
private AtomicInteger waterChunkNr = new AtomicInteger(0);
private AtomicInteger landChunkNr = new AtomicInteger(0);
private AtomicInteger cityFurnitureChunkNr = new AtomicInteger(0);
private AtomicInteger otherObjectsChunkNr = new AtomicInteger(0);
private AtomicInteger genericCityObjectsChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
......@@ -75,6 +89,7 @@ public class CityDoctorController {
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
......@@ -82,6 +97,12 @@ public class CityDoctorController {
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
if (path.endsWith(".zip")) {
loadCityGmlZipFile(path, numberOfRoundingPlaces, useValidation, lowMemory);
return;
}
currentZipEntryManager = null;
previousCheckers = null;
currentChecker = null;
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
GMLValidationHandler handler = null;
......@@ -108,7 +129,7 @@ public class CityDoctorController {
}
};
}
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler);
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler, true);
if (!validationIssues.isEmpty()) {
StringJoiner sj = new StringJoiner("\n");
validationIssues.stream().forEach(sj::add);
......@@ -128,14 +149,108 @@ public class CityDoctorController {
mainWindow.getSaveBtn().setDisable(false);
mainWindow.getResetCameraBtn().setDisable(false);
mainWindow.getHideRoofBtn().setDisable(false);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getNorthArrow().setVisible(true);
mainWindow.alignNorthArrow();
setupFeatureTabs();
buildTrees();
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
private void loadCityGmlZipFile(String path, int numberOfRoundingPlaces, boolean useValidation,
boolean lowMemory) {
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
try {
zipArchive = CityGmlZipArchive.register(path);
} catch (MalformedZipFileException e) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
});
} catch (Exception e) {
Platform.runLater(() -> {
ExceptionDialog exDialog = new ExceptionDialog();
exDialog.show(e);
});
}
if (zipArchive != null) {
previousCheckers = new HashMap<>();
Platform.runLater(() -> {
try {
currentZipEntryManager = new ZipEntryManager(mainWindow.getMainStage(), this);
currentZipEntryManager.show();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
public void decompressZipEntry(CityGmlZipEntry entry, ProgressListener l) {
entry.loadEntry(currentConfig, l);
}
public CityGmlZipArchive getZipArchive() {
return zipArchive;
}
public void loadZipEntry(CityGmlZipEntry entry) {
if (!entry.isLoaded()) {
entry.loadEntry(currentConfig);
}
if (entry.getErrorType() != null) {
throw new IllegalArgumentException("Attempted to load erroneous zip entry");
}
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getZipManagerBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
clearTrees();
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
model = entry.getModel();
currentChecker = previousCheckers.getOrDefault(model, null);
mainWindow.getClickHandler().setConfig(currentConfig);
sourceFile = entry.getArchive().getArchivePath().toString();
renderer.reset();
Platform.runLater(() -> {
mainWindow.addFileNameToTitle(entry.getArchive().getArchivePath().toString());
mainWindow.getCheckButton().setDisable(false);
mainWindow.getLod1Btn().setDisable(false);
mainWindow.getLod2Btn().setDisable(false);
mainWindow.getLod3Btn().setDisable(false);
mainWindow.getLod4Btn().setDisable(false);
mainWindow.getWorldBtn().setDisable(false);
mainWindow.getSaveBtn().setDisable(false);
mainWindow.getResetCameraBtn().setDisable(false);
mainWindow.getHideRoofBtn().setDisable(false);
mainWindow.getZipManagerBtn().setDisable(false);
mainWindow.getNorthArrow().setVisible(true);
mainWindow.alignNorthArrow();
setupFeatureTabs();
buildTrees();
updateFeatureTrees();
mainWindow.getWriteReportButton().setDisable(currentChecker == null);
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
public void showZipManager() {
Platform.runLater(() -> currentZipEntryManager.show());
}
private void setupFeatureTabs() {
......@@ -155,11 +270,13 @@ public class CityDoctorController {
buildBuildings(model);
buildVegetation(model.getVegetation());
buildTransportation(model.getTransportation());
buildTunnel(model.getTunnels());
buildBridges(model);
buildWater(model);
buildLand(model);
buildCityFurniture(model);
buildOtherCityObjects(model);
buildTunnel(model.getTunnels());
}
private void resetFeatureChunks() {
......@@ -171,7 +288,7 @@ public class CityDoctorController {
waterChunkNr.set(0);
landChunkNr.set(0);
cityFurnitureChunkNr.set(0);
otherObjectsChunkNr.set(0);
genericCityObjectsChunkNr.set(0);
}
private void buildLand(CityDoctorModel model) {
......@@ -242,12 +359,12 @@ public class CityDoctorController {
if (model.getGenericCityObjects().isEmpty()) {
return;
}
TreeView<Renderable> otherObjectsView = mainWindow.getOtherObjectsView();
TreeView<Renderable> otherObjectsView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> otherObjectsRoot = new TreeItem<>(new AllOtherObjectsNode(model.getGenericCityObjects()));
otherObjectsRoot.setExpanded(true);
otherObjectsView.setRoot(otherObjectsRoot);
buildTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot(), otherObjectsChunkNr);
addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, otherObjectsChunkNr);
buildTreeFromList(model.getGenericCityObjects(), otherObjectsView.getRoot(), genericCityObjectsChunkNr);
addMoreButtonIfNecessary(model.getGenericCityObjects(), otherObjectsView, otherObjectsRoot, genericCityObjectsChunkNr);
}
private void buildWater(CityDoctorModel model) {
......@@ -282,7 +399,7 @@ public class CityDoctorController {
TreeItem<Renderable> transRoot = new TreeItem<>(new AllTransportationNode(model.getTransportation()));
transRoot.setExpanded(true);
transView.setRoot(transRoot);
buildTreeFromList(trans, transView.getRoot(), transportationChunkNr);
buildTransportationTreeFromList(trans, transView.getRoot());
addMoreButtonIfNecessary(trans, transView, transRoot, transportationChunkNr);
}
......@@ -426,7 +543,7 @@ public class CityDoctorController {
mainWindow.getWaterView().setRoot(null);
mainWindow.getTerrainView().setRoot(null);
mainWindow.getCityFurnitureView().setRoot(null);
mainWindow.getOtherObjectsView().setRoot(null);
mainWindow.getGenericCityObjectView().setRoot(null);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getAttributeView().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
......@@ -471,18 +588,251 @@ public class CityDoctorController {
root.getChildren().add(item);
createGeometryNodes(bridge, item);
createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item);
createBridgeRoomNodes(bridge, item);
createBridgeInstallationNodes(bridge, item);
createConstructiveElementsNodes(bridge, item);
createBridgeFurnitureNodes(bridge, item);
createBridgeConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item);
}
}
private void buildTransportationTreeFromList(List<TransportationObject> list, 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);
TransportationObjectNode node = new TransportationObjectNode(t);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(t, item);
createTransportSectionNodes(t, item);
createTrafficSpacesNodes(t, item);
}
}
private void buildVegetationTreeFromList(List<Vegetation> list, 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);
VegetationNode node = new VegetationNode(v);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(v, item);
}
}
private void buildWaterTreeFromList(List<WaterObject> list, 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);
CityObjectNode node = new CityObjectNode(w);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(w, item);
}
}
private void buildCityFurnitureTreeFromList(List<CityFurniture> list, 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);
CityObjectNode node = new CityObjectNode(cf);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(cf, item);
}
}
private void buildGenericCityObjectTreeFromList(List<GenericCityObject> list, 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);
CityObjectNode node = new CityObjectNode(goc);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(goc, item);
}
}
private void createTransportSectionNodes(TransportationObject t, TreeItem<Renderable> root) {
if (t instanceof TopLevelTransportFeature top) {
if (!top.getSections().isEmpty()) {
AllTransportSectionNode allSectionsNode = new AllTransportSectionNode(top.getSections(),
TransportSection.SectionType.SECTION);
TreeItem<Renderable> allSectionsNodeTextItem = new TreeItem<>(allSectionsNode);
root.getChildren().add(allSectionsNodeTextItem);
for (TransportSection ts : top.getSections()) {
TransportationObjectNode tsNode = new TransportationObjectNode(ts);
TreeItem<Renderable> tsNodeItem = new TreeItem<>(tsNode);
tsNodeItem.setExpanded(false);
allSectionsNodeTextItem.getChildren().add(tsNodeItem);
createGeometryNodes(ts, tsNodeItem);
createTrafficSpacesNodes(ts, tsNodeItem);
}
}
if (!top.getIntersections().isEmpty()) {
AllTransportSectionNode allIntersectionsNode = new AllTransportSectionNode(top.getIntersections(),
TransportSection.SectionType.INTERSECTION);
TreeItem<Renderable> allIntersectionsNodeTextItem = new TreeItem<>(allIntersectionsNode);
root.getChildren().add(allIntersectionsNodeTextItem);
for (TransportSection ts : top.getIntersections()) {
TransportationObjectNode tsNode = new TransportationObjectNode(ts);
TreeItem<Renderable> tsNodeItem = new TreeItem<>(tsNode);
tsNodeItem.setExpanded(false);
allIntersectionsNodeTextItem.getChildren().add(tsNodeItem);
createGeometryNodes(ts, tsNodeItem);
createTrafficSpacesNodes(ts, tsNodeItem);
}
}
}
}
private void createTrafficSpacesNodes(TransportationObject t, TreeItem<Renderable> root) {
if (t instanceof TransportationSpace space) {
if (!space.getTrafficSpaces().isEmpty()) {
AllTrafficSpacesNode allTSNode = new AllTrafficSpacesNode(space.getTrafficSpaces(),
TrafficSpaceObject.TrafficSpaceType.TRAFFIC_SPACE);
TreeItem<Renderable> allTSNodeTextItem = new TreeItem<>(allTSNode);
root.getChildren().add(allTSNodeTextItem);
allTSNodeTextItem.setExpanded(true);
for (TrafficSpaceObject tso : space.getTrafficSpaces()) {
TransportationObjectNode tsoNode = new TransportationObjectNode(tso);
TreeItem<Renderable> tsoNodeItem = new TreeItem<>(tsoNode);
tsoNodeItem.setExpanded(false);
allTSNodeTextItem.getChildren().add(tsoNodeItem);
createGeometryNodes(tso, tsoNodeItem);
createTrafficAreaNodes(tso, tsoNodeItem, TrafficAreaObject.TrafficAreaType.TRAFFIC_AREA);
}
}
if (!space.getAuxTrafficSpaces().isEmpty()) {
AllTrafficSpacesNode allTSNode = new AllTrafficSpacesNode(space.getAuxTrafficSpaces(),
TrafficSpaceObject.TrafficSpaceType.AUXILIARY_TRAFFIC_SPACE);
TreeItem<Renderable> allTSNodeTextItem = new TreeItem<>(allTSNode);
root.getChildren().add(allTSNodeTextItem);
allTSNodeTextItem.setExpanded(true);
for (TrafficSpaceObject atso : space.getAuxTrafficSpaces()) {
TransportationObjectNode atsoNode = new TransportationObjectNode(atso);
TreeItem<Renderable> atsoNodeItem = new TreeItem<>(atsoNode);
atsoNodeItem.setExpanded(false);
allTSNodeTextItem.getChildren().add(atsoNodeItem);
createGeometryNodes(atso, atsoNodeItem);
createTrafficAreaNodes(atso, atsoNodeItem, TrafficAreaObject.TrafficAreaType.AUXILIARY_TRAFFIC_AREA);
}
}
}
}
public void createTrafficAreaNodes(TransportationObject t, TreeItem<Renderable> root, TrafficAreaObject.TrafficAreaType type) {
if (t instanceof TrafficSpaceObject space && !space.getTrafficAreas().isEmpty()) {
AllTrafficAreaNode allTANode = new AllTrafficAreaNode(space.getTrafficAreas(), type);
TreeItem<Renderable> allTANodeTextItem = new TreeItem<>(allTANode);
root.getChildren().add(allTANodeTextItem);
allTANodeTextItem.setExpanded(true);
for (TrafficAreaObject tao : space.getTrafficAreas()) {
TransportationObjectNode taoNode = new TransportationObjectNode(tao);
TreeItem<Renderable> taoNodeTextItem = new TreeItem<>(taoNode);
taoNodeTextItem.setExpanded(true);
allTANodeTextItem.getChildren().add(taoNodeTextItem);
createGeometryNodes(tao, taoNodeTextItem);
}
}
}
private void buildTunnelTreeFromList(List<Tunnel> list, 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);
TunnelNode node = new TunnelNode(tunnel);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(tunnel, item);
createBoundarySurfaceNodes(tunnel.getBoundarySurfaces(), item);
createTunnelHollowNodes(tunnel, item);
createTunnelInstallationNodes(tunnel, item);
createTunnelFurnitureNodes(tunnel, item);
createTunnelConstructiveElementsNodes(tunnel, item);
createTunnelPartNodes(tunnel, item);
}
}
private void createTunnelInstallationNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createInstallationNodes(tunnel.getTunnelInstallations(), root);
}
private void createTunnelHollowNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createRoomNodes(tunnel.getTunnelHollows(), root);
}
private void createTunnelFurnitureNodes(Tunnel tunnel, TreeItem<Renderable> root) {
createFurnitureNodes(tunnel.getTunnelFurniture(), root);
}
private void createTunnelConstructiveElementsNodes(Tunnel tunnel, TreeItem<Renderable> root){
if (tunnel.getTunnelConstructiveElements().isEmpty()){
return;
}
AllTunnelConstructiveElementsNode allTceNode = new AllTunnelConstructiveElementsNode(tunnel.getTunnelConstructiveElements());
TreeItem<Renderable> allTceNodeTextItem = new TreeItem<>(allTceNode);
root.getChildren().add(allTceNodeTextItem);
for (TunnelConstructiveElement tce : tunnel.getTunnelConstructiveElements()) {
TunnelConstructiveElementNode tceNode = new TunnelConstructiveElementNode(tce);
TreeItem<Renderable> tceNodeItem = new TreeItem<>(tceNode);
tceNodeItem.setExpanded(true);
allTceNodeTextItem.getChildren().add(tceNodeItem);
createGeometryNodes(tce, tceNodeItem);
createBoundarySurfaceNodes(tce.getBoundarySurfaces(), tceNodeItem);
}
}
private void createTunnelPartNodes(Tunnel tunnel, TreeItem<Renderable> root) {
if (tunnel.getTunnelParts().isEmpty()) {
return;
}
AllTunnelPartsNode allTpsText = new AllTunnelPartsNode(tunnel.getTunnelParts());
TreeItem<Renderable> allTpsTextItem = new TreeItem<>(allTpsText);
root.getChildren().add(allTpsTextItem);
for (TunnelPart tp : tunnel.getTunnelParts()) {
TunnelPartNode tpNode = new TunnelPartNode(tp);
TreeItem<Renderable> tpNodeItem = new TreeItem<>(tpNode);
tpNodeItem.setExpanded(true);
allTpsTextItem.getChildren().add(tpNodeItem);
createGeometryNodes(tp, tpNodeItem);
createBoundarySurfaceNodes(tp.getBoundarySurfaces(), tpNodeItem);
}
}
private void createBridgeRoomNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createRoomNodes(bridge.getBridgeRooms(), root);
}
private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createInstallationNodes(bridge.getBridgeInstallations(), root);
}
private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
private void createBridgeFurnitureNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createFurnitureNodes(bridge.getBridgeFurniture(), root);
}
private void createBridgeConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getConstructiveElements().isEmpty()) {
return;
}
......@@ -493,11 +843,11 @@ public class CityDoctorController {
for (BridgeConstructiveElement bce : bridge.getConstructiveElements()) {
BridgeConstructiveElementNode bceNode = new BridgeConstructiveElementNode(bce);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bceNode);
bpNodeItem.setExpanded(true);
allBceNodeTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bce, bpNodeItem);
createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bpNodeItem);
TreeItem<Renderable> bceNodeItem = new TreeItem<>(bceNode);
bceNodeItem.setExpanded(true);
allBceNodeTextItem.getChildren().add(bceNodeItem);
createGeometryNodes(bce, bceNodeItem);
createBoundarySurfaceNodes(bce.getBoundarySurfaces(), bceNodeItem);
}
}
......@@ -709,6 +1059,9 @@ public class CityDoctorController {
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
currentChecker = new Checker(config, model);
if (previousCheckers != null) {
previousCheckers.put(model, currentChecker);
}
currentChecker.runChecks(l);
Platform.runLater(() -> {
......@@ -728,6 +1081,136 @@ public class CityDoctorController {
}
}
public void startZipFileChecks(ValidationConfiguration config, ProgressListener l, boolean lowMemoryMode,
Path outputPath, boolean pdfReports, boolean xmlReports) {
if (zipArchive == null) {
logger.warn(Localization.getText("CityDoctorController.noZipFile"));
}
if (lowMemoryMode) {
startZipFileCheckStream(config, outputPath, pdfReports, xmlReports);
return;
}
try {
Platform.runLater(() -> {
mainWindow.getCheckButton().setDisable(true);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
});
previousCheckers = new HashMap<>();
zipArchive.mountArchive(currentConfig);
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
int totalEntries = zipArchive.getEntries().size();
int checkedEntries = 0;
for (CityGmlZipEntry entry : zipArchive.getEntries()) {
if (entry.getErrorType() != null && entry.getModel() == null) {
continue;
}
model = entry.getModel();
currentChecker = new Checker(config, model);
currentChecker.runChecks();
previousCheckers.put(model, currentChecker);
checkedEntries++;
if (l != null) {
l.updateProgress((float) checkedEntries / totalEntries);
}
}
Platform.runLater(() -> {
// apply check results to tree views
updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) {
if (e instanceof SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString());
}
}
renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false);
currentZipEntryManager.refresh();
});
} finally {
Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false));
}
}
private void startZipFileCheckStream(ValidationConfiguration valConfig, Path outputPath, boolean pdfReports,
boolean xmlReports) {
try {
Path outputZipDirectory = null;
if (outputPath.toFile().isDirectory()) {
String filename = FilenameUtils.removeExtension(zipArchive.getArchivePath().getFileName().toString());
filename = filename + "_validated";
outputZipDirectory = outputPath.resolve(filename);
Files.createDirectories(outputZipDirectory);
} else {
String filename = FilenameUtils.removeExtension(outputPath.toAbsolutePath().getFileName().toString());
outputZipDirectory = Path.of(filename);
}
String xmlReportsDirectory = null;
String pdfReportsDirectory = null;
if (xmlReports) {
xmlReportsDirectory = Files.createDirectories(
outputZipDirectory.resolve("xml_reports/")).toAbsolutePath().toString();
}
if (pdfReports) {
pdfReportsDirectory = Files.createDirectories(
outputZipDirectory.resolve("pdf_reports/")).toAbsolutePath().toString();
}
Checker.streamCheck(zipArchive, xmlReportsDirectory, pdfReportsDirectory, valConfig, outputZipDirectory.toString());
Desktop desktop = Desktop.getDesktop();
desktop.open(outputPath.toFile());
} catch (CityGmlParseException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void saveZipArchiveReports(File outputZipDirectory) {
if (zipArchive == null) {
return;
}
String directoryName = FilenameUtils.removeExtension(outputZipDirectory.getAbsolutePath());
Path tempOutput = Path.of(directoryName + File.separator);
File temp = null;
try {
temp = tempOutput.toFile();
for (CityGmlZipEntry entry : zipArchive.getEntries()) {
if (entry.getErrorType() != null || entry.getModel() == null) {
continue;
}
model = entry.getModel();
if (model.isValidated()) {
Checker checker = previousCheckers.get(model);
Files.createDirectories(tempOutput.resolve(entry.getEntrySubPath()).getParent());
checker.writeXmlReport(tempOutput.resolve(entry.getDisplayName() + "_report.xml").toString());
checker.writePdfReport(tempOutput.resolve(entry.getDisplayName() + "_report.pdf").toString());
}
}
ArchivePacker.packAndDeleteDirectory(tempOutput.toString());
temp = null;
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Export Report");
alert.setContentText(Localization.getText("CityDoctorController.saveZipArchiveReports"));
alert.showAndWait();
} catch (IOException e) {
logger.error(e);
} finally {
try {
if (temp != null) {
FileUtils.deleteDirectory(temp);
}
} catch (IOException e) {
logger.error(e);
}
}
}
void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().getRoot());
......@@ -736,7 +1219,8 @@ public class CityDoctorController {
updateTree(mainWindow.getCityFurnitureView().getRoot());
updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot());
updateTree(mainWindow.getOtherObjectsView().getRoot());
updateTree(mainWindow.getGenericCityObjectView().getRoot());
updateTree(mainWindow.getTunnelView().getRoot());
renderer.updateErrors();
}
......@@ -798,13 +1282,15 @@ public class CityDoctorController {
}
}
public void export(Building b) {
public void export(CityObject co) {
if (model == null) {
return;
}
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
newModel.setCityModel(new CityModel());
newModel.addBuilding(b);
newModel.addCityObject(co);
newModel.setParsedCityGMLVersion(model.getCityGMLVersion());
newModel.getCityModel().setBoundedBy(model.getCityModel().getBoundedBy());
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
......@@ -819,7 +1305,6 @@ public class CityDoctorController {
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
newModel.saveAs(f.getAbsolutePath(), true);
} catch (CityDoctorWriteException e) {
logger.error(e);
......@@ -830,6 +1315,7 @@ public class CityDoctorController {
public void showWorld() {
if (model != null) {
renderer.render(model);
resetSearch(mainWindow.getSelectedTab());
}
}
......@@ -846,68 +1332,105 @@ public class CityDoctorController {
}
mainWindow.unselectEverything();
resetFeatureChunks();
if (selectedTab == FeatureType.BUILDING) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
root.getChildren().clear();
buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
} else {
TreeView<Renderable> view;
List<? extends CityObject> cos;
AtomicInteger chunkCounter;
switch (selectedTab) {
case VEGETATION:
view = mainWindow.getVegetationView();
cos = filterFeatures(searchString, model.getVegetation());
chunkCounter = vegetationChunkNr;
break;
case BRIDGE:
view = mainWindow.getBridgeView();
cos = filterFeatures(searchString, model.getBridges());
chunkCounter = bridgeChunkNr;
break;
case TRANSPORTATION:
view = mainWindow.getTransportationView();
cos = filterFeatures(searchString, model.getTransportation());
chunkCounter = transportationChunkNr;
break;
case TUNNEL:
view = mainWindow.getTunnelView();
cos = model.getTunnels();
chunkCounter = tunnelChunkNr;
break;
case WATER:
view = mainWindow.getWaterView();
cos = filterFeatures(searchString, model.getWater());
chunkCounter = waterChunkNr;
break;
case LAND:
view = mainWindow.getTerrainView();
cos = filterFeatures(searchString, model.getLand());
chunkCounter = landChunkNr;
break;
case CITY_FURNITURE:
view = mainWindow.getCityFurnitureView();
cos = filterFeatures(searchString, model.getCityFurniture());
chunkCounter = cityFurnitureChunkNr;
break;
case GENERIC_CITY_OBJECT:
view = mainWindow.getOtherObjectsView();
cos = filterFeatures(searchString, model.getGenericCityObjects());
chunkCounter = otherObjectsChunkNr;
break;
default:
throw new IllegalStateException("Unknown selected feature tab");
}
TreeItem<Renderable> root = view.getRoot();
root.getChildren().clear();
buildTreeFromList(cos, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(cos, view, root, chunkCounter);
switch (selectedTab) {
case BUILDING -> filterBuildingTree(searchString);
case BRIDGE -> filterBridgeTree(searchString);
case TUNNEL -> filterTunnelTree(searchString);
case VEGETATION -> filterVegetationTree(searchString);
case TRANSPORTATION -> filterTransportationTree(searchString);
case WATER -> filterWaterTree(searchString);
case LAND -> filterLandTree(searchString);
case CITY_FURNITURE -> filterCityFurnitureTree(searchString);
case GENERIC_CITY_OBJECT -> filterGenericCityObjectTree(searchString);
}
}
private void filterBuildingTree(String searchString) {
List<Building> foundBuildings = filterFeatures(searchString, model.getBuildings());
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
root.getChildren().clear();
buildBuildingTreeFromList(foundBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(foundBuildings, buildingsView, root, buildingChunkNr);
}
private void filterBridgeTree(String searchString) {
List<BridgeObject> foundBridges = filterFeatures(searchString, model.getBridges());
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> root = bridgeView.getRoot();
root.getChildren().clear();
buildBridgeTreeFromList(foundBridges, root);
updateTree(root);
addMoreButtonIfNecessary(foundBridges, bridgeView, root, bridgeChunkNr);
}
private void filterTunnelTree(String searchString) {
List<Tunnel> foundTunnel = filterFeatures(searchString, model.getTunnels());
TreeView<Renderable> tunnelView = mainWindow.getTunnelView();
TreeItem<Renderable> root = tunnelView.getRoot();
root.getChildren().clear();
buildTunnelTreeFromList(foundTunnel, root);
updateTree(root);
addMoreButtonIfNecessary(foundTunnel, tunnelView, root, tunnelChunkNr);
}
private void filterVegetationTree(String searchString) {
List<Vegetation> foundVegetation = filterFeatures(searchString, model.getVegetation());
TreeView<Renderable> vegetationView = mainWindow.getVegetationView();
TreeItem<Renderable> root = vegetationView.getRoot();
root.getChildren().clear();
buildVegetationTreeFromList(foundVegetation, root);
updateTree(root);
addMoreButtonIfNecessary(foundVegetation, vegetationView, root, vegetationChunkNr);
}
private void filterTransportationTree(String searchString) {
List<TransportationObject> foundTransportation = filterFeatures(searchString, model.getTransportation());
TreeView<Renderable> transportationView = mainWindow.getTransportationView();
TreeItem<Renderable> root = transportationView.getRoot();
root.getChildren().clear();
buildTransportationTreeFromList(foundTransportation, root);
updateTree(root);
addMoreButtonIfNecessary(foundTransportation, transportationView, root, transportationChunkNr);
}
private void filterWaterTree(String searchString) {
List<WaterObject> foundWater = filterFeatures(searchString, model.getWater());
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> root = waterView.getRoot();
root.getChildren().clear();
buildWaterTreeFromList(foundWater, root);
addMoreButtonIfNecessary(foundWater, waterView, root, waterChunkNr);
}
private void filterLandTree(String searchString) {
List<CityObject> foundLand = filterFeatures(searchString, model.getLand());
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> root = landView.getRoot();
root.getChildren().clear();
buildLandFromList(foundLand, root);
addMoreButtonIfNecessary(foundLand, landView, root, landChunkNr);
}
private void filterCityFurnitureTree(String searchString) {
List<CityFurniture> foundCityFurniture = filterFeatures(searchString, model.getCityFurniture());
TreeView<Renderable> cityFurnitureView = mainWindow.getCityFurnitureView();
TreeItem<Renderable> root = cityFurnitureView.getRoot();
root.getChildren().clear();
buildCityFurnitureTreeFromList(foundCityFurniture, root);
addMoreButtonIfNecessary(foundCityFurniture, cityFurnitureView, root, cityFurnitureChunkNr);
}
private void filterGenericCityObjectTree(String searchString) {
List<GenericCityObject> foundGenericCityObject = filterFeatures(searchString, model.getGenericCityObjects());
TreeView<Renderable> genericCityObjectView = mainWindow.getGenericCityObjectView();
TreeItem<Renderable> root = genericCityObjectView.getRoot();
root.getChildren().clear();
buildGenericCityObjectTreeFromList(foundGenericCityObject, root);
addMoreButtonIfNecessary(foundGenericCityObject, genericCityObjectView, root, genericCityObjectsChunkNr);
}
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
......@@ -924,72 +1447,7 @@ public class CityDoctorController {
if (model == null) {
return;
}
resetFeatureChunks();
if (selectedTab == FeatureType.BUILDING) {
// buildings are handled differently, because of surface and building
// installations
TreeItem<Renderable> root = mainWindow.getBuildingsView().getRoot();
if (root != null) {
root.getChildren().clear();
buildBuildingTreeFromList(model.getBuildings(), root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), mainWindow.getBuildingsView(), root,
buildingChunkNr);
}
} else {
TreeView<Renderable> view;
List<? extends CityObject> cos;
AtomicInteger chunkCounter;
switch (selectedTab) {
case VEGETATION:
view = mainWindow.getVegetationView();
cos = model.getVegetation();
chunkCounter = vegetationChunkNr;
break;
case BRIDGE:
view = mainWindow.getBridgeView();
cos = model.getBridges();
chunkCounter = bridgeChunkNr;
break;
case TRANSPORTATION:
view = mainWindow.getTransportationView();
cos = model.getTransportation();
chunkCounter = transportationChunkNr;
break;
case TUNNEL:
view = mainWindow.getTunnelView();
cos = model.getTunnels();
chunkCounter = tunnelChunkNr;
break;
case WATER:
view = mainWindow.getWaterView();
cos = model.getWater();
chunkCounter = waterChunkNr;
break;
case LAND:
view = mainWindow.getTerrainView();
cos = model.getLand();
chunkCounter = landChunkNr;
break;
case CITY_FURNITURE:
view = mainWindow.getCityFurnitureView();
cos = model.getCityFurniture();
chunkCounter = cityFurnitureChunkNr;
break;
case GENERIC_CITY_OBJECT:
view = mainWindow.getOtherObjectsView();
cos = model.getGenericCityObjects();
chunkCounter = otherObjectsChunkNr;
break;
default:
throw new IllegalStateException("Unknown selected feature tab");
}
TreeItem<Renderable> root = view.getRoot();
root.getChildren().clear();
buildTreeFromList(cos, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(cos, view, root, chunkCounter);
}
buildTrees();
}
public Series<String, Number> createErrorSeries() {
......@@ -1060,12 +1518,12 @@ public class CityDoctorController {
model.getCityFurniture(), cityFurnitureChunkNr);
}
public void fillTreeViewWithErrorOtherObjects() {
public void fillTreeViewWithErrorGenericCityObjects() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getOtherObjectsView(),
model.getGenericCityObjects(), otherObjectsChunkNr);
fillTreeViewWithErrorCityObjects(mainWindow.getGenericCityObjectView(),
model.getGenericCityObjects(), genericCityObjectsChunkNr);
}
public void fillTreeViewWithErrorTransportation() {
......@@ -1135,7 +1593,12 @@ public class CityDoctorController {
buildTransportation(model.getTransportation());
updateTree(mainWindow.getTransportationView().getRoot());
break;
case TUNNEL:
buildTunnel(model.getTunnels());
updateTree(mainWindow.getTunnelView().getRoot());
break;
case WATER:
buildWater(model);
updateTree(mainWindow.getWaterView().getRoot());
break;
......@@ -1145,7 +1608,7 @@ public class CityDoctorController {
break;
case GENERIC_CITY_OBJECT:
buildOtherCityObjects(model);
updateTree(mainWindow.getOtherObjectsView().getRoot());
updateTree(mainWindow.getGenericCityObjectView().getRoot());
break;
default:
throw new IllegalStateException();
......@@ -1239,7 +1702,7 @@ public class CityDoctorController {
fillTreeViewWithErrorCityFurniture();
break;
case GENERIC_CITY_OBJECT:
fillTreeViewWithErrorOtherObjects();
fillTreeViewWithErrorGenericCityObjects();
break;
default:
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab());
......
......@@ -43,6 +43,7 @@ import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
import javafx.scene.paint.Color;
public class ListErrorVisitor implements ErrorVisitor {
......@@ -171,7 +172,11 @@ public class ListErrorVisitor implements ErrorVisitor {
@Override
public void visit(SolidSelfIntError err) {
// nothing to display for now
controller.clearHighlights();
for (PolygonIntersection intersection : err.getIntersections()) {
controller.addHighlight(intersection.getP1(), geom);
controller.addHighlight(intersection.getP2(), geom);
}
}
@Override
......@@ -208,22 +213,22 @@ public class ListErrorVisitor implements ErrorVisitor {
@Override
public void visit(NotCeilingError err) {
// nothing to display
controller.highlight(err.getPolygon(), geom);
}
@Override
public void visit(NotFloorError err) {
// nothing to display
controller.highlight(err.getPolygon(), geom);
}
@Override
public void visit(NotWallError err) {
// nothing to display
controller.highlight(err.getPolygon(), geom);
}
@Override
public void visit(NotGroundError err) {
// nothing to display
controller.highlight(err.getPolygon(), geom);
}
@Override
......
......@@ -85,6 +85,12 @@ public class MainToolBar {
@FXML
private ImageView lod4View;
@FXML
private Button zipManagerBtn;
@FXML
private ImageView zipManagerView;
@FXML
private Button aboutBtn;
......@@ -147,6 +153,7 @@ public class MainToolBar {
setupReportButton();
setupResetCameraButton();
setupHideRoofButton();
setupZipManagerButton();
loadImages();
gridButton.setOnAction(ae -> renderer.showWireFrame(gridButton.isSelected()));
......@@ -162,6 +169,7 @@ public class MainToolBar {
content.getSelectionModel().clearSelection();
}
controller.showWorld();
mainWindow.resetSearchBar();
});
showWorldBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.showWorld")));
}
......@@ -224,6 +232,10 @@ public class MainToolBar {
Image img = new Image(inStream);
hideRoofView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/zip.png")) {
Image img = new Image(inStream);
zipManagerView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
......@@ -335,6 +347,14 @@ public class MainToolBar {
}
private void setupZipManagerButton() {
zipManagerBtn.setDisable(true);
zipManagerBtn.setTooltip(new Tooltip(Localization.getText("MainToolBar.zip")));
zipManagerBtn.setOnAction(ae -> {
mainWindow.showZipManager();
});
}
public Button getCheckButton() {
return checkBtn;
}
......@@ -387,6 +407,10 @@ public class MainToolBar {
return resetCameraBtn;
}
public Button getZipManagerBtn() {
return zipManagerBtn;
}
public HBox getToolBar() {
return toolBar;
}
......
......@@ -3,9 +3,10 @@ package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.CityDoctorValidation;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.BoundingBox;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.gui.logger.GuiLogger;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingNode;
import de.hft.stuttgart.citydoctor2.gui.tree.FeatureNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.RenderableTreeCell;
import de.hft.stuttgart.citydoctor2.parameter.ArgumentParser;
......@@ -13,6 +14,7 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.Pair;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
......@@ -25,10 +27,7 @@ import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.input.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
......@@ -46,6 +45,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import static javafx.scene.input.Clipboard.getSystemClipboard;
public class MainWindow extends Application {
private static final Logger logger = LogManager.getLogger(MainWindow.class);
......@@ -301,7 +302,7 @@ public class MainWindow extends Application {
BorderPane bp = loader.load();
highlightController = new HighlightController(world);
renderer = new Renderer(this, highlightController);
clickHandler = new VertexClickHandler(errorView, renderer, stage);
clickHandler = new VertexClickHandler(errorView, renderer, stage, this);
controller = new CityDoctorController(this, highlightController, renderer);
mainToolBar = new MainToolBar(stage, controller, featurePane, renderer, this);
viewPane.getChildren().add(mainToolBar.getToolBar());
......@@ -727,77 +728,105 @@ public class MainWindow extends Application {
}
private void setupTrees() {
setupTreeRoot(errorView);
setupSelectListener(errorView);
errorView.setRoot(new TreeItem<>());
errorView.setCellFactory(param -> new RenderableTreeCell());
buildingsView.setShowRoot(true);
setupTreeRoot(buildingsView);
setupSelectListener(buildingsView);
buildingsView.setCellFactory(param -> new RenderableTreeCell());
ContextMenu cMenu = new ContextMenu();
MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
mi.setOnAction(ea -> {
Renderable render = buildingsView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof BuildingNode node) {
controller.export(node.getBuilding());
}
});
cMenu.getItems().add(mi);
MenuItem deleteMi = new MenuItem("Delete");
deleteMi.setOnAction(ae -> controller.delete(buildingsView.getSelectionModel().getSelectedItem()));
cMenu.getItems().add(deleteMi);
setupFeatureTabContextMenu(buildingsView);
buildingsView.setContextMenu(cMenu);
vegetationView.setShowRoot(true);
setupTreeRoot(vegetationView);
setupSelectListener(vegetationView);
vegetationView.setCellFactory(param -> new RenderableTreeCell());
vegetationView.setContextMenu(cMenu);
setupFeatureTabContextMenu(vegetationView);
transView.setShowRoot(true);
setupTreeRoot(transView);
setupSelectListener(transView);
transView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(transView);
tunnelView.setShowRoot(true);
setupTreeRoot(tunnelView);
setupSelectListener(tunnelView);
tunnelView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(tunnelView);
bridgeView.setShowRoot(true);
setupTreeRoot(bridgeView);
setupSelectListener(bridgeView);
bridgeView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(bridgeView);
waterView.setShowRoot(true);
setupTreeRoot(waterView);
setupSelectListener(waterView);
waterView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(waterView);
terrainView.setShowRoot(true);
setupTreeRoot(terrainView);
setupSelectListener(terrainView);
terrainView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(terrainView);
cityFurnitureView.setShowRoot(true);
setupTreeRoot(cityFurnitureView);
setupSelectListener(cityFurnitureView);
cityFurnitureView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(cityFurnitureView);
otherObjectsView.setShowRoot(true);
setupTreeRoot(otherObjectsView);
setupSelectListener(otherObjectsView);
otherObjectsView.setCellFactory(param -> new RenderableTreeCell());
setupFeatureTabContextMenu(otherObjectsView);
setupTreeRoot(vertexView);
setupSelectListener(vertexView);
vertexView.setRoot(new TreeItem<>());
vertexView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(polygonView);
setupSelectListener(polygonView);
polygonView.setRoot(new TreeItem<>());
polygonView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(edgeView);
setupSelectListener(edgeView);
edgeView.setRoot(new TreeItem<>());
edgeView.setCellFactory(param -> new RenderableTreeCell());
setupTreeRoot(attributeView);
setupSelectListener(attributeView);
attributeView.setRoot(new TreeItem<>());
attributeView.setCellFactory(param -> new RenderableTreeCell());
}
private void setupTreeRoot(TreeView<Renderable> tView){
tView.setRoot(new TreeItem<>());
tView.setCellFactory(param -> new RenderableTreeCell());
}
private void setupFeatureTabContextMenu(TreeView<Renderable> featureView) {
ContextMenu menu = new ContextMenu();
MenuItem mi = new MenuItem(Localization.getText("MainWindow.export"));
mi.setOnAction(ea -> {
Renderable render = featureView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof FeatureNode node) {
try {
controller.export(node.getFeature());
logger.info(Localization.getText("CityDoctorController.exportSuccess"));
} catch (Exception e) {
logger.error("Export failed: Unexpected error occurred");
logger.error(e);
}
} else {
logger.info(Localization.getText("MainWindow.infoTopLevelExport"));
}
});
menu.getItems().add(mi);
MenuItem clipMi = new MenuItem(Localization.getText("MainWindow.copyId"));
clipMi.setOnAction(ea -> {
Renderable render = featureView.getSelectionModel().getSelectedItem().getValue();
if (render instanceof FeatureNode node) {
Clipboard clipboard = getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(node.getFeature().getGmlId().toString());
if (!clipboard.setContent(content)) {
logger.warn(Localization.getText("MainWindow.warnCopyIdFailed"));
}
} else {
logger.info(Localization.getText("MainWindow.infoTopLevelCopyID"));
}
});
menu.getItems().add(clipMi);
MenuItem deleteMi = new MenuItem(Localization.getText("MainWindow.delete"));
deleteMi.setOnAction(ae -> controller.delete(featureView.getSelectionModel().getSelectedItem()));
menu.getItems().add(deleteMi);
featureView.setContextMenu(menu);
}
private void setupSelectListener(TreeView<Renderable> view) {
......@@ -995,7 +1024,7 @@ public class MainWindow extends Application {
return attributeView;
}
public TreeView<Renderable> getOtherObjectsView() {
public TreeView<Renderable> getGenericCityObjectView() {
return otherObjectsView;
}
......@@ -1118,6 +1147,43 @@ public class MainWindow extends Application {
controller.setOriginBB(b);
}
public void showCityObjectDetail(CityObject co) {
Pair<Tab, TreeView<Renderable>> tabPair = getFeatureTabOf(co);
Tab featureTab = tabPair.getValue0();
TreeView<Renderable> featureView = tabPair.getValue1();
featurePane.getSelectionModel().select(featureTab);
searchField.setText(co.getGmlId().getGmlString());
searchBtn.fire();
featureView.getSelectionModel().select(0);
featureView.getSelectionModel().getSelectedItem().getValue().visit(renderer);
}
private Pair<Tab,TreeView<Renderable>> getFeatureTabOf(CityObject co) {
FeatureType coType = co.getFeatureType();
if (coType == FeatureType.BUILDING){
return new Pair<>(buildingsTab, buildingsView);
} else if (coType == FeatureType.VEGETATION){
return new Pair<>(vegetationTab, vegetationView);
} else if (coType == FeatureType.TRANSPORTATION){
return new Pair<>(transportationTab,transView);
} else if (coType == FeatureType.TUNNEL){
return new Pair<>(tunnelTab, tunnelView);
} else if (coType == FeatureType.BRIDGE){
return new Pair<>(bridgeTab, bridgeView);
} else if (coType == FeatureType.WATER){
return new Pair<>(waterTab, waterView);
} else if (coType == FeatureType.LAND){
return new Pair<>(terrainTab, terrainView);
} else if (coType == FeatureType.CITY_FURNITURE){
return new Pair<>(cityFurnitureTab, cityFurnitureView);
} else if (coType == FeatureType.GENERIC_CITY_OBJECT){
return new Pair<>(otherObjectsTab, otherObjectsView);
} else {
throw new IllegalArgumentException("unknown feature type: " + coType);
}
}
public MainToolBar getMainToolbar() {
return mainToolBar;
}
......@@ -1134,6 +1200,14 @@ public class MainWindow extends Application {
return mainToolBar.getOpenBtn();
}
public void showZipManager() {
controller.showZipManager();
}
public Button getZipManagerBtn() {
return mainToolBar.getZipManagerBtn();
}
public VertexClickHandler getClickHandler() {
return clickHandler;
}
......
......@@ -120,7 +120,7 @@ public class OpenFileDialog {
if (fc == null) {
fc = new FileChooser();
fc.setTitle(Localization.getText("OpenFileDialog.select"));
fc.getExtensionFilters().add(new ExtensionFilter("GML/XML", "*.gml", "*.xml"));
fc.getExtensionFilters().add(new ExtensionFilter("GML/XML/ZIP", "*.gml", "*.xml", "*.zip"));
fc.getExtensionFilters().add(new ExtensionFilter(Localization.getText("MainWindow.all"), "*.*"));
}
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
......@@ -150,8 +150,12 @@ public class OpenFileDialog {
pathField.setDisable(true);
selectBtn.setDisable(true);
stage.setOnCloseRequest(Event::consume);
Thread t = new Thread(() -> {
try {
if (path.endsWith(".zip")) {
Platform.runLater(() -> progress.setProgress(-1));
}
controller.loadCityGml(path, numberOfRoundingPlaces, progress::setProgress, useValidation,
lowMemory);
Platform.runLater(() -> stage.close());
......
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