diff --git a/README.md b/README.md
index ea1a768..287f039 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Semviz
-![Tag](https://img.shields.io/badge/tag-v1.0.0-blue.svg) [![Build Status](https://travis-ci.com/vmoglan/semviz.svg?branch=master)](https://travis-ci.org/vmoglan/semviz)
+![Tag](https://img.shields.io/badge/tag-v1.0.1-blue.svg) [![Build Status](https://travis-ci.com/vmoglan/semviz.svg?branch=master)](https://travis-ci.org/vmoglan/semviz)
## Main objective
@@ -24,7 +24,7 @@ The display of 3D objects must be done in three ways:
### Setup
-You can download the Semviz all-in-one `.jar` at this [link](https://github.com/vmoglan/semviz/releases/download/v1.0.0/semviz-1.0.0.jar). There is no installation process, just make sure you have Java 8 installed on your marchine and then you should be able to run the file.
+You can download the Semviz all-in-one `.jar` at this [link](https://github.com/vmoglan/semviz/releases/download/v1.0.1/semviz-1.0.1.jar). There is no installation process, just make sure you have Java 8 installed on your marchine and then you should be able to run the file.
### Initialization
diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index 8d4d295..5b68682 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -4,7 +4,7 @@
com.movlad
semviz
Semviz
- 1.0.0
+ 1.0.1
A viewer for semantically annotated three-dimensional point clouds.
diff --git a/pom.xml b/pom.xml
index 6d9a041..2c4df5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.movlad
semviz
- 1.0.0
+ 1.0.1
Semviz
A viewer for semantically annotated three-dimensional point clouds.
diff --git a/src/main/java/com/movlad/semviz/application/CommandNavigationController.java b/src/main/java/com/movlad/semviz/application/CommandNavigationController.java
index 2e8e544..787a786 100644
--- a/src/main/java/com/movlad/semviz/application/CommandNavigationController.java
+++ b/src/main/java/com/movlad/semviz/application/CommandNavigationController.java
@@ -9,18 +9,14 @@
public final class CommandNavigationController extends Controller {
private final List commands;
- private int selectedIndex;
+ private int selectedCommandIndex;
public CommandNavigationController() {
commands = new ArrayList<>();
commands.add("");
- selectedIndex = commands.size() - 1;
- }
-
- public String getSelection() {
- return commands.get(selectedIndex);
+ selectedCommandIndex = commands.size() - 1;
}
/**
@@ -30,18 +26,21 @@ public String getSelection() {
*/
public void enter(String command) {
commands.add(commands.size() - 1, command);
+
+ changeSupport.firePropertyChange("CommandLaunch", null, command);
}
/**
* Selects previous command.
*/
public void up() {
- if (selectedIndex - 1 >= 0) {
- String prev = getSelection();
+ if (selectedCommandIndex - 1 >= 0) {
+ String prev = commands.get(selectedCommandIndex);
- selectedIndex--;
+ selectedCommandIndex--;
- changeSupport.firePropertyChange("CommandNavigationUp", prev, getSelection());
+ changeSupport.firePropertyChange("CommandNavigationUp", prev,
+ commands.get(selectedCommandIndex));
}
}
@@ -49,12 +48,13 @@ public void up() {
* Selects a more recent command.
*/
public void down() {
- if (selectedIndex + 1 < commands.size()) {
- String prev = getSelection();
+ if (selectedCommandIndex + 1 < commands.size()) {
+ String prev = commands.get(selectedCommandIndex);
- selectedIndex++;
+ selectedCommandIndex++;
- changeSupport.firePropertyChange("CommandNavigationDown", prev, getSelection());
+ changeSupport.firePropertyChange("CommandNavigationDown", prev,
+ commands.get(selectedCommandIndex));
}
}
diff --git a/src/main/java/com/movlad/semviz/application/QueryManagerController.java b/src/main/java/com/movlad/semviz/application/QueryManagerController.java
deleted file mode 100644
index 763f69e..0000000
--- a/src/main/java/com/movlad/semviz/application/QueryManagerController.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.movlad.semviz.application;
-
-import com.movlad.semviz.core.io.DirectoryLoader;
-import com.movlad.semviz.core.io.InvalidDirectoryException;
-import com.movlad.semviz.core.semantic.QueryManager;
-import com.movlad.semviz.core.semantic.QueryResult;
-import java.nio.file.NotDirectoryException;
-import java.util.List;
-
-/**
- * Controller that creates a bridge between the view and the query manager
- * model; SPARQL queries can be executed through this controller.
- */
-public final class QueryManagerController extends Controller {
-
- private QueryManager queryManager;
- private List queryResults;
-
- public QueryManager getQueryManager() {
- return queryManager;
- }
-
- public List getQueryResults() {
- return queryResults;
- }
-
- /**
- * Given a Semviz directory, this method loads a
- * {@link com.movlad.semviz.core.semantic.QueryManager} from the ontology
- * file within it and notifies the property change listeners of the success
- * or failure.
- *
- * @param path is the path to the Semviz directory
- */
- public void loadQueryManager(String path) {
- QueryManager prev = queryManager;
-
- queryManager = null;
-
- if (queryResults != null) {
- queryResults.clear();
- }
-
- try {
- DirectoryLoader loader = new DirectoryLoader(path);
-
- loader.load();
-
- queryManager = new QueryManager(loader);
-
- changeSupport.firePropertyChange("QueryManagerLoadSuccess", prev, queryManager);
- } catch (InvalidDirectoryException | NotDirectoryException e) {
- changeSupport.firePropertyChange("QueryManagerLoadError", null, e.getMessage());
- }
- }
-
- /**
- * Executes a query on the currently loaded
- * {@link com.movlad.semviz.core.semantic.QueryManager}, generates a
- * {@link com.movlad.semviz.core.semantic.SemanticCloud} formed by all the
- * clouds retrieved using the query.
- *
- * @param queryString is the string of the query to be executed
- */
- public void executeQuery(String queryString) {
- List prev = queryResults;
-
- try {
- queryResults = queryManager.query(queryString);
-
- changeSupport.firePropertyChange("QueryExecutionSuccess", prev, queryResults);
- } catch (Exception e) {
- changeSupport.firePropertyChange("QueryExecutionError", null, e.getMessage());
- }
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/application/SQMController.java b/src/main/java/com/movlad/semviz/application/SQMController.java
new file mode 100644
index 0000000..a297a77
--- /dev/null
+++ b/src/main/java/com/movlad/semviz/application/SQMController.java
@@ -0,0 +1,99 @@
+package com.movlad.semviz.application;
+
+import com.movlad.semviz.core.io.InvalidDirectoryException;
+import com.movlad.semviz.core.sqm.SQM;
+import com.movlad.semviz.core.sqm.SemanticCloudDescription;
+import java.io.FileNotFoundException;
+import java.nio.file.NotDirectoryException;
+import java.util.List;
+
+/**
+ * Controller for the Semviz Query Manager.
+ */
+public final class SQMController extends Controller {
+
+ private static SQMController instance = null;
+ private final SQM sqm; // the unique instance of the Semviz Query Manager
+ private List descriptions; // the list of current query results
+ private int selectedDescriptionIndex; // the currently selected Description
+
+ private SQMController() {
+ sqm = SQM.getInstance();
+ selectedDescriptionIndex = -1;
+ }
+
+ public static SQMController getInstance() {
+ if (instance == null) {
+ instance = new SQMController();
+ }
+
+ return instance;
+ }
+
+ /**
+ * @return the currently selected description
+ */
+ public SemanticCloudDescription getSelectedDescription() {
+ if (selectedDescriptionIndex > -1
+ && selectedDescriptionIndex < descriptions.size()) {
+ return descriptions.get(selectedDescriptionIndex);
+ }
+
+ return null;
+ }
+
+ /**
+ * Given a Semviz directory, this method loads a Semviz directory into the
+ * Semviz query manager singleton.
+ *
+ * @param path is the path to the Semviz directory
+ */
+ public void load(String path) {
+ if (descriptions != null) {
+ descriptions.clear();
+ }
+
+ try {
+ sqm.load(path);
+
+ changeSupport.firePropertyChange("SQMLoadSuccess", null, sqm);
+ } catch (InvalidDirectoryException | NotDirectoryException | FileNotFoundException e) {
+ changeSupport.firePropertyChange("SQMLoadError", null, e.getMessage());
+ }
+ }
+
+ /**
+ * Executes a query on the currently loaded Semviz directory.
+ *
+ * @param queryString is the string of the query to be executed
+ */
+ public void exec(String queryString) {
+ List prevDescriptions = descriptions;
+
+ try {
+ changeSupport.firePropertyChange("SQMExecutionStarted", null, sqm);
+
+ descriptions = sqm.exec(queryString);
+
+ changeSupport.firePropertyChange("SQMFailCountChanged", null, sqm.getFailCount());
+ changeSupport.firePropertyChange("SQMExecutionSuccess", prevDescriptions, descriptions);
+ } catch (Exception e) {
+ changeSupport.firePropertyChange("SQMExecutionError", null, e.getMessage());
+ }
+ }
+
+ /**
+ * Sets the selected semantic cloud description index.
+ *
+ * @param i is the index of the selected description
+ */
+ public void setSelectedDescriptionIndex(int i) {
+ int prev = selectedDescriptionIndex;
+
+ selectedDescriptionIndex = i;
+
+ changeSupport.firePropertyChange("SQMDescriptionIndexChanged", prev,
+ selectedDescriptionIndex);
+ }
+
+}
diff --git a/src/main/java/com/movlad/semviz/application/SceneController.java b/src/main/java/com/movlad/semviz/application/SceneController.java
index 0297d21..eab8b33 100644
--- a/src/main/java/com/movlad/semviz/application/SceneController.java
+++ b/src/main/java/com/movlad/semviz/application/SceneController.java
@@ -1,14 +1,17 @@
package com.movlad.semviz.application;
+import com.github.quickhull3d.Point3d;
+import com.github.quickhull3d.Vector3d;
import com.movlad.semviz.core.graphics.Geometry;
import com.movlad.semviz.core.graphics.GeometryFactory;
import com.movlad.semviz.core.graphics.Scene;
import com.movlad.semviz.core.graphics.SceneObject;
import com.movlad.semviz.core.math.geometry.BoundingBox;
import com.movlad.semviz.core.math.geometry.PointCloud;
-import com.movlad.semviz.core.semantic.SemanticCloud;
+import com.movlad.semviz.core.sqm.SemanticCloudDescription;
import java.util.ArrayList;
import java.util.List;
+import org.joml.Vector3f;
/**
* Controller for the modification of a {@code Scene} and view in general.
@@ -38,16 +41,18 @@ public Scene getScene() {
/**
* Loads the base geometry for each cloud in a semantic cloud
*
- * @param cloud is the cloud containing the clusters
+ * @param descriptions
*/
- public void loadDisplayInformation(SemanticCloud cloud) {
+ public void load(List descriptions) {
resetDisplayInformation();
+ center(descriptions);
+ rotate(descriptions);
- views = new SceneObject[cloud.size()][3];
- selectedViewIndices = new int[cloud.size()];
+ views = new SceneObject[descriptions.size()][3];
+ selectedViewIndices = new int[descriptions.size()];
- for (int i = 0; i < cloud.size(); i++) {
- clusters.add(cloud.get(i));
+ for (int i = 0; i < descriptions.size(); i++) {
+ clusters.add(descriptions.get(i).getCloud());
SceneObject object = new SceneObject(GeometryFactory.getInstance()
.createHighResolutionCloudGeometry(clusters.get(i)));
@@ -87,8 +92,6 @@ public int getSelectedViewIndex(int i) {
* @param view is the view selection for the cluster at index {@code i}
*/
public void setSelectedViewIndex(int i, int view) {
- int prev = selectedViewIndices[i];
-
selectedViewIndices[i] = view;
if (views[i][view] == null) {
@@ -117,7 +120,7 @@ public void setSelectedViewIndex(int i, int view) {
scene.replace(i, object);
- changeSupport.firePropertyChange("SelectedViewIndexUpdate", prev, selectedViewIndices[i]);
+ changeSupport.firePropertyChange("SceneViewIndexUpdate", null, scene);
}
/**
@@ -135,7 +138,56 @@ public void setDisplaySelection(int i) {
scene.add(new SceneObject("selection", geometry));
}
- changeSupport.firePropertyChange("SceneSelectionUpdate", null, i);
+ changeSupport.firePropertyChange("SceneSelectionUpdate", null, scene);
+ }
+
+ /**
+ * Centers the cluster contained within each semantic description according
+ * to a common centroid.
+ *
+ * @param descriptions is a list of semantic cloud descriptions, each
+ * containing a cluster.
+ */
+ private void center(List descriptions) {
+ Point3d centroid = new Point3d(0, 0, 0);
+ int size = 0;
+
+ for (SemanticCloudDescription description : descriptions) {
+ PointCloud cluster = description.getCloud();
+
+ size += cluster.size();
+
+ cluster.forEach(point -> {
+ centroid.add(new Vector3d(point.x, point.y, point.z));
+ });
+ }
+
+ centroid.set(centroid.x / size, centroid.y / size, centroid.z / size);
+
+ descriptions.stream().map((description) -> description.getCloud()).forEachOrdered((cluster) -> {
+ cluster.forEach(point -> {
+ point.sub(centroid);
+ });
+ });
+ }
+
+ /**
+ * Rotates the cluster of each semantic description so that the up vector of
+ * the whole corresponds to the world Z-axis.
+ *
+ * @param descriptions is a list of semantic cloud descriptions, each
+ * containing a cluster.
+ */
+ private void rotate(List descriptions) {
+ descriptions.stream().map((description) -> description.getCloud()).forEachOrdered((cluster) -> {
+ cluster.forEach(point -> {
+ Vector3f v = new Vector3f((float) point.x, (float) point.y, (float) point.z);
+
+ v.rotateAxis((float) (Math.PI / 2), 0.0f, 1.0f, 0.0f);
+
+ point.set(v.x, v.y, v.z);
+ });
+ });
}
}
diff --git a/src/main/java/com/movlad/semviz/application/SemanticCloudController.java b/src/main/java/com/movlad/semviz/application/SemanticCloudController.java
deleted file mode 100644
index 561a0aa..0000000
--- a/src/main/java/com/movlad/semviz/application/SemanticCloudController.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.movlad.semviz.application;
-
-import com.movlad.semviz.core.semantic.QueryManager;
-import com.movlad.semviz.core.semantic.QueryResult;
-import com.movlad.semviz.core.semantic.SemanticCloud;
-import java.util.List;
-
-/**
- * Controller that notifies listeners about change concerning a loaded semantic
- * cloud.
- */
-public final class SemanticCloudController extends Controller {
-
- private SemanticCloud semanticCloud;
-
- /**
- * Loads a semantic cloud from a list of results issued from a query manager
- * and notifies listeners.
- *
- * @param queryManager contains the model from which the results are issued
- * @param queryResults are the results issued from a SPARQL query
- */
- public void loadSuperCloud(QueryManager queryManager, List queryResults) {
- SemanticCloud prev = semanticCloud;
-
- semanticCloud = new SemanticCloud(queryManager, queryResults);
-
- semanticCloud.load();
- changeSupport.firePropertyChange("SemanticCloudChange", prev, semanticCloud);
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/graphics/BufferAttribute.java b/src/main/java/com/movlad/semviz/core/graphics/BufferAttribute.java
index 58e039e..9e2c82c 100644
--- a/src/main/java/com/movlad/semviz/core/graphics/BufferAttribute.java
+++ b/src/main/java/com/movlad/semviz/core/graphics/BufferAttribute.java
@@ -6,7 +6,7 @@
* Class representing one attribute of a buffer layout, such as position, color
* or texture coordinates.
*/
-class BufferAttribute {
+public class BufferAttribute {
private final String name;
private final int size;
diff --git a/src/main/java/com/movlad/semviz/core/graphics/BufferLayout.java b/src/main/java/com/movlad/semviz/core/graphics/BufferLayout.java
index bc9896b..cfe8c83 100644
--- a/src/main/java/com/movlad/semviz/core/graphics/BufferLayout.java
+++ b/src/main/java/com/movlad/semviz/core/graphics/BufferLayout.java
@@ -9,7 +9,7 @@
* {@code VertexBufferObject}, such as position, color, texture coordinates etc.
* .
*/
-class BufferLayout implements Iterable {
+public class BufferLayout implements Iterable {
private final List attributes;
private int stride = 0;
diff --git a/src/main/java/com/movlad/semviz/core/graphics/Renderer.java b/src/main/java/com/movlad/semviz/core/graphics/Renderer.java
index b5739e9..8621f8d 100644
--- a/src/main/java/com/movlad/semviz/core/graphics/Renderer.java
+++ b/src/main/java/com/movlad/semviz/core/graphics/Renderer.java
@@ -15,8 +15,8 @@
*/
public abstract class Renderer implements GLEventListener {
- private final Scene scene;
- private final Camera camera;
+ private volatile Scene scene;
+ private Camera camera;
private ShaderProgram program;
@@ -24,10 +24,16 @@ public abstract class Renderer implements GLEventListener {
private IntBuffer vaos;
private IntBuffer vbos;
- public Renderer(Scene scene, Camera camera) {
+ public Renderer() {
+ this.VAO = IntBuffer.allocate(1);
+ }
+
+ public final void setScene(Scene scene) {
this.scene = scene;
+ }
+
+ public final void setCamera(Camera camera) {
this.camera = camera;
- this.VAO = IntBuffer.allocate(1);
}
@Override
diff --git a/src/main/java/com/movlad/semviz/core/io/CloudLoader.java b/src/main/java/com/movlad/semviz/core/io/CloudLoader.java
index 3e56dad..06895e4 100644
--- a/src/main/java/com/movlad/semviz/core/io/CloudLoader.java
+++ b/src/main/java/com/movlad/semviz/core/io/CloudLoader.java
@@ -11,33 +11,24 @@
*/
public class CloudLoader {
+ private final int POINT_ATTR_COUNT = 9;
private String path;
- private boolean normalsIncluded;
-
- private int numInvalidLines;
-
+ private int failCount;
private PointCloud pointCloud;
/**
* @param path is the path of the cloud {@code .txt} file
- * @param normalsIncluded is true if the file also contains the normal
- * vectors in each point
*/
- public CloudLoader(String path, boolean normalsIncluded) {
+ public CloudLoader(String path) {
this.path = path;
- this.normalsIncluded = normalsIncluded;
}
public void setPath(String path) {
this.path = path;
}
- public void setNormalsIncluded(boolean normalsIncluded) {
- this.normalsIncluded = normalsIncluded;
- }
-
- public int getNumInvalidLines() {
- return numInvalidLines;
+ public int getFailCount() {
+ return failCount;
}
/**
@@ -54,15 +45,7 @@ public PointCloud getCloud() {
* @throws IOException if the cloud file is not found
*/
public void load() throws IOException {
- int numFields;
-
- numInvalidLines = 0;
-
- if (normalsIncluded) {
- numFields = 9;
- } else {
- numFields = 6;
- }
+ failCount = 0;
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
pointCloud = new PointCloud();
@@ -70,26 +53,28 @@ public void load() throws IOException {
for (String line; (line = reader.readLine()) != null;) {
String[] attributes = line.split("\\t");
- if (attributes.length == numFields) {
- Point point = new Point();
+ if (attributes.length == POINT_ATTR_COUNT) {
+ try {
+ Point point = new Point();
- point.x = Float.parseFloat(attributes[0]);
- point.y = Float.parseFloat(attributes[1]);
- point.z = Float.parseFloat(attributes[2]);
+ point.x = Float.parseFloat(attributes[0]);
+ point.y = Float.parseFloat(attributes[1]);
+ point.z = Float.parseFloat(attributes[2]);
- point.r = Short.parseShort(attributes[3]);
- point.g = Short.parseShort(attributes[4]);
- point.b = Short.parseShort(attributes[5]);
+ point.r = Short.parseShort(attributes[3]);
+ point.g = Short.parseShort(attributes[4]);
+ point.b = Short.parseShort(attributes[5]);
- if (numFields == 9) {
point.normalX = Float.parseFloat(attributes[6]);
point.normalY = Float.parseFloat(attributes[7]);
point.normalZ = Float.parseFloat(attributes[8]);
- }
- pointCloud.add(point);
+ pointCloud.add(point);
+ } catch (NumberFormatException e) {
+ failCount++;
+ }
} else {
- numInvalidLines++;
+ failCount++;
}
}
}
diff --git a/src/main/java/com/movlad/semviz/core/io/DirectoryLoader.java b/src/main/java/com/movlad/semviz/core/io/DirectoryLoader.java
deleted file mode 100644
index b65ed2a..0000000
--- a/src/main/java/com/movlad/semviz/core/io/DirectoryLoader.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package com.movlad.semviz.core.io;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.nio.file.NotDirectoryException;
-import org.apache.jena.ontology.OntModel;
-import org.apache.jena.rdf.model.ModelFactory;
-
-/**
- * Used for validating and loading a Semviz directory.
- */
-public class DirectoryLoader {
-
- private final String dirPath;
- private OntModel model;
- private File cloudsDir;
- private boolean isValid;
-
- /**
- * @param dirPath is the path to the directory
- */
- public DirectoryLoader(String dirPath) {
- this.dirPath = dirPath;
- this.isValid = false;
- }
-
- /**
- * @throws InvalidDirectoryException if something goes wrong when loading a
- * directory
- * @throws java.nio.file.NotDirectoryException if the file at the given path
- * is not a directory
- */
- public void load() throws InvalidDirectoryException, NotDirectoryException {
- this.model = null;
-
- File dir = new File(dirPath);
-
- if (!dir.exists()) {
- throw new InvalidDirectoryException("Directory does not exist");
- }
-
- if (!dir.isDirectory()) {
- throw new NotDirectoryException("File is not a directory.");
- }
-
- model = null;
-
- if (!containsValidOntology(dir) || !containsCloudsDir(dir)) {
- throw new InvalidDirectoryException("Invalid directory structure.");
- }
-
- this.isValid = true;
- }
-
- public boolean isValid() {
- return isValid;
- }
-
- public OntModel getModel() {
- return model;
- }
-
- public File getCloudsDir() {
- return cloudsDir;
- }
-
- /**
- * Called within the constructor, this method checks whether the path in the
- * parameter leads to a valid Semviz directory.
- *
- * @param dirPath is the path that leads to the directory
- */
- private boolean validateDir(String dirPath) {
- this.model = null;
-
- File dir = new File(dirPath);
-
- if (!dir.exists()) {
- return false;
- }
-
- if (!dir.isDirectory()) {
- return false;
- }
-
- model = null;
-
- return containsValidOntology(dir) && containsCloudsDir(dir);
- }
-
- /**
- * @param dir gives the array of files in the directory
- * @returns true if the a Knowdip ontology is found in the directory and it
- * is valid
- */
- private boolean containsValidOntology(File dir) {
- File[] files = dir.listFiles();
-
- for (File file : files) {
- if (file.getName().toLowerCase().endsWith(".owl")) {
- model = ModelFactory.createOntologyModel();
-
- FileInputStream is;
-
- try {
- is = new FileInputStream(file.getAbsolutePath());
- } catch (FileNotFoundException e) {
- return false;
- }
-
- model.read(is, null);
-
- if (model.getNsPrefixURI("knowdip") == null) {
- model = null;
-
- return false;
- }
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param dir gives the array of files in the directory
- * @returns true if the directory contains a cloud folder
- */
- private boolean containsCloudsDir(File dir) {
- File[] files = dir.listFiles();
-
- for (File file : files) {
- if (file.getName().toLowerCase().equals("clouds")) {
- if (file.isDirectory()) {
- cloudsDir = file;
-
- return true;
- }
- }
- }
-
- return false;
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/semantic/QueryExecutor.java b/src/main/java/com/movlad/semviz/core/semantic/QueryExecutor.java
deleted file mode 100644
index 9fda5aa..0000000
--- a/src/main/java/com/movlad/semviz/core/semantic/QueryExecutor.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.movlad.semviz.core.semantic;
-
-import java.util.*;
-import org.apache.jena.ontology.Individual;
-import org.apache.jena.ontology.OntClass;
-import org.apache.jena.ontology.OntModel;
-import org.apache.jena.query.*;
-import org.apache.jena.rdf.model.Literal;
-import org.apache.jena.rdf.model.RDFNode;
-import org.apache.jena.rdf.model.Resource;
-
-class QueryExecutor {
-
- private final Query query;
- private final OntModel model;
-
- public QueryExecutor(Query query, OntModel model) {
- this.query = query;
- this.model = model;
- }
-
- public List exec() {
- QueryExecution execution = QueryExecutionFactory.create(query, model);
- ResultSet results = execution.execSelect();
- List solutions = ResultSetFormatter.toList(results);
- List queryResults = new ArrayList<>();
-
- solutions.forEach(solution -> {
- Iterator varNameIt = solution.varNames();
- QueryResult result = new QueryResult();
-
- while (varNameIt.hasNext()) {
- String varName = varNameIt.next();
- RDFNode node = solution.get(varName);
- Individual cloud = validateCloudResource(node);
-
- if (cloud != null) {
- result.setIndividual(cloud);
- } else {
- if (node.isResource()) {
- result.putAttribute(varName, ((Resource) node).getURI());
- } else {
- result.putAttribute(varName, ((Literal) node).getLexicalForm());
- }
- }
- }
-
- if (result.getIndividual() != null) {
- queryResults.add(result);
- }
- });
-
- return queryResults;
- }
-
- private Individual validateCloudResource(RDFNode node) {
- if (node.isResource()) {
- String uri = node.asResource().getURI();
- Individual individual = model.getIndividual(uri);
- OntClass ontClass = model.getOntClass(model.getNsPrefixURI("knowdip") + "Point-Cloud");
-
- if (individual.getOntClass().hasSuperClass(ontClass)) {
- return individual;
- }
- }
-
- return null;
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/semantic/QueryManager.java b/src/main/java/com/movlad/semviz/core/semantic/QueryManager.java
deleted file mode 100644
index d8a59eb..0000000
--- a/src/main/java/com/movlad/semviz/core/semantic/QueryManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.movlad.semviz.core.semantic;
-
-import com.movlad.semviz.core.io.CloudLoader;
-import com.movlad.semviz.core.io.InvalidDirectoryException;
-import com.movlad.semviz.core.io.DirectoryLoader;
-import com.movlad.semviz.core.math.geometry.PointCloud;
-import java.io.IOException;
-import java.util.List;
-import org.apache.jena.ontology.Individual;
-import org.apache.jena.query.Query;
-import org.apache.jena.query.QueryFactory;
-
-public class QueryManager {
-
- private static final String NS = "http://lab.ponciano.info/knowdip#";
- private static final String PREFIX = "PREFIX knowdip: <" + NS + ">";
-
- DirectoryLoader dir;
-
- public QueryManager(DirectoryLoader dir) throws InvalidDirectoryException {
- if (!dir.isValid()) {
- throw new InvalidDirectoryException("Invalid parameter directory.");
- }
-
- this.dir = dir;
- }
-
- /**
- * Queries the loaded model and notifies the observers of a change in
- * results.Updates the {@code CanvasController}.
- *
- * @param queryString is the SPARQL query
- * @return a list of query results
- */
- public List query(String queryString) {
- Query query = QueryFactory.create(PREFIX + System.lineSeparator() + queryString);
- QueryExecutor queryExec = new QueryExecutor(query, dir.getModel());
-
- return queryExec.exec();
- }
-
- /**
- * @param cloudIndividual is the instance containing the semantic
- * description of a cloud
- * @return point cloud semantically described by the individual in parameter
- */
- public PointCloud retrieve(Individual cloudIndividual) {
- String pathToCloud = dir.getCloudsDir().getAbsolutePath()
- + "/" + cloudIndividual.getLocalName() + ".txt";
- CloudLoader loader = new CloudLoader(pathToCloud, true);
-
- try {
- loader.load();
- } catch (IOException e) {
- return null;
- }
-
- return loader.getCloud();
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/semantic/QueryResult.java b/src/main/java/com/movlad/semviz/core/semantic/QueryResult.java
deleted file mode 100644
index ec679aa..0000000
--- a/src/main/java/com/movlad/semviz/core/semantic/QueryResult.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.movlad.semviz.core.semantic;
-
-import org.apache.jena.ontology.Individual;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class QueryResult {
-
- private Individual individual;
- private Map attributes;
-
- public QueryResult() {
- individual = null;
- attributes = new HashMap<>();
- }
-
- public Individual getIndividual() {
- return individual;
- }
-
- public void setIndividual(Individual cloud) {
- this.individual = cloud;
- }
-
- public void putAttribute(String key, String value) {
- attributes.put(key, value);
- }
-
- public String getAttribute(String key) {
- return attributes.get(key);
- }
-
- public Set getKeys() {
- return attributes.keySet();
- }
-
- public Collection getValues() {
- return attributes.values();
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/semantic/SemanticCloud.java b/src/main/java/com/movlad/semviz/core/semantic/SemanticCloud.java
deleted file mode 100644
index 3a5d90a..0000000
--- a/src/main/java/com/movlad/semviz/core/semantic/SemanticCloud.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.movlad.semviz.core.semantic;
-
-import com.github.quickhull3d.Point3d;
-import com.github.quickhull3d.Vector3d;
-import com.movlad.semviz.core.math.geometry.PointCloud;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import org.joml.Vector3f;
-
-/**
- * When executing a SPARQL query via
- * {@link com.movlad.semviz.core.semantic.QueryManager}, multiple cloud
- * individuals are retrieved. These clusters that originate from the same base
- * cloud are not centered by default, and in order to center them, the centroid
- * of the base cloud needs to be subtracted from each of their points. This
- * class groups all of the retrieved clusters, calculates the centroid of their
- * base cloud and then centers them.
- */
-public class SemanticCloud implements Iterable {
-
- private final List clusters;
- private final QueryManager queryManager;
- private final List queryResults;
-
- /**
- * Constructor.
- *
- * @param queryManager holds the data of the currently loaded Semviz
- * directory
- * @param queryResults is the list of results obtained after the execution
- * of a SPARQL query on the query manager
- */
- public SemanticCloud(QueryManager queryManager, List queryResults) {
- this.clusters = new ArrayList<>();
- this.queryManager = queryManager;
- this.queryResults = queryResults;
- }
-
- public PointCloud get(int i) {
- return clusters.get(i);
- }
-
- /**
- * Retrieves all the clusters described by the query results, centers them
- * and rotates them.
- */
- public void load() {
- queryResults.forEach(result -> {
- clusters.add(queryManager.retrieve(result.getIndividual()));
- });
-
- center();
- rotate();
- }
-
- /**
- * Subtracts the centroid of the base cloud from each point of each cluster.
- */
- private void center() {
- Point3d centroid = new Point3d(0, 0, 0);
- int size = 0;
-
- for (PointCloud cluster : clusters) {
- size += cluster.size();
-
- cluster.forEach(point -> {
- centroid.add(new Vector3d(point.x, point.y, point.z));
- });
- }
-
- centroid.set(centroid.x / size, centroid.y / size, centroid.z / size);
-
- clusters.forEach(cluster -> {
- cluster.forEach(point -> {
- point.sub(centroid);
- });
- });
- }
-
- /**
- * Rotates each point of each cloud 90 degrees around the X-Axis so that
- * they are well aligned with the world up vector.
- */
- private void rotate() {
- for (PointCloud cluster : clusters) {
- cluster.forEach(point -> {
- Vector3f v = new Vector3f((float) point.x, (float) point.y, (float) point.z);
-
- v.rotateAxis((float) (Math.PI / 2), 0.0f, 1.0f, 0.0f);
-
- point.set(v.x, v.y, v.z);
- });
- }
- }
-
- public int size() {
- return clusters.size();
- }
-
- @Override
- public Iterator iterator() {
- return clusters.iterator();
- }
-
-}
diff --git a/src/main/java/com/movlad/semviz/core/sqm/SQM.java b/src/main/java/com/movlad/semviz/core/sqm/SQM.java
new file mode 100644
index 0000000..a3c919e
--- /dev/null
+++ b/src/main/java/com/movlad/semviz/core/sqm/SQM.java
@@ -0,0 +1,250 @@
+package com.movlad.semviz.core.sqm;
+
+import com.movlad.semviz.core.io.CloudLoader;
+import com.movlad.semviz.core.io.InvalidDirectoryException;
+import com.movlad.semviz.core.math.geometry.PointCloud;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.NotDirectoryException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.jena.ontology.Individual;
+import org.apache.jena.ontology.OntModel;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.QueryExecutionFactory;
+import org.apache.jena.query.QueryFactory;
+import org.apache.jena.query.QuerySolution;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.rdf.model.Literal;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+
+/**
+ * The Semviz Query Manager ({@code SQM}) is a singleton used for loading a
+ * Semviz directory and retrieving semantic descriptions of clouds using SPARQL
+ * queries.
+ */
+public class SQM {
+
+ private static SQM instance = null;
+ private OntModel model;
+ private String path;
+ private int failCount;
+
+ private SQM() {
+ failCount = 0;
+ }
+
+ public static SQM getInstance() {
+ if (instance == null) {
+ instance = new SQM();
+ }
+
+ return instance;
+ }
+
+ /**
+ * @return the active ontology model currently loaded within the query
+ * manager
+ */
+ public OntModel getModel() {
+ return model;
+ }
+
+ /**
+ * @return the path to the active Semviz directory
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return the number of {@code SemanticCloudDescription} instances that
+ * could not be retrieved on the last query
+ */
+ public int getFailCount() {
+ return failCount;
+ }
+
+ /**
+ * Attempts to load a Semviz directory.
+ *
+ * @param path is the absolute path to the Semviz directory to be loaded
+ * @throws FileNotFoundException if the file does not exist
+ * @throws NotDirectoryException if the file at the given path is not a
+ * directory
+ * @throws InvalidDirectoryException if the directory does not contain an
+ * ontology
+ */
+ public void load(String path) throws InvalidDirectoryException, NotDirectoryException,
+ FileNotFoundException {
+ failCount = 0;
+ model = null;
+
+ File directory = new File(path);
+
+ if (!directory.exists()) {
+ throw new InvalidDirectoryException("Directory does not exist");
+ }
+
+ if (!directory.isDirectory()) {
+ throw new NotDirectoryException("File is not a directory.");
+ }
+
+ File[] files = directory.listFiles();
+
+ for (File file : files) {
+ if (file.getName().toLowerCase().endsWith(".owl")) {
+ FileInputStream is = new FileInputStream(file.getAbsolutePath());
+
+ model = ModelFactory.createOntologyModel();
+
+ model.read(is, null);
+ }
+ }
+
+ if (model == null) {
+ throw new InvalidDirectoryException("Not a valid directory.");
+ }
+
+ this.path = path;
+ }
+
+ /**
+ * Executes a SPARQL query on the active Semviz directory and returns the
+ * list of successfully retrieved instances of
+ * {@code SemanticCloudDescription}.
+ *
+ * @param queryString is the SPARQL query to be executed
+ * @return the list of successfully retrieved instances of
+ * {@code SemanticCloudDescription}.
+ */
+ public List exec(String queryString) {
+ failCount = 0;
+
+ List descriptions = new ArrayList<>();
+ String prefixes = generatePrefixes();
+ Query query = QueryFactory.create(prefixes + queryString);
+ QueryExecution execution = QueryExecutionFactory.create(query, model);
+ ResultSet results = execution.execSelect();
+
+ while (results.hasNext()) {
+ QuerySolution solution = results.next();
+
+ SemanticCloudDescription result = processQuerySolution(solution);
+
+ if (result != null) {
+ descriptions.add(result);
+ } else {
+ failCount++;
+ }
+ }
+
+ return descriptions;
+ }
+
+ /**
+ * @return a String containing all the prefixes generated from the
+ * namespaces found in the active ontology
+ */
+ private String generatePrefixes() {
+ Map namespaceMap = model.getNsPrefixMap();
+ String prefixes = new String();
+
+ prefixes = namespaceMap.keySet().stream().map((key) -> "PREFIX " + key
+ + ": <" + namespaceMap.get(key) + ">"
+ + System.lineSeparator()).reduce(prefixes, String::concat);
+
+ return prefixes;
+ }
+
+ /**
+ * Maps an instance of {@code SemanticCloudDescription} to an instance of
+ * {@code QuerySolution}.
+ *
+ * @param solution is the instance of {@code QuerySolution} to be processed
+ * @return an instance of {@code SemanticCloudDescription} that corresponds
+ * to the parameter {@code QuerySolution}
+ */
+ private SemanticCloudDescription processQuerySolution(QuerySolution solution) {
+ SemanticCloudDescription result;
+ Iterator varNameIt = solution.varNames();
+ Individual individual = null;
+ Map attributes = new HashMap<>();
+ PointCloud cloud = null;
+
+ while (varNameIt.hasNext()) {
+ String varName = varNameIt.next();
+ RDFNode node = solution.get(varName);
+
+ individual = validateCloudResource(node);
+
+ if (individual == null) {
+ if (node.isResource()) {
+ attributes.put(varName, ((Resource) node).getURI());
+ } else {
+ attributes.put(varName, ((Literal) node).getLexicalForm());
+ }
+ } else {
+ cloud = retrieveCloud(individual);
+ }
+ }
+
+ if ((individual == null) || (cloud == null)) {
+ return null;
+ }
+
+ result = new SemanticCloudDescription(individual, attributes, cloud);
+
+ return result;
+ }
+
+ /**
+ * Validates an RDF node as a point cloud resource by checking whether its
+ * local name contains {@code PointCloud}.
+ *
+ * @param node is the RDF node to be checked
+ * @return an individual if a node is a valid {@code PointCloud} resource,
+ * {@code null} otherwise
+ */
+ private Individual validateCloudResource(RDFNode node) {
+ if (node.isResource()) {
+ String uri = node.asResource().getURI();
+ Individual individual = model.getIndividual(uri);
+
+ if (individual.getLocalName().contains("PointCloud")) {
+ return individual;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Retrieves a "physical" point cloud based on its semantic description.
+ *
+ * @param individual is an ontology individual that describes a point cloud
+ * @return the point cloud corresponding to a given ontology individual
+ */
+ private PointCloud retrieveCloud(Individual individual) {
+ String localName = individual.getLocalName();
+ String pathToCloud = path + "/clouds/" + localName + ".txt";
+ CloudLoader loader = new CloudLoader(pathToCloud);
+
+ try {
+ loader.load();
+ } catch (IOException ex) {
+ return null;
+ }
+
+ return loader.getCloud();
+ }
+
+}
diff --git a/src/main/java/com/movlad/semviz/core/sqm/SemanticCloudDescription.java b/src/main/java/com/movlad/semviz/core/sqm/SemanticCloudDescription.java
new file mode 100644
index 0000000..1418ef9
--- /dev/null
+++ b/src/main/java/com/movlad/semviz/core/sqm/SemanticCloudDescription.java
@@ -0,0 +1,47 @@
+package com.movlad.semviz.core.sqm;
+
+import com.movlad.semviz.core.math.geometry.PointCloud;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import org.apache.jena.ontology.Individual;
+
+public class SemanticCloudDescription {
+
+ private final Individual individual;
+ private final Map attributes;
+ private final PointCloud cloud;
+
+ public SemanticCloudDescription(Individual individual, Map attributes,
+ PointCloud cloud) {
+ this.individual = individual;
+ this.attributes = attributes;
+ this.cloud = cloud;
+ }
+
+ public Individual getIndividual() {
+ return individual;
+ }
+
+ public String getAttribute(String key) {
+ return attributes.get(key);
+ }
+
+ public Set attributeKeySet() {
+ return attributes.keySet();
+ }
+
+ public Collection attributeValues() {
+ return attributes.values();
+ }
+
+ public PointCloud getCloud() {
+ return cloud;
+ }
+
+ @Override
+ public String toString() {
+ return individual.getLocalName();
+ }
+
+}
diff --git a/src/main/java/com/movlad/semviz/view/LoadingDialog.form b/src/main/java/com/movlad/semviz/view/LoadingDialog.form
new file mode 100644
index 0000000..85abcc8
--- /dev/null
+++ b/src/main/java/com/movlad/semviz/view/LoadingDialog.form
@@ -0,0 +1,48 @@
+
+
+
diff --git a/src/main/java/com/movlad/semviz/view/LoadingDialog.java b/src/main/java/com/movlad/semviz/view/LoadingDialog.java
new file mode 100644
index 0000000..569052e
--- /dev/null
+++ b/src/main/java/com/movlad/semviz/view/LoadingDialog.java
@@ -0,0 +1,54 @@
+package com.movlad.semviz.view;
+
+import javax.swing.JFrame;
+
+public final class LoadingDialog extends javax.swing.JDialog {
+
+ /**
+ * @param parent is the parent frame
+ */
+ public LoadingDialog(JFrame parent) {
+ super(parent);
+
+ this.initComponents();
+ this.setBounds(parent.getWidth() / 2, parent.getHeight() / 2, getWidth(), getHeight());
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ Label_Loading = new javax.swing.JLabel();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setUndecorated(true);
+
+ Label_Loading.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ Label_Loading.setText("Loading...");
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(Label_Loading, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 55, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(Label_Loading, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap())
+ );
+
+ pack();
+ }// //GEN-END:initComponents
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel Label_Loading;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/src/main/java/com/movlad/semviz/view/MainFrame.form b/src/main/java/com/movlad/semviz/view/MainFrame.form
index 7efe0f4..f2086f9 100644
--- a/src/main/java/com/movlad/semviz/view/MainFrame.form
+++ b/src/main/java/com/movlad/semviz/view/MainFrame.form
@@ -126,26 +126,21 @@
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
@@ -158,22 +153,14 @@
-
-
-
-
-
-
-
-
-
-
+
-
+
+
@@ -215,7 +202,7 @@
-
+
@@ -264,7 +251,7 @@
-
+
@@ -287,7 +274,7 @@
-
+
@@ -323,9 +310,9 @@
-
+
-
+
@@ -349,7 +336,7 @@
-
+
@@ -388,7 +375,7 @@
-
+
diff --git a/src/main/java/com/movlad/semviz/view/MainFrame.java b/src/main/java/com/movlad/semviz/view/MainFrame.java
index af7d5aa..c547722 100644
--- a/src/main/java/com/movlad/semviz/view/MainFrame.java
+++ b/src/main/java/com/movlad/semviz/view/MainFrame.java
@@ -7,13 +7,10 @@
import com.jogamp.opengl.awt.GLJPanel;
import com.movlad.semviz.application.CommandNavigationController;
-import com.movlad.semviz.application.QueryManagerController;
+import com.movlad.semviz.application.SQMController;
import com.movlad.semviz.application.SceneController;
-import com.movlad.semviz.application.SemanticCloudController;
-import com.movlad.semviz.core.semantic.QueryManager;
-import com.movlad.semviz.core.semantic.QueryResult;
-import com.movlad.semviz.core.semantic.SemanticCloud;
-import java.awt.Color;
+import com.movlad.semviz.core.sqm.SQM;
+import com.movlad.semviz.core.sqm.SemanticCloudDescription;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
@@ -21,28 +18,29 @@
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.nio.file.Paths;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
+import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
+import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
public class MainFrame extends javax.swing.JFrame implements PropertyChangeListener {
- private QueryManagerController queryManagerController;
- private SemanticCloudController semanticCloudController;
- private CommandNavigationController commandNavigationController;
+ private SQMController sqmController;
+ private CommandNavigationController navigationController;
private SceneController sceneController;
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox ComboBox_GeometrySelection;
private javax.swing.JLabel Label_GeometrySelection;
private java.awt.Label Label_Individuals;
- private javax.swing.JLabel Label_StatusLED;
private javax.swing.JLabel Label_StatusText;
private javax.swing.JLabel Label_VarInfo;
private javax.swing.JList List_Individuals;
@@ -86,10 +84,12 @@ public static void main(String args[]) {
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- } catch (Exception e) {
- JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+ if (System.getProperty("os.name").contains("Windows")) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+ }
}
//
@@ -122,7 +122,6 @@ private void initComponents() {
TextField_Command = new javax.swing.JTextField();
Panel_Control = new javax.swing.JPanel();
Panel_Status = new javax.swing.JPanel();
- Label_StatusLED = new javax.swing.JLabel();
Label_StatusText = new javax.swing.JLabel();
Panel_Individuals = new javax.swing.JPanel();
Label_Individuals = new java.awt.Label();
@@ -152,17 +151,14 @@ public void keyPressed(java.awt.event.KeyEvent evt) {
Panel_Control.setBackground(new java.awt.Color(204, 204, 204));
- Label_StatusLED.setFont(new java.awt.Font("Arial", 0, 20)); // NOI18N
- Label_StatusLED.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
- Label_StatusLED.setText("•");
-
- Label_StatusText.setFont(new java.awt.Font("Arial", 0, 20)); // NOI18N
- Label_StatusText.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+ Label_StatusText.setFont(new java.awt.Font("Arial", 0, 14)); // NOI18N
+ Label_StatusText.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
Label_StatusText.setText("Ontology Model Loaded");
+ Label_StatusText.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
Panel_Individuals.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
- Label_Individuals.setFont(new java.awt.Font("Dialog", 1, 12)); // NOI18N
+ Label_Individuals.setFont(new java.awt.Font("Arial", 1, 13)); // NOI18N
Label_Individuals.setText("Cloud List");
List_Individuals.setModel(new javax.swing.AbstractListModel() {
@@ -201,7 +197,7 @@ public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
.addContainerGap())
);
- Label_VarInfo.setFont(new java.awt.Font("Tahoma", 1, 13)); // NOI18N
+ Label_VarInfo.setFont(new java.awt.Font("Arial", 1, 13)); // NOI18N
Label_VarInfo.setText("Queried Info");
Table_VarInfo.setModel(new javax.swing.table.DefaultTableModel(
@@ -227,7 +223,7 @@ public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
.addComponent(Scroll_VarInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(Panel_VarInfoLayout.createSequentialGroup()
.addComponent(Label_VarInfo)
- .addGap(0, 0, Short.MAX_VALUE)))
+ .addGap(0, 178, Short.MAX_VALUE)))
.addContainerGap())
);
Panel_VarInfoLayout.setVerticalGroup(
@@ -240,7 +236,7 @@ public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
- Label_GeometrySelection.setFont(new java.awt.Font("Tahoma", 1, 13)); // NOI18N
+ Label_GeometrySelection.setFont(new java.awt.Font("Arial", 1, 13)); // NOI18N
Label_GeometrySelection.setText("View");
ComboBox_GeometrySelection.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
@@ -257,9 +253,9 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) {
.addGroup(Panel_GeometrySelectionLayout.createSequentialGroup()
.addContainerGap()
.addGroup(Panel_GeometrySelectionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(ComboBox_GeometrySelection, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(ComboBox_GeometrySelection, 0, 252, Short.MAX_VALUE)
.addGroup(Panel_GeometrySelectionLayout.createSequentialGroup()
- .addComponent(Label_GeometrySelection)
+ .addComponent(Label_GeometrySelection, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
@@ -277,23 +273,19 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) {
Panel_Status.setLayout(Panel_StatusLayout);
Panel_StatusLayout.setHorizontalGroup(
Panel_StatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(Panel_StatusLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(Label_StatusLED, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(Label_StatusText, javax.swing.GroupLayout.PREFERRED_SIZE, 208, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addContainerGap(34, Short.MAX_VALUE))
.addComponent(Panel_Individuals, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(Panel_VarInfo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(Panel_GeometrySelection, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, Panel_StatusLayout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(Label_StatusText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap())
);
Panel_StatusLayout.setVerticalGroup(
Panel_StatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, Panel_StatusLayout.createSequentialGroup()
.addGap(27, 27, 27)
- .addGroup(Panel_StatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
- .addComponent(Label_StatusLED, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(Label_StatusText, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(Label_StatusText, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(Panel_Individuals, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@@ -320,7 +312,7 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) {
Panel_GLContainer.setLayout(Panel_GLContainerLayout);
Panel_GLContainerLayout.setHorizontalGroup(
Panel_GLContainerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 698, Short.MAX_VALUE)
+ .addGap(0, 706, Short.MAX_VALUE)
);
Panel_GLContainerLayout.setVerticalGroup(
Panel_GLContainerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -389,7 +381,7 @@ private void menuItem_OpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN
if (returnVal == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getAbsolutePath();
- queryManagerController.loadQueryManager(path);
+ sqmController.load(path);
}
}//GEN-LAST:event_menuItem_OpenActionPerformed
@@ -401,17 +393,15 @@ private void TextField_CommandKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIR
switch (evt.getKeyCode()) {
case KeyEvent.VK_ENTER:
String queryString = TextField_Command.getText();
-
- commandNavigationController.enter(queryString);
- queryManagerController.executeQuery(queryString);
+ navigationController.enter(queryString);
break;
case KeyEvent.VK_UP:
- commandNavigationController.up();
+ navigationController.up();
break;
case KeyEvent.VK_DOWN:
- commandNavigationController.down();
+ navigationController.down();
break;
}
@@ -429,49 +419,22 @@ private void ComboBox_GeometrySelectionItemStateChanged(java.awt.event.ItemEvent
private void List_IndividualsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_List_IndividualsValueChanged
int index = List_Individuals.getSelectedIndex();
- resetVarInfoTable();
-
- DefaultTableModel model = (DefaultTableModel) Table_VarInfo.getModel();
-
- if (index != -1) {
- // An individual is selected
-
- /*
- Filling in variable information table with the semantic attributes
- decribing the selected individual.
- */
- List queryResults = queryManagerController.getQueryResults();
-
- queryResults.get(index).getKeys().forEach(key -> {
- String[] row = new String[2];
-
- row[0] = key;
- row[1] = queryResults.get(index).getAttribute(key);
-
- model.addRow(row);
- });
-
- sceneController.setDisplaySelection(index);
- ComboBox_GeometrySelection.setEnabled(true);
- ComboBox_GeometrySelection.setSelectedIndex(sceneController.getSelectedViewIndex(index));
- }
+ sqmController.setSelectedDescriptionIndex(index);
}//GEN-LAST:event_List_IndividualsValueChanged
private void initControllers() {
- queryManagerController = new QueryManagerController();
- semanticCloudController = new SemanticCloudController();
- commandNavigationController = new CommandNavigationController();
+ sqmController = SQMController.getInstance();
+ navigationController = new CommandNavigationController();
sceneController = new SceneController();
- queryManagerController.register(this);
- semanticCloudController.register(this);
- commandNavigationController.register(this);
+ sqmController.register(this);
+ navigationController.register(this);
sceneController.register(this);
}
private void initStatusBar() {
- Label_StatusLED.setForeground(Color.RED);
- Label_StatusText.setText("Inactive");
+ Label_StatusText.setText("No directory loaded.");
+ Label_StatusText.setToolTipText("");
}
private void initIndividualsList() {
@@ -554,53 +517,68 @@ public void propertyChange(PropertyChangeEvent evt) {
JOptionPane.ERROR_MESSAGE);
}
- if (evt.getPropertyName().contains("CommandNavigation")) {
- TextField_Command.setText((String) evt.getNewValue());
- }
+ pollSQMEvents(evt);
+ pollNavigationEvents(evt);
+ }
- if (evt.getPropertyName().contains("QueryManagerLoad")) {
+ /**
+ * Checks whether an event comes from the {@code SQMController} and takes
+ * action accordingly.
+ *
+ * @param evt is a property change event
+ */
+ private void pollSQMEvents(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().contains("SQMLoad")) {
resetInterface();
}
- if (evt.getPropertyName().contains("QueryExecution")) {
- onQueryExecution(evt);
+ if (evt.getPropertyName().contains("SQMExecution")) {
+ onSQMExecution(evt);
}
switch (evt.getPropertyName()) {
- case "QueryManagerLoadSuccess":
- onQueryManagerLoadSuccess(evt);
+ case "SQMLoadSuccess":
+ onSQMLoadSuccess(evt);
+
+ break;
+
+ case "SQMExecutionSuccess":
+ onSQMExecutionSuccess(evt);
break;
- case "QueryExecutionSuccess":
- onQueryExecutionSuccess(evt);
+ case "SQMFailCountChanged":
+ onSQMFailCountChanged(evt);
break;
- case "SemanticCloudChange":
- sceneController.loadDisplayInformation((SemanticCloud) evt.getNewValue());
+ case "SQMDescriptionIndexChanged":
+ onSQMDescriptionIndexChanged(evt);
break;
}
}
/**
- * Called when the query manager is successfully loaded.
+ * Checks whether an event is related to command navigation and takes action
+ * accordingly.
+ *
+ * @param evt is a property change event
*/
- private void onQueryManagerLoadSuccess(PropertyChangeEvent evt) {
- Label_StatusLED.setForeground(Color.GREEN);
- Label_StatusText.setText("Active");
- TextField_Command.setEnabled(true);
- sceneController.resetDisplayInformation();
+ private void pollNavigationEvents(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().contains("CommandNavigation")) {
+ TextField_Command.setText((String) evt.getNewValue());
+ }
- JOptionPane.showMessageDialog(this, "Load complete.", "Info",
- JOptionPane.INFORMATION_MESSAGE);
+ if (evt.getPropertyName().equals("CommandLaunch")) {
+ onCommandLaunch(evt);
+ }
}
/**
- * Called whenever a query is executed.
+ * Called whenever a exec is executed.
*/
- private void onQueryExecution(PropertyChangeEvent evt) {
+ private void onSQMExecution(PropertyChangeEvent evt) {
resetIndividualsList();
resetVarInfoTable();
resetGeometrySelectionComboBox();
@@ -608,20 +586,116 @@ private void onQueryExecution(PropertyChangeEvent evt) {
}
/**
- * Called upon successful execution of a query.
+ * Called when the exec manager is successfully loaded.
*/
- private void onQueryExecutionSuccess(PropertyChangeEvent evt) {
+ private void onSQMLoadSuccess(PropertyChangeEvent evt) {
+ SQM sqm = (SQM) evt.getNewValue();
+ String activeDirectoryPath = sqm.getPath();
+
+ Label_StatusText.setText("Active directory: "
+ + Paths.get(activeDirectoryPath).getFileName().toString());
+ Label_StatusText.setToolTipText(activeDirectoryPath);
+ TextField_Command.setEnabled(true);
+ sceneController.resetDisplayInformation();
+
+ JOptionPane.showMessageDialog(this, "Load complete.", "Info",
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ /**
+ * Called upon successful execution of a exec.
+ */
+ private void onSQMExecutionSuccess(PropertyChangeEvent evt) {
+ List descriptions
+ = (List) evt.getNewValue();
+
+ sceneController.load(descriptions);
+
DefaultListModel listModel = (DefaultListModel) List_Individuals.getModel();
- List queryResults = (List) evt.getNewValue();
+ descriptions.forEach(description -> {
+ listModel.addElement(description.toString());
+ });
+ }
+
+ /**
+ * Called whenever the fail count of the Semviz Query Manager changes.
+ *
+ * @param evt is a property change event
+ */
+ private void onSQMFailCountChanged(PropertyChangeEvent evt) {
+ int failCount = (int) evt.getNewValue();
+
+ if (failCount > 0) {
+ JOptionPane.showMessageDialog(this, "A number of " + failCount + " cloud "
+ + "individuals could not be retreived.", "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ /**
+ * Called whenever the selected description index is changed within the
+ * Semviz Query Manager controller.
+ *
+ * @param evt is a property change event
+ */
+ private void onSQMDescriptionIndexChanged(PropertyChangeEvent evt) {
+ resetVarInfoTable();
+
+ int index = (int) evt.getNewValue();
+ DefaultTableModel model = (DefaultTableModel) Table_VarInfo.getModel();
+
+ if (index != -1) {
+ // An individual is selected
+
+ /*
+ Filling in variable information table with the semantic attributes
+ decribing the selected individual.
+ */
+ sqmController.getSelectedDescription().attributeKeySet().forEach(key -> {
+ String[] row = new String[2];
+
+ row[0] = key;
+ row[1] = sqmController.getSelectedDescription().getAttribute(key);
+
+ model.addRow(row);
+ });
+
+ sceneController.setDisplaySelection(index);
+ ComboBox_GeometrySelection.setEnabled(true);
+ ComboBox_GeometrySelection.setSelectedIndex(sceneController.getSelectedViewIndex(index));
+ }
+ }
- queryResults.forEach(result -> {
- listModel.addElement(result.getIndividual().getLocalName());
+ /**
+ * Called whenever a SPARQL query is launched.
+ *
+ * @param evt is a property change event
+ */
+ private void onCommandLaunch(PropertyChangeEvent evt) {
+ String queryString = (String) evt.getNewValue();
+
+ SwingWorker swingWorker = new SwingWorker() {
+ @Override
+ protected Void doInBackground() throws Exception {
+ sqmController.exec(queryString);
+
+ return null;
+ }
+ };
+
+ final JDialog dialog = new LoadingDialog(this);
+
+ swingWorker.addPropertyChangeListener((PropertyChangeEvent evt1) -> {
+ if (evt1.getPropertyName().equals("state")) {
+ if (evt1.getNewValue() == SwingWorker.StateValue.DONE) {
+ dialog.dispose();
+ }
+ }
});
- QueryManager queryManager = queryManagerController.getQueryManager();
+ swingWorker.execute();
- semanticCloudController.loadSuperCloud(queryManager, queryResults);
+ dialog.setVisible(true);
}
public void exit() {
diff --git a/src/main/java/com/movlad/semviz/view/ViewerPanel.java b/src/main/java/com/movlad/semviz/view/ViewerPanel.java
index c2601fe..3a5ffdd 100644
--- a/src/main/java/com/movlad/semviz/view/ViewerPanel.java
+++ b/src/main/java/com/movlad/semviz/view/ViewerPanel.java
@@ -5,18 +5,22 @@
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLJPanel;
import com.jogamp.opengl.util.Animator;
+import com.movlad.semviz.application.SQMController;
import com.movlad.semviz.application.SceneController;
import com.movlad.semviz.core.graphics.Controls;
import com.movlad.semviz.core.graphics.OrbitControls;
import com.movlad.semviz.core.graphics.OrthographicCamera;
import com.movlad.semviz.core.graphics.Renderer;
+import com.movlad.semviz.core.graphics.Scene;
import java.awt.Dimension;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import org.joml.Vector3f;
/**
* Interface component on which a scene is drawn.
*/
-public final class ViewerPanel extends GLJPanel {
+public final class ViewerPanel extends GLJPanel implements PropertyChangeListener {
private final OrthographicCamera camera;
private final Controls controls;
@@ -34,6 +38,11 @@ public ViewerPanel(Dimension d, SceneController sceneController) {
super(new GLCapabilities(GLProfile.get(GLProfile.GL3)));
setSize(d);
+ sceneController.register(this);
+ SQMController.getInstance().register(this);
+
+ Scene scene = new Scene();
+
camera = new OrthographicCamera(-getWidth() / 2, getWidth() / 2, -getHeight() / 2, getHeight() / 2,
0.1f, 1000.0f);
@@ -49,7 +58,7 @@ public ViewerPanel(Dimension d, SceneController sceneController) {
addMouseMotionListener(controls);
addMouseWheelListener(controls);
- renderer = new Renderer(sceneController.getScene(), camera) {
+ renderer = new Renderer() {
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
@@ -60,6 +69,8 @@ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height
};
+ renderer.setCamera(camera);
+ renderer.setScene(scene);
addGLEventListener(renderer);
animator = new Animator(this);
@@ -67,4 +78,16 @@ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height
animator.start();
}
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().equals("SQMExecutionStarted")) {
+ animator.stop();
+ }
+
+ if (evt.getPropertyName().contains("Scene")) {
+ renderer.setScene((Scene) evt.getNewValue());
+ animator.start();
+ }
+ }
+
}
diff --git a/src/main/resources/icons/icons8-reboot-100.png b/src/main/resources/icons/icons8-reboot-100.png
new file mode 100644
index 0000000..7778b81
Binary files /dev/null and b/src/main/resources/icons/icons8-reboot-100.png differ