Commit 97a65114 authored by Riegel's avatar Riegel
Browse files

Merge branch 'dev' into 'master'

Version 3.15.0

See merge request !8
parents 99c8f6a8 5950ea5f
Pipeline #10106 passed with stage
in 3 minutes and 15 seconds
#!/bin/sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/lin</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.sh</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
<fileSet>
<directory>${project.build.directory}/jre/jre-mac/runtime/${mac-jre}/
</directory>
<outputDirectory>/runtime</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/no_runtime</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.bat</include>
<include>start.sh</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
java -classpath app/*;plugins/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
pause
\ No newline at end of file
#!/bin/sh
java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>zip</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>app</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/win</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>start.bat</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/assembly/common</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>checkForSolid.xml</include>
</includes>
<filtered>false</filtered>
</fileSet>
<fileSet>
<directory>${project.build.directory}/jre/jre-win/runtime/${win-jre}/
</directory>
<outputDirectory>/runtime</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<filtered>false</filtered>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
"runtime/bin/java.exe" -classpath app/*;plugins/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
pause
\ No newline at end of file
package de.hft.stuttgart.citydoctor2.gui;
import java.io.IOException;
import java.io.InputStream;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
public class AboutDialog {
@FXML
private ImageView logoView;
@FXML
private ImageView beuthView;
@FXML
private ImageView minisView;
@FXML
private ImageView hftView;
@FXML
private Button closeBtn;
@FXML
private Label cdLabel;
private Stage stage;
public AboutDialog(Window parent) throws IOException {
FXMLLoader loader = new FXMLLoader(AboutDialog.class.getResource("AboutDialog.fxml"));
loader.setController(this);
VBox box = loader.load();
stage = new Stage(StageStyle.UTILITY);
stage.setTitle(Localization.getText("AboutDialog.title"));
stage.setResizable(false);
Scene scene = new Scene(box);
stage.setScene(scene);
stage.initOwner(parent);
stage.initModality(Modality.APPLICATION_MODAL);
}
public void initialize() {
String developedBy = Localization.getText("AboutDialog.developedBy");
String contact = Localization.getText("AboutDialog.contact");
closeBtn.setText(Localization.getText("AboutDialog.closeBtn"));
cdLabel.setText("CityDoctor Version " + Localization.getText(Localization.VERSION) + "\n\n" +
developedBy + ":\n" +
"Hochschule für Technik\n" +
"Beuth Hochschule Berlin\n\n" +
contact + ":\n" +
"Matthias Betz\n" +
"matthias.betz@hft-stuttgart.de");
closeBtn.setOnAction(ae -> hide());
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.png")) {
Image img = new Image(inStream);
logoView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/hft_logo.png")) {
Image img = new Image(inStream);
hftView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Beuth-Logo_basis.png")) {
Image img = new Image(inStream);
beuthView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/BMBF_Logo.png")) {
Image img = new Image(inStream);
minisView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
}
public void show() {
stage.show();
}
public void hide() {
stage.hide();
}
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.hft.stuttgart.citydoctor2.check.DefaultParameter;
import de.hft.stuttgart.citydoctor2.check.FilterConfiguration;
import de.hft.stuttgart.citydoctor2.check.GlobalParameters;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementConfiguration;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.Unit;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.gui.tree.TreeRequirement;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.application.Platform;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.CheckBoxTreeTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.StringConverter;
import javafx.util.converter.DefaultStringConverter;
public class CheckDialog {
private static final String NUMBER_OF_ROUNDING_PLACES = "numberOfRoundingPlaces";
private static final Logger logger = LogManager.getLogger(CheckDialog.class);
private static final String CHECK_ENABLED = Localization.getText("CheckDialog.checkEnabled");
private static final String NAME = Localization.getText("CheckDialog.checkName");
private static final String VALUE = Localization.getText("CheckDialog.parameterValue");
private static final String UNIT = Localization.getText("CheckDialog.parameterUnit");
private Stage stage;
@FXML
private TreeTableView<TreeRequirement> geometricTable;
@FXML
private TreeTableView<TreeRequirement> semanticTable;
@FXML
private TableView<GlobalParameter> globalParametersTable;
@FXML
private ScrollPane scrollPane;
@FXML
private Button cancelBtn;
@FXML
private Button checkBtn;
@FXML
private ProgressBar progress;
@FXML
private Tab filterTab;
@FXML
private TabPane tabPane;
@FXML
private Button loadBtn;
@FXML
private ImageView loadView;
@FXML
private Button saveBtn;
@FXML
private ImageView saveView;
@FXML
private Button selectBtn;
@FXML
private TextField schematronField;
@FXML
private Tab checksTab;
@FXML
private Label globalParametersLabel;
@FXML
private Label availableChecksLabel;
@FXML
private Label geometricChecksLabel;
@FXML
private Label semanticChecksLabel;
@FXML
private Label schematronFileLabel;
private CityDoctorController controller;
private FilterPane filterPane;
private MainWindow window;
public CheckDialog(MainWindow window, Window parent, CityDoctorController controller) throws IOException {
this.window = window;
this.controller = controller;
FXMLLoader loader = new FXMLLoader(CheckDialog.class.getResource("CheckDialog.fxml"));
loader.setController(this);
VBox box = loader.load();
stage = new Stage();
stage.getIcons().add(new Image(MainWindow.class.getResourceAsStream("icons/CityDoctor-Logo-rot_klein.jpg")));
Scene scene = new Scene(box);
stage.setScene(scene);
stage.initOwner(parent);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(Localization.getText("CheckDialog.title"));
}
public void initialize() {
createEnableColumn(geometricTable);
createNameColumn(geometricTable);
createValueColumn(geometricTable);
createUnitColumn(geometricTable);
createEnableColumn(semanticTable);
createNameColumn(semanticTable);
createValueColumn(semanticTable);
createUnitColumn(semanticTable);
checksTab.setText(Localization.getText("CheckDialog.checksTab"));
filterTab.setText(Localization.getText("CheckDialog.filterTab"));
globalParametersLabel.setText(Localization.getText("CheckDialog.globalParametersLabel"));
availableChecksLabel.setText(Localization.getText("CheckDialog.availableChecksLabel"));
geometricChecksLabel.setText(Localization.getText("CheckDialog.geometricChecksLabel"));
semanticChecksLabel.setText(Localization.getText("CheckDialog.semanticChecksLabel"));
schematronFileLabel.setText(Localization.getText("CheckDialog.schematronFileLabel"));
selectBtn.setText(Localization.getText("CheckDialog.selectBtn"));
checkBtn.setText(Localization.getText("CheckDialog.checkBtn"));
cancelBtn.setText(Localization.getText("CheckDialog.cancelBtn"));
List<TableColumn<GlobalParameter, ?>> columns = globalParametersTable.getColumns();
TableColumn<GlobalParameter, String> nameCol = new TableColumn<>(NAME);
columns.add(nameCol);
nameCol.setMinWidth(200);
nameCol.setPrefWidth(325);
nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
setupValueColumns(columns);
TableColumn<GlobalParameter, Unit> unitCol = new TableColumn<>(UNIT);
columns.add(unitCol);
unitCol.setMinWidth(50);
unitCol.setPrefWidth(75);
unitCol.setMaxWidth(100);
unitCol.setEditable(false);
unitCol.setCellValueFactory(new PropertyValueFactory<>("unit"));
unitCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Unit>() {
@Override
public String toString(Unit object) {
return object.getRepresentation();
}
@Override
public Unit fromString(String string) {
return Unit.valueOf(string);
}
}));
loadImages();
setupSelectButton();
setupSaveButton();
setupLoadButton();
populateTreeWithChecks(geometricTable, RequirementType.GEOMETRY, true);
populateTreeWithChecks(semanticTable, RequirementType.SEMANTIC, false);
globalParametersTable.getItems().add(new GlobalParameter(NUMBER_OF_ROUNDING_PLACES, "8", Unit.NONE));
globalParametersTable.getItems().add(new GlobalParameter("minVertexDistance", "0.0001", Unit.METER));
cancelBtn.setOnAction(ea -> stage.close());
setupCheckButton();
tabPane.getSelectionModel().selectedIndexProperty().addListener((v, old, newV) -> {
if (newV.intValue() == 1 && filterPane == null) {
try {
getFilterPane();
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
schematronField.setText(ValidationConfiguration.CHECK_FOR_SOLID_XML);
}
private void setupValueColumns(List<TableColumn<GlobalParameter, ?>> columns) {
TableColumn<GlobalParameter, String> valueCol = new TableColumn<>(VALUE);
columns.add(valueCol);
valueCol.setMinWidth(150);
valueCol.setPrefWidth(200);
valueCol.setEditable(true);
valueCol.setCellValueFactory(new PropertyValueFactory<>("value"));
valueCol.setCellFactory(column -> new TableEditCell<GlobalParameter, String>(new DefaultStringConverter()) {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
GlobalParameter row = (GlobalParameter) getTableRow().getItem();
if (row == null) {
return;
}
row.setValue(item);
if (NUMBER_OF_ROUNDING_PLACES.equals(row.getName())) {
setEditable(false);
}
}
}
});
}
private void setupSelectButton() {
selectBtn.setOnAction(ae -> {
FileChooser chooser = new FileChooser();
List<String> extensions = new ArrayList<>();
extensions.add("*.xml");
String schematronFiles = Localization.getText("CheckDialog.schematronFiles");
chooser.getExtensionFilters().add(new ExtensionFilter(schematronFiles, extensions));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
chooser.setInitialDirectory(dir);
}
String schematronChooserTitle = Localization.getText("CheckDialog.schematronChooserTitle");
chooser.setTitle(schematronChooserTitle);
File file = chooser.showOpenDialog(stage);
if (file != null) {
schematronField.setText(file.getAbsolutePath());
}
});
}
private void setupLoadButton() {
loadBtn.setOnAction(ae -> {
FileChooser fc = new FileChooser();
String validationConfiguration = Localization.getText("CheckDialog.validationConfiguration");
fc.getExtensionFilters().add(new ExtensionFilter(validationConfiguration, "*.yml"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showOpenDialog(stage);
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
ValidationConfiguration config = ValidationConfiguration.loadValidationConfig(f.getAbsolutePath());
applyConfig(config);
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
}
private void setupSaveButton() {
saveBtn.setOnAction(ae -> {
ValidationConfiguration config = createConfig();
FileChooser fc = new FileChooser();
fc.getExtensionFilters()
.add(new ExtensionFilter(Localization.getText("CheckDialog.validationConfiguration"), "*.yml"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(stage);
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
config.saveAs(f);
} catch (IOException e) {
window.showExceptionDialog(e);
}
}
});
}
private void applyConfig(ValidationConfiguration config) throws IOException {
FilterConfiguration filter = config.getFilter();
if (filter != null) {
getFilterPane().applyFilterConfig(filter);
}
Map<String, RequirementConfiguration> checks = config.getRequirements();
for (Entry<String, RequirementConfiguration> e : checks.entrySet()) {
for (TreeItem<TreeRequirement> ti : geometricTable.getRoot().getChildren()) {
applyCheckConfig(e, ti);
}
}
globalParametersTable.getItems().clear();
globalParametersTable.getItems().add(new GlobalParameter(GlobalParameters.NUMBER_OF_ROUNDING_PLACES,
config.getNumberOfRoundingPlacesAsString(), Unit.NONE));
globalParametersTable.getItems().add(new GlobalParameter(GlobalParameters.MIN_VERTEX_DISTANCE,
config.getMinVertexDistanceAsString(), Unit.METER));
schematronField.setText(config.getSchematronFilePath());
}
private FilterPane getFilterPane() throws IOException {
if (filterPane == null) {
filterPane = new FilterPane();
Platform.runLater(() -> filterTab.setContent(filterPane.getPane()));
}
return filterPane;
}
private void applyCheckConfig(Entry<String, RequirementConfiguration> e, TreeItem<TreeRequirement> ti) {
Requirement r = ti.getValue().getRequirement();
RequirementConfiguration cConfig = e.getValue();
if (r.getId().equals(e.getKey())) {
ti.getValue().getEnabledProperty().set(cConfig.isEnabled());
for (Entry<String, String> paramEntry : cConfig.getParameters().entrySet()) {
String name = paramEntry.getKey();
String value = paramEntry.getValue();
for (TreeItem<TreeRequirement> configItem : ti.getChildren()) {
TreeRequirement parameterCheck = configItem.getValue();
if (name.equals(parameterCheck.getNameProperty().getValue())) {
parameterCheck.setValue(value);
}
}
}
}
}
private boolean collectCheckConfiguration(ValidationConfiguration config) {
collectCheckInformationFromTree(config, geometricTable);
collectCheckInformationFromTree(config, semanticTable);
config.setSchematronFilePathInGlobalParameters(schematronField.getText());
config.setMinVertexDistanceInGlobalParameters(
Double.parseDouble(globalParametersTable.getItems().get(1).getValue()));
// check if everything is okay with the configuration
config.validateConfiguration();
return true;
}
private void collectCheckInformationFromTree(ValidationConfiguration config, TreeTableView<TreeRequirement> table) {
for (TreeItem<TreeRequirement> ti : table.getRoot().getChildren()) {
Requirement r = ti.getValue().getRequirement();
if (ti.getValue().getEnabledProperty().getValue()) {
RequirementConfiguration cc = config.getRequirements().get(r.getId());
cc.setEnabled(ti.getValue().isEnabled());
// collect parameters
collectParameters(cc, ti);
} else {
config.getRequirements().get(r.getId()).setEnabled(false);
}
}
}
private void loadImages() {
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/openFolderIcon.png")) {
Image img = new Image(inStream);
loadView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/save.png")) {
Image img = new Image(inStream);
saveView.setImage(img);
}
} catch (IOException e) {
// ignore close exception
}
}
private void setupCheckButton() {
checkBtn.setOnAction(ea -> {
ValidationConfiguration config = createConfig();
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 (logger.isInfoEnabled()) {
String checksDone = Localization.getText("CheckDialog.checksDone");
logger.info(checksDone);
}
} catch (Exception e) {
if (logger.isErrorEnabled()) {
String failedChecks = Localization.getText("CheckDialog.failedChecks");
logger.error(failedChecks, e);
}
Platform.runLater(() -> {
ExceptionDialog dialog = new ExceptionDialog();
dialog.show(e);
});
} finally {
Platform.runLater(() -> {
checkBtn.setDisable(false);
cancelBtn.setDisable(false);
stage.setOnCloseRequest(null);
stage.close();
});
}
});
t.start();
});
}
private ValidationConfiguration createConfig() {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setMinVertexDistanceInGlobalParameters(
Double.parseDouble(globalParametersTable.getItems().get(1).getValue()));
if (filterPane != null) {
config.setFilter(filterPane.getConfiguration());
}
collectCheckConfiguration(config);
if (schematronField.getText().isEmpty()) {
return config;
}
File f = new File(schematronField.getText());
if (!f.exists() || f.isDirectory() && logger.isWarnEnabled()) {
String schematronFileNotExisting = Localization.getText("CheckDialog.schematronFileNotExisting");
logger.warn(schematronFileNotExisting);
} else {
config.setSchematronFilePathInGlobalParameters(schematronField.getText());
}
return config;
}
private void collectParameters(RequirementConfiguration cc, TreeItem<TreeRequirement> ti) {
Map<String, String> parameters = new HashMap<>();
for (TreeItem<TreeRequirement> paramTi : ti.getChildren()) {
String name = paramTi.getValue().getNameProperty().getValue();
String value = paramTi.getValue().getValueProperty().getValue();
parameters.put(name, value);
}
cc.setParameters(parameters);
}
private void createEnableColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, Boolean> enableColumn = new TreeTableColumn<>(CHECK_ENABLED);
view.getColumns().add(enableColumn);
enableColumn.setCellValueFactory(param -> {
TreeRequirement check = param.getValue().getValue();
if (check != null) {
return check.getEnabledProperty();
}
return null;
});
StringConverter<Boolean> converter = new StringConverter<>() {
@Override
public String toString(Boolean object) {
return " ";
}
@Override
public Boolean fromString(String string) {
return Boolean.parseBoolean(string);
}
};
enableColumn.setCellFactory(list -> new CheckBoxTreeTableCell<TreeRequirement, Boolean>(null, converter) {
@Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
setText(null);
}
}
});
}
private void createNameColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> nameColumn = new TreeTableColumn<>(NAME);
nameColumn.setEditable(false);
view.getColumns().add(nameColumn);
nameColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getNameProperty();
}
return null;
});
}
private void createValueColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> valueColumn = new TreeTableColumn<>(VALUE);
view.getColumns().add(valueColumn);
valueColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getValueProperty();
}
return null;
});
valueColumn.setCellFactory(col -> new TreeEditCell<>(new DefaultStringConverter()));
valueColumn.setPrefWidth(100);
}
private void createUnitColumn(TreeTableView<TreeRequirement> view) {
TreeTableColumn<TreeRequirement, String> unitColumn = new TreeTableColumn<>(UNIT);
unitColumn.setEditable(false);
view.getColumns().add(unitColumn);
unitColumn.setCellValueFactory(param -> {
if (param.getValue().getValue() != null) {
return param.getValue().getValue().getUnitProperty();
}
return null;
});
}
private void populateTreeWithChecks(TreeTableView<TreeRequirement> view, RequirementType type, boolean enabled) {
view.setRoot(new TreeItem<>());
List<Requirement> requirements = new ArrayList<>(Checks.getAvailableRequirements().values());
Collections.sort(requirements, (r1, r2) -> r1.getId().compareTo(r2.getId()));
for (Requirement r : requirements) {
if (r.getType() != type) {
continue;
}
TreeRequirement treeCheck = new TreeRequirement(r);
treeCheck.setEnabled(enabled);
TreeItem<TreeRequirement> ti = new TreeItem<>(treeCheck);
view.getRoot().getChildren().add(ti);
for (DefaultParameter dp : r.getDefaultParameter()) {
TreeItem<TreeRequirement> dpTi = new TreeItem<>(new TreeRequirement(dp));
ti.getChildren().add(dpTi);
}
ti.setExpanded(true);
}
}
public void show() {
Platform.runLater(() -> {
if (controller.getCurrentConfig() != null) {
for (GlobalParameter parameter : globalParametersTable.getItems()) {
if (parameter.getName().equals(NUMBER_OF_ROUNDING_PLACES)) {
parameter.setValue("" + controller.getCurrentConfig().getNumberOfRoundingPlaces());
}
}
}
globalParametersTable.refresh();
progress.setProgress(0d);
stage.showAndWait();
});
}
}
package de.hft.stuttgart.citydoctor2.gui;
public enum CheckStatus {
ERROR, OK, NOT_CHECKED
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.CityModel;
import org.xml.sax.SAXParseException;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeConstructiveElement;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.Installation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.ReliefObject;
import de.hft.stuttgart.citydoctor2.datastructure.TinObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.gui.table.ErrorStat;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBoundarySurfacesNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgeConstructiveElementsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgePartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBridgesNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllInstallationsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingPartsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllBuildingsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllOpeningsNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTerrainNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllTransportationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllVegetationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.AllWaterNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BoundarySurfaceNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeConstructiveElementNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BridgeNode;
import de.hft.stuttgart.citydoctor2.gui.tree.InstallationNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingNode;
import de.hft.stuttgart.citydoctor2.gui.tree.BuildingPartNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ButtonRenderable;
import de.hft.stuttgart.citydoctor2.gui.tree.CityObjectNode;
import de.hft.stuttgart.citydoctor2.gui.tree.GeometryNode;
import de.hft.stuttgart.citydoctor2.gui.tree.LandUseNode;
import de.hft.stuttgart.citydoctor2.gui.tree.OpeningNode;
import de.hft.stuttgart.citydoctor2.gui.tree.ReliefNode;
import de.hft.stuttgart.citydoctor2.gui.tree.Renderable;
import de.hft.stuttgart.citydoctor2.gui.tree.TinNode;
import de.hft.stuttgart.citydoctor2.gui.tree.VegetationNode;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.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.parser.ProgressListener;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
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;
public class CityDoctorController {
private static final int MAX_FEATURES_PER_CHUNK = 200;
private static final Logger logger = LogManager.getLogger(CityDoctorController.class);
private MainWindow mainWindow;
private CityDoctorModel model;
private ParserConfiguration currentConfig;
private String sourceFile;
private Checker currentChecker;
private HighlightController highlightController;
private Renderer renderer;
private AtomicInteger buildingChunkNr = new AtomicInteger(0);
private AtomicInteger vegetationChunkNr = new AtomicInteger(0);
private AtomicInteger transportationChunkNr = new AtomicInteger(0);
private AtomicInteger bridgeChunkNr = new AtomicInteger(0);
private AtomicInteger waterChunkNr = new AtomicInteger(0);
private AtomicInteger landChunkNr = new AtomicInteger(0);
public CityDoctorController(MainWindow mainWindow, HighlightController highlightController, Renderer renderer) {
this.mainWindow = mainWindow;
this.highlightController = highlightController;
this.renderer = renderer;
}
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation)
throws CityGmlParseException, InvalidGmlFileException {
loadCityGml(path, numberOfRoundingPlaces, l, useValidation, false);
}
public void loadCityGml(String path, int numberOfRoundingPlaces, ProgressListener l, boolean useValidation,
boolean lowMemory) throws CityGmlParseException, InvalidGmlFileException {
try {
Platform.runLater(() -> {
mainWindow.getOpenBtn().setDisable(true);
mainWindow.getWriteReportButton().setDisable(true);
mainWindow.getMeshGroup().getChildren().clear();
clearTrees();
mainWindow.resetSearchBar();
mainWindow.resetFilterComboBox();
});
currentChecker = null;
currentConfig = new ParserConfiguration(numberOfRoundingPlaces, useValidation, lowMemory);
GMLValidationHandler handler = null;
List<String> validationIssues = new ArrayList<>();
if (useValidation) {
handler = new GMLValidationHandler() {
@Override
public void error(SAXParseException exception) {
if (exception.getLineNumber() >= 0) {
String s = "In line " + exception.getLineNumber() + ":";
validationIssues.add(s);
}
validationIssues.add(exception.getMessage());
}
@Override
public void warning(SAXParseException exception) {
error(exception);
}
@Override
public void fatalError(SAXParseException exception) {
error(exception);
}
};
}
model = CityGmlParser.parseCityGmlFile(path, currentConfig, l, handler);
if (!validationIssues.isEmpty()) {
StringJoiner sj = new StringJoiner("\n");
validationIssues.stream().forEach(sj::add);
throw new InvalidGmlFileException(sj.toString());
}
mainWindow.getClickHandler().setConfig(currentConfig);
sourceFile = path;
renderer.reset();
Platform.runLater(() -> {
mainWindow.addFileNameToTitle(path);
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);
buildTrees();
});
} finally {
Platform.runLater(() -> mainWindow.getOpenBtn().setDisable(false));
}
}
public void buildTrees() {
resetFeatureChunks();
buildBuildings(model);
buildVegetation(model.getVegetation());
buildTransportation(model.getTransportation());
buildBridges(model);
buildWater(model);
buildLand(model);
}
private void resetFeatureChunks() {
buildingChunkNr.set(0);
vegetationChunkNr.set(0);
transportationChunkNr.set(0);
bridgeChunkNr.set(0);
waterChunkNr.set(0);
landChunkNr.set(0);
}
private void buildLand(CityDoctorModel model) {
if (model.getLand().isEmpty()) {
return;
}
TreeView<Renderable> landView = mainWindow.getTerrainView();
TreeItem<Renderable> landRoot = new TreeItem<>(new AllTerrainNode(model.getLand()));
landRoot.setExpanded(true);
landView.setRoot(landRoot);
buildLandFromList(model.getLand(), landView.getRoot());
addMoreButtonIfNecessary(model.getLand(), landView, landRoot, landChunkNr);
}
private void buildLandFromList(List<CityObject> list, TreeItem<Renderable> root) {
int landChunk = landChunkNr.get();
for (int i = landChunk * MAX_FEATURES_PER_CHUNK; i < (landChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
CityObject land = list.get(i);
Renderable node;
if (land instanceof ReliefObject relief) {
node = new ReliefNode(relief);
} else if (land instanceof TinObject tin) {
node = new TinNode(tin);
} else {
node = new LandUseNode((LandObject) land);
}
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(land, item);
if (land instanceof ReliefObject relief) {
createTinNodes(relief, item);
}
}
}
private void createTinNodes(ReliefObject relief, TreeItem<Renderable> item) {
if (relief.getComponents().isEmpty()) {
return;
}
AllTinNode allTinText = new AllTinNode(relief.getComponents());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allTinText);
item.getChildren().add(allBpsTextItem);
for (TinObject tin : relief.getComponents()) {
TinNode tinNode = new TinNode(tin);
TreeItem<Renderable> tinNodeItem = new TreeItem<>(tinNode);
tinNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(tinNodeItem);
createGeometryNodes(tin, tinNodeItem);
}
}
private void buildWater(CityDoctorModel model) {
if (model.getWater().isEmpty()) {
return;
}
TreeView<Renderable> waterView = mainWindow.getWaterView();
TreeItem<Renderable> waterRoot = new TreeItem<>(new AllWaterNode(model.getWater()));
waterRoot.setExpanded(true);
waterView.setRoot(waterRoot);
buildTreeFromList(model.getWater(), waterView.getRoot(), waterChunkNr);
addMoreButtonIfNecessary(model.getWater(), waterView, waterRoot, waterChunkNr);
}
private void buildBridges(CityDoctorModel model) {
if (model.getBridges().isEmpty()) {
return;
}
TreeView<Renderable> bridgeView = mainWindow.getBridgeView();
TreeItem<Renderable> bridgeRoot = new TreeItem<>(new AllBridgesNode(model.getBridges()));
bridgeRoot.setExpanded(true);
bridgeView.setRoot(bridgeRoot);
buildBridgeTreeFromList(model.getBridges(), bridgeView.getRoot());
addMoreButtonIfNecessary(model.getBridges(), bridgeView, bridgeRoot, bridgeChunkNr);
}
private void buildTransportation(List<TransportationObject> trans) {
if (trans.isEmpty()) {
return;
}
TreeView<Renderable> transView = mainWindow.getTransportationView();
TreeItem<Renderable> transRoot = new TreeItem<>(new AllTransportationNode(model.getTransportation()));
transRoot.setExpanded(true);
transView.setRoot(transRoot);
buildTreeFromList(trans, transView.getRoot(), transportationChunkNr);
addMoreButtonIfNecessary(trans, transView, transRoot, transportationChunkNr);
}
private void buildVegetation(List<Vegetation> veg) {
if (veg.isEmpty()) {
return;
}
TreeView<Renderable> vegetationsView = mainWindow.getVegetationView();
TreeItem<Renderable> vegRoot = new TreeItem<>(new AllVegetationNode(model.getVegetation()));
vegRoot.setExpanded(true);
vegetationsView.setRoot(vegRoot);
buildTreeFromListWithProducer(veg, vegetationsView.getRoot(), vegetationChunkNr, VegetationNode::new);
addMoreButtonIfNecessary(veg, vegetationsView, vegRoot, vegetationChunkNr);
}
private void addMoreButtonIfNecessary(List<? extends CityObject> list, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
Runnable run = new Runnable() {
public void run() {
// 29 is the height of one item
int numberOfDisplayedItems = (int) (view.getHeight() / 29);
int selectedIndex = view.getSelectionModel().getSelectedIndex();
// remove button node
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.incrementAndGet();
int visibleFeatures = countVisibleNodes(view);
buildTreeFromList(list, root, chunkCounter);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
};
// add button for expansion
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private void buildBuildings(CityDoctorModel model) {
if (model.getBuildings().isEmpty()) {
return;
}
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = new TreeItem<>(new AllBuildingsNode(model.getBuildings()));
root.setExpanded(true);
buildBuildingTreeFromList(model.getBuildings(), root);
addMoreButtonToBuildingsIfNecessary(model.getBuildings(), buildingsView, root, buildingChunkNr);
buildingsView.setRoot(root);
}
private void addMoreButtonToBuildingsIfNecessary(List<Building> list, TreeView<Renderable> view,
TreeItem<Renderable> root, AtomicInteger chunkCounter) {
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
Runnable run = new Runnable() {
public void run() {
// 29 is the height of one item
int numberOfDisplayedItems = (int) (view.getHeight() / 29);
int selectedIndex = view.getSelectionModel().getSelectedIndex();
// remove button node
root.getChildren().remove(root.getChildren().size() - 1);
chunkCounter.getAndIncrement();
int visibleFeatures = countVisibleNodes(view);
buildBuildingTreeFromList(list, root);
updateTree(root);
if (selectedIndex >= 0) {
view.getSelectionModel().select(selectedIndex);
}
if ((chunkCounter.get() + 1) * MAX_FEATURES_PER_CHUNK < list.size()) {
root.getChildren().add(new TreeItem<>(new ButtonRenderable(this)));
}
view.scrollTo(visibleFeatures - numberOfDisplayedItems + 1);
}
};
// add button for expansion
root.getChildren().add(new TreeItem<>(new ButtonRenderable(run)));
}
}
private static int countVisibleNodes(TreeView<Renderable> view) {
return countVisibleNodes(view.getRoot()) + 1;
}
private static int countVisibleNodes(TreeItem<Renderable> root) {
int visibleFeatures = root.getChildren().size();
for (TreeItem<Renderable> child : root.getChildren()) {
if (!child.getChildren().isEmpty() && child.isExpanded()) {
visibleFeatures += countVisibleNodes(child);
}
}
return visibleFeatures;
}
private void buildTreeFromList(List<? extends CityObject> cos, TreeItem<Renderable> root,
AtomicInteger chunkCounter) {
int chunk = chunkCounter.get();
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
CityObject co = cos.get(i);
CityObjectNode node = new CityObjectNode(co);
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem);
createGeometryNodes(co, nodeItem);
}
}
private <T extends CityObject> void buildTreeFromListWithProducer(List<T> cos, TreeItem<Renderable> root,
AtomicInteger chunkCounter, Function<T, Renderable> nodeProducer) {
int chunk = chunkCounter.get();
for (int i = chunk * MAX_FEATURES_PER_CHUNK; i < (chunk + 1) * MAX_FEATURES_PER_CHUNK && i < cos.size(); i++) {
T co = cos.get(i);
Renderable node = nodeProducer.apply(co);
TreeItem<Renderable> nodeItem = new TreeItem<>(node);
nodeItem.setExpanded(true);
root.getChildren().add(nodeItem);
createGeometryNodes(co, nodeItem);
}
}
private void clearTrees() {
mainWindow.getBuildingsView().setRoot(null);
mainWindow.getVegetationView().setRoot(null);
mainWindow.getTransportationView().setRoot(null);
mainWindow.getBridgeView().setRoot(null);
mainWindow.getWaterView().setRoot(null);
mainWindow.getTerrainView().setRoot(null);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
clearGeometryTrees();
}
private void clearGeometryTrees() {
highlightController.clearHighlights();
mainWindow.getPolygonsView().getRoot().getChildren().clear();
mainWindow.getEdgeView().getRoot().getChildren().clear();
mainWindow.getVertexView().getRoot().getChildren().clear();
}
private void buildBuildingTreeFromList(List<Building> list, TreeItem<Renderable> root) {
int buildingChunk = buildingChunkNr.get();
for (int i = buildingChunk * MAX_FEATURES_PER_CHUNK; i < (buildingChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
Building b = list.get(i);
BuildingNode node = new BuildingNode(b);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(b, item);
createBoundarySurfaceNodes(b.getBoundarySurfaces(), item);
createBuildingInstallationNodes(b, item);
createBuildingPartNodes(b, item);
}
}
private void buildBridgeTreeFromList(List<BridgeObject> list, TreeItem<Renderable> root) {
int bridgeChunk = bridgeChunkNr.get();
for (int i = bridgeChunk * MAX_FEATURES_PER_CHUNK; i < (bridgeChunk + 1) * MAX_FEATURES_PER_CHUNK
&& i < list.size(); i++) {
BridgeObject bridge = list.get(i);
BridgeNode node = new BridgeNode(bridge);
TreeItem<Renderable> item = new TreeItem<>(node);
item.setExpanded(true);
root.getChildren().add(item);
createGeometryNodes(bridge, item);
createBoundarySurfaceNodes(bridge.getBoundarySurfaces(), item);
createBridgeInstallationNodes(bridge, item);
createConstructiveElementsNodes(bridge, item);
createBridgePartNodes(bridge, item);
}
}
private void createBridgeInstallationNodes(BridgeObject bridge, TreeItem<Renderable> root) {
createInstallationNodes(bridge.getBridgeInstallations(), root);
}
private void createConstructiveElementsNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getConstructiveElements().isEmpty()) {
return;
}
AllBridgeConstructiveElementsNode allBceNode = new AllBridgeConstructiveElementsNode(
bridge.getConstructiveElements());
TreeItem<Renderable> allBceNodeTextItem = new TreeItem<>(allBceNode);
item.getChildren().add(allBceNodeTextItem);
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);
}
}
private void createBridgePartNodes(BridgeObject bridge, TreeItem<Renderable> item) {
if (bridge.getParts().isEmpty()) {
return;
}
AllBridgePartsNode allBpsText = new AllBridgePartsNode(bridge.getParts());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
item.getChildren().add(allBpsTextItem);
for (BridgeObject bp : bridge.getParts()) {
BridgeNode bpNode = new BridgeNode(bp);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bp, bpNodeItem);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
}
}
private void createBuildingInstallationNodes(Building ab, TreeItem<Renderable> root) {
createInstallationNodes(ab.getBuildingInstallations(), root);
}
private void createInstallationNodes(List<Installation> installations, TreeItem<Renderable> root) {
if (installations.isEmpty()) {
return;
}
AllInstallationsNode allBiNode = new AllInstallationsNode(installations);
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBiNode);
root.getChildren().add(allBpsTextItem);
for (Installation bi : installations) {
InstallationNode biNode = new InstallationNode(bi);
TreeItem<Renderable> biItem = new TreeItem<>(biNode);
biItem.setExpanded(true);
allBpsTextItem.getChildren().add(biItem);
createGeometryNodes(bi, biItem);
createBoundarySurfaceNodes(bi.getBoundarySurfaces(), biItem);
}
}
private void createBoundarySurfaceNodes(List<BoundarySurface> bsList, TreeItem<Renderable> root) {
if (bsList.isEmpty()) {
return;
}
AllBoundarySurfacesNode allBsText = new AllBoundarySurfacesNode(bsList);
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBsText);
root.getChildren().add(allBpsTextItem);
allBpsTextItem.getChildren().add(new TreeItem<>());
allBpsTextItem.expandedProperty().addListener((obs, old, newV) -> {
if (Boolean.TRUE.equals(newV) && allBpsTextItem.getChildren().size() == 1) {
Platform.runLater(() -> {
allBpsTextItem.getChildren().clear();
for (BoundarySurface bs : bsList) {
BoundarySurfaceNode bsText = new BoundarySurfaceNode(bs);
TreeItem<Renderable> bsTextItem = new TreeItem<>(bsText);
bsTextItem.setExpanded(true);
allBpsTextItem.getChildren().add(bsTextItem);
createGeometryNodes(bs, bsTextItem);
createOpeningNodes(bs.getOpenings(), bsTextItem);
}
updateTree(allBpsTextItem);
});
}
});
}
private void createOpeningNodes(List<Opening> openings, TreeItem<Renderable> root) {
if (openings == null || openings.isEmpty()) {
return;
}
AllOpeningsNode allOpeningsNode = new AllOpeningsNode(openings);
TreeItem<Renderable> allOpeningsItem = new TreeItem<>(allOpeningsNode);
for (Opening o : openings) {
OpeningNode openingNode = new OpeningNode(o);
TreeItem<Renderable> openingsItem = new TreeItem<>(openingNode);
allOpeningsItem.getChildren().add(openingsItem);
}
root.getChildren().add(allOpeningsItem);
}
private void createBuildingPartNodes(Building ab, TreeItem<Renderable> item) {
if (ab.getBuildingParts().isEmpty()) {
return;
}
AllBuildingPartsNode allBpsText = new AllBuildingPartsNode(ab.getBuildingParts());
TreeItem<Renderable> allBpsTextItem = new TreeItem<>(allBpsText);
item.getChildren().add(allBpsTextItem);
for (BuildingPart bp : ab.getBuildingParts()) {
BuildingPartNode bpNode = new BuildingPartNode(bp);
TreeItem<Renderable> bpNodeItem = new TreeItem<>(bpNode);
bpNodeItem.setExpanded(true);
allBpsTextItem.getChildren().add(bpNodeItem);
createGeometryNodes(bp, bpNodeItem);
createBoundarySurfaceNodes(bp.getBoundarySurfaces(), bpNodeItem);
}
}
private void createGeometryNodes(CityObject co, TreeItem<Renderable> item) {
for (Geometry geom : co.getGeometries()) {
GeometryNode geomNode = new GeometryNode(geom);
TreeItem<Renderable> geomItem = new TreeItem<>(geomNode);
item.getChildren().add(geomItem);
}
}
public void startChecks(ValidationConfiguration config, ProgressListener l) {
if (model == null) {
logger.warn(Localization.getText("CityDoctorController.noDatamodel"));
return;
}
if (sourceFile == null) {
logger.warn(Localization.getText("CityDoctorController.noSourceFile"));
return;
}
try {
Platform.runLater(() -> {
mainWindow.getCheckButton().setDisable(true);
mainWindow.getErrorTree().getRoot().getChildren().clear();
mainWindow.getGlobalErrorsView().getItems().clear();
});
config.setNumberOfRoundingPlacesInGlobalParameters(currentConfig.getNumberOfRoundingPlaces());
config.setParserConfig(currentConfig);
currentChecker = new Checker(config, model);
currentChecker.runChecks(l);
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);
});
} finally {
Platform.runLater(() -> mainWindow.getCheckButton().setDisable(false));
}
}
void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().getRoot());
updateTree(mainWindow.getBridgeView().getRoot());
updateTree(mainWindow.getTerrainView().getRoot());
updateTree(mainWindow.getTransportationView().getRoot());
updateTree(mainWindow.getWaterView().getRoot());
renderer.updateErrors();
}
private void updateTree(TreeItem<Renderable> root) {
if (root == null) {
return;
}
for (TreeItem<Renderable> item : root.getChildren()) {
updateItem(item);
}
}
private void updateItem(TreeItem<Renderable> item) {
if (item.getValue() == null) {
return;
}
item.getValue().refreshTextColor();
for (TreeItem<Renderable> child : item.getChildren()) {
updateItem(child);
}
}
public void writePdfReport(File pdfFile) {
if (currentChecker == null) {
return;
}
currentChecker.writePdfReport(pdfFile.getAbsolutePath());
}
public void writeXmlReport(File xmlFile) {
if (currentChecker == null) {
return;
}
currentChecker.writeXmlReport(xmlFile.getAbsolutePath());
}
private Map<ErrorId, ErrorStat> getErrorStats() {
Map<ErrorId, ErrorStat> stats = new HashMap<>();
addErrorStats(stats, model.getBridges());
addErrorStats(stats, model.getBuildings());
addErrorStats(stats, model.getLand());
addErrorStats(stats, model.getTransportation());
addErrorStats(stats, model.getVegetation());
addErrorStats(stats, model.getWater());
return stats;
}
private void addErrorStats(Map<ErrorId, ErrorStat> stats, List<? extends CityObject> cos) {
List<CheckError> errors = new ArrayList<>();
for (CityObject co : cos) {
co.collectContainedErrors(errors);
}
Set<CheckError> filteredErrors = new HashSet<>(errors);
for (CheckError error : filteredErrors) {
ErrorStat stat = stats.computeIfAbsent(error.getErrorId(), ErrorStat::new);
stat.incrementCount();
}
}
public void export(Building b) {
if (model == null) {
return;
}
CityDoctorModel newModel = new CityDoctorModel(model.getParserConfig(), model.getFile());
newModel.setCityModel(new CityModel());
newModel.addBuilding(b);
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(mainWindow.getMainStage());
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
newModel.saveAs(f.getAbsolutePath(), true);
} catch (CityDoctorWriteException e) {
logger.error(e);
}
}
}
public void showWorld() {
if (model != null) {
renderer.render(model);
}
}
public void storeModel(File f, boolean saveQualityAde) throws CityDoctorWriteException {
if (model == null) {
return;
}
model.saveAs(f.getAbsolutePath(), saveQualityAde);
}
public void searchFeature(String searchString, FeatureType selectedTab) {
if (model == null || searchString == null || searchString.trim().isEmpty()) {
return;
}
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 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;
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);
}
}
private <T extends CityObject> List<T> filterFeatures(String searchString, List<T> features) {
List<T> foundFeatures = new ArrayList<>();
for (T t : features) {
if (t.getGmlId().getGmlString().contains(searchString)) {
foundFeatures.add(t);
}
}
return foundFeatures;
}
public void resetSearch(FeatureType selectedTab) {
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 WATER:
view = mainWindow.getWaterView();
cos = model.getWater();
chunkCounter = waterChunkNr;
break;
case LAND:
view = mainWindow.getTerrainView();
cos = model.getLand();
chunkCounter = landChunkNr;
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);
}
}
public Series<String, Number> createErrorSeries() {
Series<String, Number> series = new Series<>();
if (model == null) {
return series;
}
Map<ErrorId, ErrorStat> errorStats = getErrorStats();
for (ErrorStat es : errorStats.values()) {
series.getData().add(new Data<>(es.getErrorId().toString(), es.getCount()));
}
return series;
}
public String getFileName() {
return model.getFileName();
}
public void fillTreeViewWithErrorBuildings() {
TreeView<Renderable> buildingsView = mainWindow.getBuildingsView();
TreeItem<Renderable> root = buildingsView.getRoot();
if (model == null) {
return;
}
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<Building> errorBuildings = new ArrayList<>();
for (Building b : model.getBuildings()) {
if (b.containsAnyError()) {
errorBuildings.add(b);
}
}
resetFeatureChunks();
buildBuildingTreeFromList(errorBuildings, root);
updateTree(root);
addMoreButtonToBuildingsIfNecessary(errorBuildings, buildingsView, root, buildingChunkNr);
}
public void fillTreeViewWithErrorVegetation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getVegetationView(), model.getVegetation(), vegetationChunkNr);
}
public void fillTreeViewWithErrorBridges() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getBridgeView(), model.getBridges(), bridgeChunkNr);
}
public void fillTreeViewWithErrorLand() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTerrainView(), model.getLand(), landChunkNr);
}
public void fillTreeViewWithErrorTransportation() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getTransportationView(), model.getTransportation(),
transportationChunkNr);
}
public void fillTreeViewWithErrorWater() {
if (model == null) {
return;
}
fillTreeViewWithErrorCityObjects(mainWindow.getWaterView(), model.getWater(), waterChunkNr);
}
private void fillTreeViewWithErrorCityObjects(TreeView<Renderable> treeView, List<? extends CityObject> objects,
AtomicInteger chunkCounter) {
TreeItem<Renderable> root = treeView.getRoot();
if (root == null) {
return;
}
mainWindow.resetSearchBar();
root.getChildren().clear();
List<CityObject> errorObjects = new ArrayList<>();
for (CityObject co : objects) {
if (co.containsAnyError()) {
errorObjects.add(co);
}
}
buildTreeFromList(errorObjects, root, chunkCounter);
updateTree(root);
addMoreButtonIfNecessary(errorObjects, treeView, root, chunkCounter);
}
public void fillTreeViewFromFeatures(FeatureType selectedTab) {
if (model == null) {
return;
}
mainWindow.resetSearchBar();
switch (selectedTab) {
case BUILDING:
buildBuildings(model);
updateTree(mainWindow.getBuildingsView().getRoot());
break;
case VEGETATION:
buildVegetation(model.getVegetation());
updateTree(mainWindow.getVegetationView().getRoot());
break;
case BRIDGE:
buildBridges(model);
updateTree(mainWindow.getBridgeView().getRoot());
break;
case LAND:
buildLand(model);
updateTree(mainWindow.getTerrainView().getRoot());
break;
case TRANSPORTATION:
buildTransportation(model.getTransportation());
updateTree(mainWindow.getTransportationView().getRoot());
break;
case WATER:
buildWater(model);
updateTree(mainWindow.getWaterView().getRoot());
break;
default:
throw new IllegalStateException();
}
}
public CityDoctorModel getModel() {
return model;
}
public void showView(View v) {
v.fireOnShowEvent(model, currentChecker, mainWindow);
}
public void askAndSave() {
boolean saveWithQualityAde = true;
if (model.isValidated()) {
ButtonType yesBtn = ButtonType.YES;
ButtonType noBtn = ButtonType.NO;
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setTitle("Save with QualityADE?");
dialog.setContentText("Save with QualityADE information?");
dialog.getDialogPane().getButtonTypes().add(yesBtn);
dialog.getDialogPane().getButtonTypes().add(noBtn);
Optional<ButtonType> result = dialog.showAndWait();
if (result.isPresent() && result.get() == ButtonType.NO) {
saveWithQualityAde = false;
}
}
FileChooser fc = new FileChooser();
fc.getExtensionFilters().add(new ExtensionFilter("CityGML", "*.gml"));
fc.getExtensionFilters().add(new ExtensionFilter("OFF - Object File Format", "*.off"));
File dir = new File(Settings.get(Settings.LAST_OPEN_FOLDER, ""));
if (dir.exists() && dir.isDirectory()) {
fc.setInitialDirectory(dir);
} else {
Settings.set(Settings.LAST_OPEN_FOLDER, "");
}
File f = fc.showSaveDialog(mainWindow.getMainStage());
if (f != null) {
Settings.set(Settings.LAST_OPEN_FOLDER, f.getParent());
try {
storeModel(f, saveWithQualityAde);
} catch (CityDoctorWriteException e) {
mainWindow.showExceptionDialog(e);
}
}
}
public void delete(TreeItem<Renderable> selectedItem) {
if (model == null) {
return;
}
Renderable render = selectedItem.getValue();
if (render instanceof BuildingNode node) {
model.getBuildings().remove(node.getBuilding());
mainWindow.getBuildingsView().getRoot().getChildren().remove(selectedItem);
}
}
public void errorFilterIndexChanged(Number newV) {
mainWindow.getMeshGroup().getChildren().clear();
mainWindow.unselectEverything();
if (newV.intValue() == 0) {
fillTreeViewFromFeatures(mainWindow.getSelectedTab());
} else if (newV.intValue() == 1) {
switch (mainWindow.getSelectedTab()) {
case BUILDING:
fillTreeViewWithErrorBuildings();
break;
case VEGETATION:
fillTreeViewWithErrorVegetation();
break;
case BRIDGE:
fillTreeViewWithErrorBridges();
break;
case LAND:
fillTreeViewWithErrorLand();
break;
case TRANSPORTATION:
fillTreeViewWithErrorTransportation();
break;
case WATER:
fillTreeViewWithErrorWater();
break;
default:
throw new IllegalStateException("Unknown selected feature tab: " + mainWindow.getSelectedTab());
}
} else {
throw new IllegalStateException("Unknown filter index selected: " + newV);
}
}
public ParserConfiguration getCurrentConfig() {
return currentConfig;
}
}
/*-
* Copyright 2022 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
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.gui;
public class CityDoctorGUIStarter {
public static void main(String[] args) {
MainWindow.main(args);
}
}
package de.hft.stuttgart.citydoctor2.gui;
import javafx.scene.input.MouseEvent;
public interface ClickDispatcher {
public void click(MouseEvent me, ClickHandler handler);
}
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import javafx.scene.input.MouseEvent;
public interface ClickHandler {
public void onPolygonClick(Polygon p, MouseEvent me);
public void onVertexClick(Vertex v, MouseEvent me);
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.PrintWriter;
import java.io.StringWriter;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
public class ExceptionDialog {
private Alert alert;
private TextArea textArea;
public ExceptionDialog() {
alert = new Alert(AlertType.ERROR);
alert.setTitle("Exception Dialog");
alert.getDialogPane().setPrefWidth(800);
Label label = new Label(Localization.getText("ExceptionDialog.stacktrace"));
textArea = new TextArea();
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
// Set expandable Exception into the dialog pane.
alert.getDialogPane().setExpandableContent(expContent);
}
public void show(Throwable ex) {
// Create expandable Exception.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
String exceptionText = sw.toString();
textArea.setText(exceptionText);
alert.setContentText(ex.getMessage());
alert.setHeaderText(ex.getClass().getSimpleName());
alert.showAndWait();
}
}
package de.hft.stuttgart.citydoctor2.gui;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.ExcludeFilterConfiguration;
import de.hft.stuttgart.citydoctor2.check.FilterConfiguration;
import de.hft.stuttgart.citydoctor2.check.IncludeFilterConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.gui.filter.TypeFilterSelection;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class FilterPane {
@FXML
private VBox inclFeatureBox;
@FXML
private ImageView addInclFeatureView;
@FXML
private VBox inclMatchBox;
@FXML
private ImageView addInclMatchView;
@FXML
private Button addInclFeatureBtn;
@FXML
private Button addInclMatchBtn;
@FXML
private VBox exclFeatureBox;
@FXML
private ImageView addExclFeatureView;
@FXML
private VBox exclMatchBox;
@FXML
private ImageView addExclMatchView;
@FXML
private Button addExclFeatureBtn;
@FXML
private Button addExclMatchBtn;
private ScrollPane pane;
private Image deleteImg;
private List<ComboBox<TypeFilterSelection>> includeTypeBoxes = new ArrayList<>();
private List<TextField> includeMatcherFields = new ArrayList<>();
private List<TextField> excludeMatcherFields = new ArrayList<>();
private List<ComboBox<TypeFilterSelection>> excludeTypeBoxes = new ArrayList<>();
private List<TypeFilterSelection> availableFilters;
public FilterPane() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(FilterPane.class.getResource("FilterPane.fxml"));
fxmlLoader.setController(this);
pane = fxmlLoader.load();
}
public void initialize() {
loadImages();
availableFilters = new ArrayList<>();
availableFilters.add(new TypeFilterSelection(FeatureType.BUILDING, Localization.getText("FilterPane.buildings")));
availableFilters.add(new TypeFilterSelection(FeatureType.BRIDGE, Localization.getText("FilterPane.bridges")));
availableFilters.add(new TypeFilterSelection(FeatureType.LAND, Localization.getText("FilterPane.landUse")));
availableFilters.add(new TypeFilterSelection(FeatureType.TRANSPORTATION, Localization.getText("FilterPane.transportation")));
availableFilters.add(new TypeFilterSelection(FeatureType.VEGETATION, Localization.getText("FilterPane.vegetation")));
availableFilters.add(new TypeFilterSelection(FeatureType.WATER, Localization.getText("FilterPane.water")));
setupIncludeFeatureButton();
setupIncludeMatchButton();
setupExcludeFeatureButton();
setupExcludeMatchButton();
}
private void setupExcludeMatchButton() {
addExclMatchBtn.setOnAction(ae -> addExcludeMatchField());
}
private TextField addExcludeMatchField() {
TextField tf = new TextField();
tf.setPrefWidth(400);
excludeMatcherFields.add(tf);
HBox box = new HBox(10);
box.getChildren().add(tf);
ImageView imgView = new ImageView(deleteImg);
imgView.setFitHeight(25);
imgView.setFitWidth(25);
box.getChildren().add(imgView);
imgView.setOnMouseClicked(me2 -> {
excludeMatcherFields.remove(tf);
exclMatchBox.getChildren().remove(box);
});
exclMatchBox.getChildren().add(box);
return tf;
}
private void setupExcludeFeatureButton() {
addExclFeatureBtn.setOnAction(ae -> addExcludeTypeFilterBox());
}
private ComboBox<TypeFilterSelection> addExcludeTypeFilterBox() {
ComboBox<TypeFilterSelection> cBox = new ComboBox<>();
cBox.setPrefWidth(400);
cBox.getItems().addAll(availableFilters);
cBox.getSelectionModel().select(0);
excludeTypeBoxes.add(cBox);
HBox box = new HBox(10);
box.getChildren().add(cBox);
ImageView imgView = new ImageView(deleteImg);
imgView.setFitHeight(25);
imgView.setFitWidth(25);
box.getChildren().add(imgView);
imgView.setOnMouseClicked(me2 -> {
excludeTypeBoxes.remove(cBox);
exclFeatureBox.getChildren().remove(box);
});
exclFeatureBox.getChildren().add(box);
return cBox;
}
private void setupIncludeMatchButton() {
addInclMatchBtn.setOnAction(ae -> addIncludeMatchField());
}
private TextField addIncludeMatchField() {
TextField tf = new TextField();
tf.setPrefWidth(400);
includeMatcherFields.add(tf);
HBox box = new HBox(10);
box.getChildren().add(tf);
ImageView imgView = new ImageView(deleteImg);
imgView.setFitHeight(25);
imgView.setFitWidth(25);
box.getChildren().add(imgView);
imgView.setOnMouseClicked(me2 -> {
includeMatcherFields.remove(tf);
inclMatchBox.getChildren().remove(box);
});
inclMatchBox.getChildren().add(box);
return tf;
}
public void applyFilterConfig(FilterConfiguration filter) {
includeMatcherFields.clear();
inclMatchBox.getChildren().clear();
includeTypeBoxes.clear();
inclFeatureBox.getChildren().clear();
excludeMatcherFields.clear();
exclMatchBox.getChildren().clear();
excludeTypeBoxes.clear();
exclFeatureBox.getChildren().clear();
applyExcludeFilters(filter);
applyIncludeFilters(filter);
}
private void applyIncludeFilters(FilterConfiguration filter) {
IncludeFilterConfiguration include = filter.getInclude();
if (include != null) {
for (String s : include.getIds()) {
addIncludeMatchField().setText(s);
}
for (FeatureType type : include.getTypes()) {
ComboBox<TypeFilterSelection> box = addIncludeTypeFilterBox();
for (TypeFilterSelection tfs : box.getItems()) {
if (tfs.getType() == type) {
box.getSelectionModel().select(tfs);
}
}
}
}
}
private void applyExcludeFilters(FilterConfiguration filter) {
ExcludeFilterConfiguration exclude = filter.getExclude();
if (exclude != null) {
for (String s : exclude.getIds()) {
addExcludeMatchField().setText(s);
}
for (FeatureType type : exclude.getTypes()) {
ComboBox<TypeFilterSelection> box = addExcludeTypeFilterBox();
for (TypeFilterSelection tfs : box.getItems()) {
if (tfs.getType() == type) {
box.getSelectionModel().select(tfs);
}
}
}
}
}
private void setupIncludeFeatureButton() {
addInclFeatureBtn.setOnAction(ae -> addIncludeTypeFilterBox());
}
private ComboBox<TypeFilterSelection> addIncludeTypeFilterBox() {
ComboBox<TypeFilterSelection> cBox = new ComboBox<>();
cBox.setPrefWidth(400);
cBox.getItems().addAll(availableFilters);
cBox.getSelectionModel().select(0);
includeTypeBoxes.add(cBox);
HBox box = new HBox(10);
box.getChildren().add(cBox);
ImageView imgView = new ImageView(deleteImg);
imgView.setFitHeight(25);
imgView.setFitWidth(25);
box.getChildren().add(imgView);
imgView.setOnMouseClicked(me2 -> {
includeTypeBoxes.remove(cBox);
inclFeatureBox.getChildren().remove(box);
});
inclFeatureBox.getChildren().add(box);
return cBox;
}
public FilterConfiguration getConfiguration() {
IncludeFilterConfiguration includeFilters = new IncludeFilterConfiguration();
List<FeatureType> featureTypes = new ArrayList<>();
for (ComboBox<TypeFilterSelection> box : includeTypeBoxes) {
featureTypes.add(box.getSelectionModel().getSelectedItem().getType());
}
includeFilters.setTypes(featureTypes);
List<String> ids = new ArrayList<>();
for (TextField tf : includeMatcherFields) {
ids.add(tf.getText());
}
includeFilters.setIds(ids);
ExcludeFilterConfiguration excludeFilters = new ExcludeFilterConfiguration();
List<FeatureType> excludeFeatureTypes = new ArrayList<>();
for (ComboBox<TypeFilterSelection> box : excludeTypeBoxes) {
excludeFeatureTypes.add(box.getSelectionModel().getSelectedItem().getType());
}
excludeFilters.setTypes(excludeFeatureTypes);
List<String> excludeIds = new ArrayList<>();
for (TextField tf : excludeMatcherFields) {
excludeIds.add(tf.getText());
}
excludeFilters.setIds(excludeIds);
FilterConfiguration fConfig = new FilterConfiguration();
fConfig.setInclude(includeFilters);
fConfig.setExclude(excludeFilters);
return fConfig;
}
private void loadImages() {
try {
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Add.png")) {
Image img = new Image(inStream);
addInclFeatureView.setImage(img);
addInclMatchView.setImage(img);
addExclFeatureView.setImage(img);
addExclMatchView.setImage(img);
}
try (InputStream inStream = MainWindow.class.getResourceAsStream("icons/Delete.png")) {
deleteImg = new Image(inStream);
}
} catch (IOException e) {
// ignore close exception
}
}
public ScrollPane getPane() {
return pane;
}
}
/*-
* 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
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.gui;
import java.io.Serial;
import java.io.Serializable;
import de.hft.stuttgart.citydoctor2.check.Unit;
public class GlobalParameter implements Serializable {
@Serial
private static final long serialVersionUID = 1423983452743345752L;
private String name;
private String value;
private Unit unit;
public GlobalParameter(String name, String value, Unit unit) {
super();
this.name = name;
this.value = value;
this.unit = unit;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((unit == null) ? 0 : unit.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GlobalParameter other = (GlobalParameter) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (unit != other.unit)
return false;
if (value == null) {
return other.value == null;
} else return value.equals(other.value);
}
@Override
public String toString() {
return "GlobalParameter [name=" + name + ", value=" + value + ", unit=" + unit + "]";
}
public Unit getUnit() {
return unit;
}
public void setUnit(Unit unit) {
this.unit = unit;
}
}
package de.hft.stuttgart.citydoctor2.gui;
import java.util.List;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import javafx.application.Platform;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
public class HighlightController {
private double scale;
private Group points;
private Group edges;
private Group highlights;
public HighlightController(Group world) {
highlights = new Group();
points = new Group();
edges = new Group();
highlights.getChildren().add(edges);
highlights.getChildren().add(points);
Platform.runLater(() -> world.getChildren().add(highlights));
}
public void clearHighlights() {
points.getChildren().clear();
edges.getChildren().clear();
}
public void changeScaling(double translateZ) {
scale = Math.abs(translateZ);
scale = Math.min(150, scale);
scale = Math.max(10, scale);
scale = scale * 0.01;
for (Node n : points.getChildren()) {
n.setScaleX(scale);
n.setScaleY(scale);
n.setScaleZ(scale);
}
double edgeSize = scale / 10;
for (Node n : edges.getChildren()) {
if (n instanceof Cylinder cy) {
cy.setRadius(edgeSize);
}
}
}
public void highlight(Polygon p, TriangulatedGeometry currentTriGeom) {
clearHighlights();
addHighlight(p, currentTriGeom, Color.RED, Color.BLUE);
}
private void addHighlight(Polygon p, TriangulatedGeometry currentTriGeom, Color extColor, Color intColor) {
if (currentTriGeom == null || p == null) {
return;
}
addHighlight(p.getExteriorRing(), currentTriGeom, extColor);
for (LinearRing intRing : p.getInnerRings()) {
addHighlight(intRing, currentTriGeom, intColor);
}
}
public void highlight(LinearRing ring, TriangulatedGeometry currentTriGeom) {
clearHighlights();
if (ring.getType() == LinearRingType.EXTERIOR) {
addHighlight(ring, currentTriGeom, Color.RED);
} else {
addHighlight(ring, currentTriGeom, Color.BLUE);
}
}
public void highlight(List<LinearRing> rings, TriangulatedGeometry currentTriGeom) {
clearHighlights();
for (LinearRing lr : rings) {
if (lr.getType() == LinearRingType.EXTERIOR) {
addHighlight(lr, currentTriGeom, Color.RED);
} else {
addHighlight(lr, currentTriGeom, Color.BLUE);
}
}
}
private void addHighlight(LinearRing ring, TriangulatedGeometry currentTriGeom, Color pointColor) {
if (currentTriGeom == null || ring == null) {
return;
}
Vector3d movedBy = currentTriGeom.getMovedBy();
for (Vertex v : ring.getVertices()) {
highlightPoint(movedBy, v, pointColor);
}
for (int i = 0; i < ring.getVertices().size() - 1; i++) {
Vertex v1 = ring.getVertices().get(i);
Vertex v2 = ring.getVertices().get(i + 1);
highlightEdge(v1, v2, movedBy);
}
}
public void highlight(Edge e, TriangulatedGeometry currentTriGeom) {
clearHighlights();
addHighlight(e, currentTriGeom);
}
private void addHighlight(Edge e, TriangulatedGeometry currentTriGeom) {
if (currentTriGeom == null || e == null) {
return;
}
Vector3d movedBy = currentTriGeom.getMovedBy();
highlightEdge(e.getFrom(), e.getTo(), movedBy);
highlightPoint(movedBy, e.getFrom(), Color.RED);
highlightPoint(movedBy, e.getTo(), Color.RED);
}
public void highlight(Vertex v, TriangulatedGeometry currentTriGeom) {
clearHighlights();
addHighlight(v, currentTriGeom, Color.RED);
}
public void addHighlight(Vertex v, TriangulatedGeometry currentTriGeom, Color c) {
if (currentTriGeom == null || v == null) {
return;
}
Vector3d movedBy = currentTriGeom.getMovedBy();
highlightPoint(movedBy, v, c);
}
private void highlightPoint(Vector3d movedBy, Vertex v, Color color) {
Sphere sp = new Sphere(0.5);
sp.setMaterial(new PhongMaterial(color));
sp.setTranslateX(v.getX() - movedBy.getX());
sp.setTranslateY(v.getY() - movedBy.getY());
sp.setTranslateZ(v.getZ() - movedBy.getZ());
sp.setScaleX(scale);
sp.setScaleY(scale);
sp.setScaleZ(scale);
sp.setUserData(new VertexClickDispatcher(v));
points.getChildren().add(sp);
}
private void highlightEdge(Vector3d v1, Vector3d v2, Vector3d movedBy) {
Point3D origin = new Point3D(v1.getX() - movedBy.getX(), v1.getY() - movedBy.getY(),
v1.getZ() - movedBy.getZ());
Point3D target = new Point3D(v2.getX() - movedBy.getX(), v2.getY() - movedBy.getY(),
v2.getZ() - movedBy.getZ());
Point3D yAxis = new Point3D(0, 1, 0);
Point3D diff = target.subtract(origin);
double height = diff.magnitude();
Point3D mid = target.midpoint(origin);
Translate moveToMidpoint = new Translate(mid.getX(), mid.getY(), mid.getZ());
Point3D axisOfRotation = diff.crossProduct(yAxis);
double angle = Math.acos(diff.normalize().dotProduct(yAxis));
Rotate rotateAroundCenter = new Rotate(-Math.toDegrees(angle), axisOfRotation);
Cylinder cy = new Cylinder(scale / 10, height);
cy.setMaterial(new PhongMaterial(Color.ORANGE));
cy.getTransforms().addAll(moveToMidpoint, rotateAroundCenter);
edges.getChildren().add(cy);
}
public void highlightEdges(List<Edge> errorEdges, TriangulatedGeometry currentTriGeom) {
clearHighlights();
for (Edge e : errorEdges) {
addHighlight(e, currentTriGeom);
}
}
public void highlightPolygons(List<List<Polygon>> components, TriangulatedGeometry currentTriGeom) {
clearHighlights();
for (int i = 0; i < components.size(); i++) {
Color extColor;
Color intColor = switch (i % 3) {
case 1 -> {
extColor = Color.GREEN;
yield Color.YELLOW;
}
case 2 -> {
extColor = Color.BROWN;
yield Color.VIOLET;
}
default -> {
extColor = Color.RED;
yield Color.BLUE;
}
};
// select some color pairs for exterior and inner rings
List<Polygon> component = components.get(i);
for (Polygon p : component) {
addHighlight(p, currentTriGeom, extColor, intColor);
}
}
}
public void addHighlight(Polygon p, TriangulatedGeometry currentTriGeom) {
addHighlight(p, currentTriGeom, Color.RED, Color.BLUE);
}
public void highlight(Triangle3d t, TriangulatedGeometry currentTriGeom) {
highlightEdge(t.getP1(), t.getP2(), currentTriGeom.getMovedBy());
highlightEdge(t.getP2(), t.getP3(), currentTriGeom.getMovedBy());
highlightEdge(t.getP3(), t.getP1(), currentTriGeom.getMovedBy());
}
}
/*-
* 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
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.gui;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javafx.scene.control.ListCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
public class LanguageSelectorCell extends ListCell<Locale> {
private static Map<String, Image> imageCache = new HashMap<>();
@Override
protected void updateItem(Locale item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
String country = item.getLanguage().toLowerCase(Locale.US);
Image iconRef = imageCache.computeIfAbsent(country, key -> {
String iconPath = "icons/icon_" + country + ".png";
return new Image(MainWindow.class.getResourceAsStream(iconPath));
});
ImageView iconImageView = new ImageView(iconRef);
setGraphic(iconImageView);
}
}
}
package de.hft.stuttgart.citydoctor2.gui;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeInvalidError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError;
import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError;
import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError;
import de.hft.stuttgart.citydoctor2.check.error.NestedRingError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldVertexError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonNormalsDeviation;
import de.hft.stuttgart.citydoctor2.check.error.NotCeilingError;
import de.hft.stuttgart.citydoctor2.check.error.NotFloorError;
import de.hft.stuttgart.citydoctor2.check.error.NotGroundError;
import de.hft.stuttgart.citydoctor2.check.error.NotWallError;
import de.hft.stuttgart.citydoctor2.check.error.NullAreaError;
import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.check.error.RingNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
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 javafx.scene.paint.Color;
public class ListErrorVisitor implements ErrorVisitor {
private HighlightController controller;
private TriangulatedGeometry geom;
public ListErrorVisitor(HighlightController controller) {
this.controller = controller;
}
public void setGeometry(TriangulatedGeometry geom) {
this.geom = geom;
}
@Override
public void visit(PolygonHoleOutsideError err) {
List<LinearRing> highlightedRings = new ArrayList<>();
highlightedRings.add(err.getPolygon().getExteriorRing());
highlightedRings.addAll(err.getHolesOutside());
controller.highlight(highlightedRings, geom);
}
@Override
public void visit(NonManifoldEdgeError err) {
controller.highlightEdges(err.getEdges(), geom);
}
@Override
public void visit(MultipleConnectedComponentsError err) {
controller.highlightPolygons(err.getComponents(), geom);
}
@Override
public void visit(NestedRingError err) {
List<LinearRing> highlightedRings = new ArrayList<>();
highlightedRings.add(err.getPolygon().getExteriorRing());
highlightedRings.add(err.getInnerRing());
controller.highlight(highlightedRings, geom);
}
@Override
public void visit(NonManifoldVertexError err) {
controller.highlightPolygons(err.getComponents(), geom);
controller.addHighlight(err.getVertex(), geom, Color.BLUEVIOLET);
}
@Override
public void visit(PolygonWrongOrientationError err) {
controller.highlightEdges(err.getEdges(), geom);
}
@Override
public void visit(PolygonSameOrientationError err) {
List<LinearRing> highlightedRings = new ArrayList<>();
highlightedRings.add(err.getPolygon().getExteriorRing());
highlightedRings.add(err.getInnerRing());
controller.highlight(highlightedRings, geom);
}
@Override
public void visit(SolidNotClosedError err) {
controller.highlightEdges(err.getErrorEdges(), geom);
}
@Override
public void visit(DependenciesNotMetError err) {
// don't display
}
@Override
public void visit(UnknownCheckError err) {
// don't display
}
@Override
public void visit(RingNotClosedError err) {
controller.highlight(err.getRing(), geom);
}
@Override
public void visit(ConsecutivePointSameError err) {
controller.highlight(err.getRing(), geom);
controller.addHighlight(err.getVertex1(), geom, Color.BLACK);
controller.addHighlight(err.getVertex2(), geom, Color.BLACK);
}
@Override
public void visit(AllPolygonsWrongOrientationError err) {
// don't display
}
@Override
public void visit(PolygonInteriorDisconnectedError err) {
controller.highlight(err.getConnectedRings(), geom);
}
@Override
public void visit(NullAreaError err) {
// don't display
}
@Override
public void visit(RingTooFewPointsError err) {
controller.highlight(err.getRing(), geom);
}
@Override
public void visit(NonPlanarPolygonNormalsDeviation err) {
controller.highlight(err.getPolygon(), geom);
}
@Override
public void visit(NonPlanarPolygonDistancePlaneError err) {
controller.highlight(err.getPolygon(), geom);
controller.addHighlight(err.getVertex(), geom, Color.BLACK);
}
@Override
public void visit(PolygonIntersectingRingsError err) {
List<LinearRing> rings = new ArrayList<>();
rings.add(err.getIntersectingRings().getValue0());
rings.add(err.getIntersectingRings().getValue1());
controller.highlight(rings, geom);
}
@Override
public void visit(SolidSelfIntError err) {
// nothing to display for now
}
@Override
public void visit(TooFewPolygonsError err) {
// don't display
}
@Override
public void visit(RingDuplicatePointError err) {
controller.highlight(err.getRing(), geom);
controller.addHighlight(err.getVertex1(), geom, Color.BLACK);
controller.addHighlight(err.getVertex2(), geom, Color.BLACK);
}
@Override
public void visit(RingEdgeIntersectionError err) {
List<Edge> list = new ArrayList<>();
list.add(err.getEdge1());
list.add(err.getEdge2());
controller.highlightEdges(list, geom);
controller.addHighlight(new Vertex(err.getIntersection()), geom, Color.BLACK);
}
@Override
public void visit(PointTouchesEdgeError err) {
controller.highlight(err.getEdge(), geom);
controller.addHighlight(err.getVertex(), geom, Color.BLACK);
}
@Override
public void visit(CheckError err) {
// nothing to display
}
@Override
public void visit(NotCeilingError err) {
// nothing to display
}
@Override
public void visit(NotFloorError err) {
// nothing to display
}
@Override
public void visit(NotWallError err) {
// nothing to display
}
@Override
public void visit(NotGroundError err) {
// nothing to display
}
@Override
public void visit(SchematronError err) {
// nothing to display
}
@Override
public void visit(SurfaceUnfragmentedError err) {
// nothing to display
}
@Override
public void visit(DegeneratedRingError err) {
controller.highlight(err.getRing(), geom);
}
@Override
public void visit(AttributeMissingError err) {
// nothing to display
}
@Override
public void visit(AttributeValueWrongError err) {
// nothing to display
}
@Override
public void visit(AttributeInvalidError err) {
// nothing to display
}
@Override
public void visit(PolygonWithoutSurfaceError err) {
controller.highlight(err.getPolygon(), geom);
}
}
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