Skip to content

Commit 8547aba

Browse files
committed
Refactored: Vertex is abstract -> superclass of Class, Literal.
1 parent b460c42 commit 8547aba

9 files changed

Lines changed: 435 additions & 348 deletions

File tree

src/controller/Controller.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import javafx.scene.image.ImageView;
1212
import javafx.stage.Modality;
1313
import javafx.stage.Stage;
14+
import model.conceptual.Class;
1415
import model.conceptual.Edge;
16+
import model.conceptual.Literal;
1517
import model.conceptual.Vertex;
1618
import model.conceptual.Vertex.OutsideElementException;
1719
import model.conceptual.Vertex.UndefinedElementTypeException;
@@ -620,7 +622,7 @@ private void addElementSubaction(MouseEvent mouseEvent) {
620622

621623
if (elementName.getText().equals("")){
622624
isClass = true;
623-
elementName = new Text("_:" + Vertex.getNextBlankNodeName());
625+
elementName = new Text("_:" + Class.getNextBlankNodeName());
624626
} else isClass = !elementName.getText().matches(globalLiteralRegex + "|" + instanceLiteralRegex);
625627

626628
double textWidth = elementName.getBoundsInLocal().getWidth();
@@ -648,13 +650,22 @@ private void addElementSubaction(MouseEvent mouseEvent) {
648650
if (isOntology && isClass) {
649651
String rdfslabel = classInfo.get(2);
650652
String rdfscomment = classInfo.get(3);
651-
classes.add(new Vertex(compiledElement, rdfslabel, rdfscomment));
653+
classes.add(new Class(compiledElement, rdfslabel, rdfscomment));
652654
} else if (isOntology){
653655
String dataType = classInfo.get(1);
654-
classes.add(new Vertex(compiledElement, dataType));
655-
} else classes.add(new Vertex(compiledElement));
656-
} catch (OutsideElementException | UndefinedElementTypeException e) {
657-
e.printStackTrace();
656+
classes.add(new Literal(compiledElement, dataType));
657+
} else if (isClass) {
658+
classes.add(new Class(compiledElement));
659+
} else {
660+
classes.add(new Literal(compiledElement));
661+
}
662+
} catch (UndefinedElementTypeException e) {
663+
setErrorStatus("Adding the element failed: The name does not match Turtle syntax. Recreate the" +
664+
" graph. ");
665+
LOGGER.log(Level.SEVERE, "Adding element failed: ", e);
666+
} catch (OutsideElementException e) {
667+
setErrorStatus("Somehow, you went outside the bounds of the canvas...");
668+
LOGGER.log(Level.SEVERE, "Adding the element failed: ", e);
658669
}
659670
}
660671

@@ -803,9 +814,7 @@ private void showOptionsDialog() {
803814
return;
804815
}
805816

806-
LOGGER.info("AFTER Correlation:" +
807-
"\nCorrelated: " + dataIntegrator.getCorrelations().toString() +
808-
"\nUncorrelated (assumed constant): " + dataIntegrator.uncorrelatedClassesToString());
817+
LOGGER.info("AFTER Correlation:" + "\nCorrelated: " + dataIntegrator.getCorrelations().toString());
809818

810819
try {
811820
instanceData = dataIntegrator.generate();

src/controller/OntologyClassDialogController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import javafx.scene.control.CheckBox;
99
import javafx.scene.control.TextArea;
1010
import javafx.scene.control.TextField;
11-
import javafx.scene.input.MouseEvent;
1211
import javafx.stage.Stage;
1312

1413
import java.net.URL;

src/model/conceptual/Class.java

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package model.conceptual;
2+
3+
import javafx.event.EventTarget;
4+
import javafx.geometry.Bounds;
5+
import javafx.scene.shape.Ellipse;
6+
import javafx.scene.shape.Shape;
7+
import javafx.scene.text.Text;
8+
import javafx.util.Pair;
9+
10+
import java.util.ArrayList;
11+
12+
public class Class extends Vertex {
13+
private boolean isBlankNode;
14+
private boolean isIri;
15+
private String typeDefinition;
16+
private String rdfsLabel, rdfsComment;
17+
18+
private static char nextBlankNodeName = (char) 96;
19+
private static final ArrayList<Character> blankNodeNames = new ArrayList<>();
20+
21+
22+
/**
23+
* Constructor for a Vertex with meta-information, namely it's human-readable label and comment (defined in RDFS).
24+
*
25+
* @param element the container of the shape and name of the Vertex.
26+
* @param rdfsLabel the human-readable label of the Vertex.
27+
* @param rdfsComment the comment regarding the Vertex.
28+
* @throws OutsideElementException if the container is not castable to a stackpane (aka it is outside the canvas.
29+
*/
30+
public Class(EventTarget element, String rdfsLabel, String rdfsComment) throws OutsideElementException {
31+
this(element);
32+
this.rdfsLabel = rdfsLabel;
33+
this.rdfsComment = rdfsComment;
34+
}
35+
36+
public Class(EventTarget container) throws OutsideElementException {
37+
super(container);
38+
39+
if (super.name.charAt(0) == '_') {
40+
((Text) super.container.getChildren().get(1)).setText("");
41+
isBlankNode = true;
42+
isIri = false;
43+
} else if (this.name.matches("https?:.*|mailto:.*")){
44+
isBlankNode = false;
45+
isIri = true;
46+
} else {
47+
isBlankNode = false;
48+
isIri = false;
49+
}
50+
51+
Shape shape = (Shape) super.container.getChildren().get(0);
52+
if (shape instanceof Ellipse && shape.getStrokeDashArray().size() == 0)
53+
super.elementType = GraphElemType.GLOBAL_CLASS;
54+
else if (shape instanceof Ellipse) super.elementType = GraphElemType.INSTANCE_CLASS;
55+
}
56+
57+
/**
58+
* Snap the users property arrow as close to the edge of the shape as possible. This is fairly straightforward for
59+
* a Literal, but is much more involved for a Class.
60+
*
61+
* @param subX the x value of the subject of the property arrow - needed to find the intercept of the line and the
62+
* ellipse.
63+
* @param subY the y value of the subject of the property arrow - needed to find the intercept of the line and the
64+
* ellipse.
65+
* @param x the x value of the users click.
66+
* @param y the y value of the users click.
67+
*/
68+
@Override
69+
public void setSnapTo(double subX, double subY, double x, double y) {
70+
this.snapToCenter();
71+
72+
Bounds b = container.getBoundsInParent();
73+
Ellipse e = (Ellipse) container.getChildren().get(0);
74+
75+
ArrayList<Pair<Double, Double>> coords = getIntersection(
76+
subX, subY,
77+
this.x, this.y,
78+
b.getMinX() + e.getRadiusX(), b.getMinY() + e.getRadiusY(),
79+
e.getRadiusX(), e.getRadiusY()
80+
);
81+
82+
if (coords.size() == 1) {
83+
this.x = coords.get(0).getKey();
84+
this.y = coords.get(0).getValue();
85+
}
86+
}
87+
88+
/**
89+
* Find the intersection(s) of the property arrow and the Object ellipse. Should usually be a single intersection,
90+
* multiple denote a pass across the shape rather than into it.
91+
* @param x1 subject point x-value.
92+
* @param y1 subject point y-value.
93+
* @param x2 object x-value.
94+
* @param y2 object y-value.
95+
* @param midX x-value of the midpoint of the ellipse.
96+
* @param midY y-value of the midpoint of the ellipse.
97+
* @param h the major axis of the ellipse.
98+
* @param v the minor axis of the ellipse.
99+
* @return list of coordinates in which the ellipse and the line intersect.
100+
*/
101+
private static ArrayList<Pair<Double, Double>> getIntersection(
102+
double x1, double y1,
103+
double x2, double y2,
104+
double midX, double midY,
105+
double h, double v) {
106+
ArrayList<Pair<Double, Double>> points = new ArrayList<>();
107+
108+
x1 -= midX;
109+
y1 -= midY;
110+
x2 -= midX;
111+
y2 -= midY;
112+
113+
if (x1 == x2) {
114+
double y = (v/h)*Math.sqrt(h*h-x1*x1);
115+
if (Math.min(y1, y2) <= y && y <= Math.max(y1, y2)) points.add(new Pair<>(x1+midX, y+midY));
116+
if (Math.min(y1, y2) <= -y && -y <= Math.max(y1, y2)) points.add(new Pair<>(x1+midX, -y+midY));
117+
} else {
118+
double a = (y2 - y1) / (x2 - x1);
119+
double b = (y1 - a*x1);
120+
121+
double r = a*a*h*h + v*v;
122+
double s = 2*a*b*h*h;
123+
double t = h*h*b*b - h*h*v*v;
124+
125+
double d = s*s - 4*r*t;
126+
127+
if (d > 0) {
128+
double xi1 = (-s+Math.sqrt(d))/(2*r);
129+
double xi2 = (-s-Math.sqrt(d))/(2*r);
130+
131+
double yi1 = a*xi1+b;
132+
double yi2 = a*xi2+b;
133+
134+
if (isPointInLine(x1, y1, x2, y2, xi1, yi1)) points.add(new Pair<>(xi1+midX, yi1+midY));
135+
if (isPointInLine(x1, y1, x2, y2, xi2, yi2)) points.add(new Pair<>(xi2+midX, yi2+midY));
136+
} else if (d == 0) {
137+
double xi = -s/(2*r);
138+
double yi = a*xi+b;
139+
140+
if (isPointInLine(x1, y1, x2, y2, xi, yi)) points.add(new Pair<>(xi+midX, yi+midY));
141+
}
142+
}
143+
144+
return points;
145+
}
146+
147+
/**
148+
* Determines if a given point is within the the given line.
149+
* @param x1 subject x-value.
150+
* @param y1 subject y-value.
151+
* @param x2 object x-value.
152+
* @param y2 object y-value.
153+
* @param px given points x-value.
154+
* @param py given points y-value.
155+
* @return whether the point is within the line or not.
156+
*/
157+
private static boolean isPointInLine(double x1, double y1, double x2, double y2, double px, double py) {
158+
double xMin = Math.min(x1, x2);
159+
double xMax = Math.max(x1, x2);
160+
161+
double yMin = Math.min(y1, y2);
162+
double yMax = Math.max(y1, y2);
163+
164+
return (xMin <= px && px <= xMax) && (yMin <= py && py <= yMax);
165+
}
166+
167+
@Override
168+
public void addOutgoingEdge(Edge e) {
169+
if (e.getName().matches("a|rdf:type|http://www.w3.org/1999/02/22-rdf-syntax-ns#type"))
170+
typeDefinition = e.getObject().name;
171+
else
172+
super.addOutgoingEdge(e);
173+
}
174+
175+
public boolean isBlank() { return isBlankNode; }
176+
177+
public boolean isIri() { return isIri; }
178+
179+
public static char getNextBlankNodeName() {
180+
nextBlankNodeName += 1;
181+
blankNodeNames.add(nextBlankNodeName);
182+
return nextBlankNodeName;
183+
}
184+
185+
public static ArrayList<Character> getBlankNodeNames(){ return blankNodeNames; }
186+
187+
public String getTypeDefinition() { return typeDefinition; }
188+
189+
public String getRdfsLabel() {
190+
return rdfsLabel;
191+
}
192+
193+
public String getRdfsComment() {
194+
return rdfsComment;
195+
}
196+
}

src/model/conceptual/Literal.java

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package model.conceptual;
2+
3+
import javafx.event.EventTarget;
4+
import javafx.geometry.Bounds;
5+
6+
import java.util.Arrays;
7+
8+
public class Literal extends Vertex {
9+
private static final String globalLiteralRegex = "\".*\"(\\^\\^.*|@.*)?" + // unspecified / String
10+
"|true|false" + // boolean
11+
"|[+\\-]?\\d+" + //integer
12+
"|[+\\-]?\\d*\\.\\d+" + // decimal
13+
"|([+\\-]?\\d+\\.\\d+|[+\\-]?\\.\\d+|[+\\-]?\\d+)[Ee][+\\-]\\d+"; // double;
14+
private static final String instanceLiteralRegex = "(?<!\")[^:]*(?!\")";
15+
16+
private String dataType;
17+
18+
/**
19+
* Constructor for a Vertex with meta-information regarding the datatype of the Literal.
20+
*
21+
* @param container the container of the shape and the name.
22+
* @param dataType the data type of the given Vertex.
23+
* @throws OutsideElementException if the container is not castable to a stackpane (aka it is outside the canvas.
24+
* @throws UndefinedElementTypeException if the name of the Vertex does not correspond to any of the GraphElemTypes.
25+
*/
26+
public Literal(EventTarget container, String dataType)
27+
throws OutsideElementException, UndefinedElementTypeException {
28+
this(container);
29+
this.dataType = dataType;
30+
}
31+
32+
public Literal(EventTarget container) throws OutsideElementException, UndefinedElementTypeException {
33+
super(container);
34+
35+
if (this.name.matches(globalLiteralRegex)) this.elementType = GraphElemType.GLOBAL_LITERAL;
36+
else if (this.name.matches(instanceLiteralRegex)) this.elementType = GraphElemType.INSTANCE_LITERAL;
37+
else throw new UndefinedElementTypeException();
38+
}
39+
40+
/**
41+
* @return the datatype of the Vertex, in angle-brackets if it is a fully-qualified IRI.
42+
*/
43+
public String getDataType() {
44+
if (this.elementType == GraphElemType.GLOBAL_LITERAL){
45+
final String ints = "[+\\-]?\\d";
46+
47+
if (name.matches("\".*\"")) return "xsd:string";
48+
else if (name.matches("true|false")) return "xsd:boolean";
49+
else if (name.matches(ints+"+")) return "xsd:integer";
50+
else if (name.matches(ints+"*\\.\\d+")) return "xsd:decimal";
51+
else if (name.matches("("+ints+"+\\.\\d+|[+\\-]?\\.\\d+|"+ints+")E"+ints+"+")) return "xsd:double";
52+
else if (name.matches(".*\\^\\^.*")) return name.split("\\^\\^")[1];
53+
else return null;
54+
}
55+
56+
if (dataType == null)
57+
return null;
58+
else if (dataType.matches("http(s)?:.*") && elementType != GraphElemType.GLOBAL_CLASS)
59+
return "<" + dataType + ">";
60+
else if (this.elementType != GraphElemType.GLOBAL_CLASS)
61+
return dataType;
62+
else
63+
return null;
64+
}
65+
66+
/**
67+
* Snap the users property arrow as close to the edge of the shape as possible. This is fairly straightforward for
68+
* a Literal, but is much more involved for a Class.
69+
*
70+
* @param subX the x value of the subject of the property arrow - needed to find the intercept of the line and the
71+
* ellipse.
72+
* @param subY the y value of the subject of the property arrow - needed to find the intercept of the line and the
73+
* ellipse.
74+
* @param x the x value of the users click.
75+
* @param y the y value of the users click.
76+
*/
77+
@Override
78+
public void setSnapTo(double subX, double subY, double x, double y) {
79+
Bounds bounds = container.getBoundsInParent();
80+
double distMinX = Math.abs(bounds.getMinX() - x);
81+
double distMaxX = Math.abs(bounds.getMaxX() - x);
82+
double distMinY = Math.abs(bounds.getMinY() - y);
83+
double distMaxY = Math.abs(bounds.getMaxY() - y);
84+
double[] distArray = {distMinX, distMaxX, distMinY, distMaxY};
85+
Arrays.sort(distArray);
86+
double minDist = distArray[0];
87+
88+
if (minDist == distMinX) {
89+
this.x = bounds.getMinX();
90+
this.y = y;
91+
} else if (minDist == distMaxX) {
92+
this.x = bounds.getMaxX();
93+
this.y = y;
94+
} else if (minDist == distMinY) {
95+
this.x = x;
96+
this.y = bounds.getMinY();
97+
} else {
98+
this.x = x;
99+
this.y = bounds.getMaxY();
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)