diff --git a/pom.xml b/pom.xml
index c82e3af..773de23 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,7 +157,7 @@
junit
junit
- 4.12
+ 4.13.1
compile
@@ -168,6 +168,12 @@
test
+
+ org.openjfx
+ javafx-swing
+ 11-ea+24
+
+
@@ -180,7 +186,7 @@
11
11
- com.todense.application.Starter2
+ com.todense.application.StarterInvoker
@@ -191,7 +197,7 @@
- com.todense.application.Starter2
+ com.todense.application.StarterInvoker
diff --git a/src/main/java/com/todense/application/Starter.java b/src/main/java/com/todense/application/Starter.java
index 3e038ca..116de99 100644
--- a/src/main/java/com/todense/application/Starter.java
+++ b/src/main/java/com/todense/application/Starter.java
@@ -16,6 +16,7 @@ public class Starter extends MvvmfxGuiceApplication {
@Override
public void startMvvmfx(Stage stage) {
+
stage.setTitle("OmniGraph");
final ViewTuple viewTuple = FluentViewLoader.fxmlView(MainView.class).load();
final Parent root = viewTuple.getView();
diff --git a/src/main/java/com/todense/application/Starter2.java b/src/main/java/com/todense/application/StarterInvoker.java
similarity index 54%
rename from src/main/java/com/todense/application/Starter2.java
rename to src/main/java/com/todense/application/StarterInvoker.java
index f328553..b032c6b 100644
--- a/src/main/java/com/todense/application/Starter2.java
+++ b/src/main/java/com/todense/application/StarterInvoker.java
@@ -1,7 +1,8 @@
package com.todense.application;
-public class Starter2 {
+public class StarterInvoker {
+ // This class exist because of some bug with maven javafx plugin
public static void main(String[] args) {
Starter.main(args);
}
diff --git a/src/main/java/com/todense/model/EdgeList.java b/src/main/java/com/todense/model/EdgeList.java
index 7d1c31c..2b67567 100644
--- a/src/main/java/com/todense/model/EdgeList.java
+++ b/src/main/java/com/todense/model/EdgeList.java
@@ -48,7 +48,6 @@ public Edge getEdge(Node n, Node m){
String id = n.getID() < m.getID() ?
n.getID()+"-"+m.getID() :
m.getID()+"-"+n.getID();
- assert edgeMap.get(id) != null : "No edge with id: "+id;
return edgeMap.get(id);
}
diff --git a/src/main/java/com/todense/model/graph/Graph.java b/src/main/java/com/todense/model/graph/Graph.java
index 3269c01..64d71dc 100644
--- a/src/main/java/com/todense/model/graph/Graph.java
+++ b/src/main/java/com/todense/model/graph/Graph.java
@@ -6,6 +6,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.BiConsumer;
public class Graph {
@@ -44,7 +45,6 @@ public Node addNode(Point2D pt, int id){
return n;
}
-
public Edge addEdge(Node n, Node m){
assert !edges.isEdgeBetween(n, m):
"Edge "+edges.getEdge(n, m).toString()+" already exist!";
@@ -67,13 +67,47 @@ public void removeEdge(Edge e){
edges.remove(e);
}
- public void removeAllEdges(){
- edges.clear();
- for (Node node : nodes) {
- node.getNeighbours().clear();
+ public void removeEdges(List nodes){
+ applyToAllPairOfNodes(nodes, (n, m) -> {
+ if(edges.isEdgeBetween(n, m)){
+ removeEdge(n, m);
+ }
+ });
+ }
+
+ public void applyToAllPairOfNodes(List nodes, BiConsumer consumer){
+ for (int i = 0; i < nodes.size(); i++) {
+ for (int j = i+1; j < nodes.size(); j++) {
+ consumer.accept(nodes.get(i), nodes.get(j));
+ }
+ }
+ }
+
+ public void applyToAllConnectedPairOfNodes(List nodes, BiConsumer consumer){
+ for (int i = 0; i < nodes.size(); i++) {
+ for (int j = i+1; j < nodes.size(); j++) {
+ Node n = nodes.get(i);
+ Node m = nodes.get(j);
+ Edge e = getEdge(n, m);
+ if(e != null){
+ consumer.accept(nodes.get(i), nodes.get(j));
+ }
+ }
}
}
+ public void applyToAllConnectedPairOfNodes(BiConsumer consumer){
+ applyToAllConnectedPairOfNodes(nodes, consumer);
+ }
+
+ public void applyToAllPairOfNodes(BiConsumer consumer){
+ applyToAllPairOfNodes(nodes, consumer);
+ }
+
+ public void removeEdges(){
+ this.removeEdges(this.nodes);
+ }
+
public void removeNode(Node n){
//decrement indexes
for (int i = n.getIndex() + 1; i < nodes.size(); i++) {
diff --git a/src/main/java/com/todense/util/Util.java b/src/main/java/com/todense/util/Util.java
index 154c48f..ccce751 100644
--- a/src/main/java/com/todense/util/Util.java
+++ b/src/main/java/com/todense/util/Util.java
@@ -36,8 +36,7 @@ public static boolean isDouble(String strNum) {
}
//calculates rgb values of a color with given opacity over a background color
- public static Color getFaintColor(Color color, Color backgroundColor) {
- double opacity = 0.3;
+ public static Color getFaintColor(Color color, Color backgroundColor, double opacity) {
int r = (int) (backgroundColor.getRed() * 255 + (color.getRed() * 255 - backgroundColor.getRed() * 255) * opacity);
int g = (int) (backgroundColor.getGreen() * 255 + (color.getGreen()* 255 - backgroundColor.getGreen()* 255) * opacity);
int b = (int) (backgroundColor.getBlue() * 255 + (color.getBlue()* 255 - backgroundColor.getBlue()* 255) * opacity);
@@ -45,6 +44,10 @@ public static Color getFaintColor(Color color, Color backgroundColor) {
return Color.rgb(r, g, b);
}
+ public static Color getFaintColor(Color color, Color backgroundColor) {
+ return getFaintColor(color, backgroundColor, 0.3);
+ }
+
public static void bindSliderAndTextField(Slider slider, TextField textField, String pattern){
StringProperty sp = textField.textProperty();
DoubleProperty dp = slider.valueProperty();
diff --git a/src/main/java/com/todense/view/AlgorithmView.java b/src/main/java/com/todense/view/AlgorithmView.java
index d40cfff..1b6f2d3 100644
--- a/src/main/java/com/todense/view/AlgorithmView.java
+++ b/src/main/java/com/todense/view/AlgorithmView.java
@@ -57,12 +57,12 @@ public void initialize(){
@FXML
private void startAlgorithmAction() {
- viewModel.start();
+ viewModel.startTask();
}
@FXML
private void stopAlgorithmAction() {
- viewModel.stop();
+ viewModel.stopTask();
}
}
diff --git a/src/main/java/com/todense/view/AntsView.java b/src/main/java/com/todense/view/AntsView.java
index 8f7dec8..3a4c76c 100644
--- a/src/main/java/com/todense/view/AntsView.java
+++ b/src/main/java/com/todense/view/AntsView.java
@@ -186,12 +186,12 @@ private void scaleIncrementAction() {
@FXML
private void startAction() {
- viewModel.startAlgorithm();
+ viewModel.startTask();
}
@FXML
private void stopAction() {
- viewModel.stopAlgorithm();
+ viewModel.stopTask();
}
}
diff --git a/src/main/java/com/todense/view/CanvasView.java b/src/main/java/com/todense/view/CanvasView.java
index 099aa35..c7ffc99 100644
--- a/src/main/java/com/todense/view/CanvasView.java
+++ b/src/main/java/com/todense/view/CanvasView.java
@@ -10,6 +10,7 @@
import javafx.scene.Cursor;
import javafx.scene.canvas.Canvas;
import javafx.scene.layout.Pane;
+import javafx.scene.shape.StrokeLineCap;
public class CanvasView implements FxmlView {
@@ -49,10 +50,15 @@ public void initialize(){
canvas.setOnScroll(viewModel.getMouseHandler()::onMouseScroll);
canvas.setOnMouseExited(viewModel.getMouseHandler()::onMouseExited);
+ canvas.getGraphicsContext2D().setLineCap(StrokeLineCap.BUTT);
+
Platform.runLater(() -> {
viewModel.setCanvasNode(canvas);
viewModel.getPopOverManager().setContext(context);
});
}
+
+
+
}
diff --git a/src/main/java/com/todense/view/GraphView.java b/src/main/java/com/todense/view/GraphView.java
index fa29a8e..19905ba 100644
--- a/src/main/java/com/todense/view/GraphView.java
+++ b/src/main/java/com/todense/view/GraphView.java
@@ -11,16 +11,18 @@
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.Label;
+import javafx.scene.layout.VBox;
import org.controlsfx.control.ToggleSwitch;
public class GraphView implements FxmlView {
- @FXML private Label nodeSizeLabel, edgeWidthLabel;
- @FXML private JFXSlider nodeSizeSlider, edgeWidthSlider;
+ @FXML private Label nodeSizeLabel, edgeWidthLabel, edgeWidthDecayLabel, edgeOpacityDecayLabel;
+ @FXML private JFXSlider nodeSizeSlider, edgeWidthSlider, edgeWidthDecaySlider, edgeOpacityDecaySlider;
@FXML private ColorPicker nodeColorPicker, edgeColorPicker, labelColorPicker, weightColorPicker;
@FXML private ChoiceBox nodeLabelChoiceBox;
@FXML private ChoiceBox edgeWeightChoiceBox;
- @FXML private ToggleSwitch nodeBorderToggleSwitch, edgeVisibilityToggleSwitch;
+ @FXML private ToggleSwitch nodeBorderToggleSwitch, edgeVisibilityToggleSwitch, widthDecayToggleSwitch, opacityDecayToggleSwitch;
+ @FXML private VBox edgeWidthDecayVBox, edgeWidthDecayStrengthVBox, edgeOpacityDecayVBox, edgeOpacityDecayStrengthVBox;
@InjectViewModel
GraphViewModel viewModel;
@@ -35,8 +37,32 @@ public void initialize(){
edgeWeightChoiceBox.valueProperty().bindBidirectional(viewModel.edgeWeightModeProperty());
nodeSizeSlider.valueProperty().bindBidirectional(viewModel.nodeSizeProperty());
edgeWidthSlider.valueProperty().bindBidirectional(viewModel.edgeWidthProperty());
+ edgeWidthDecaySlider.valueProperty().bindBidirectional(viewModel.edgeWidthDecayProperty());
+ edgeOpacityDecaySlider.valueProperty().bindBidirectional(viewModel.edgeOpacityDecayProperty());
nodeBorderToggleSwitch.selectedProperty().bindBidirectional(viewModel.nodeBorderProperty());
edgeVisibilityToggleSwitch.selectedProperty().bindBidirectional(viewModel.edgeVisibilityProperty());
+ widthDecayToggleSwitch.selectedProperty().bindBidirectional(viewModel.edgeWidthDecayOnProperty());
+ opacityDecayToggleSwitch.selectedProperty().bindBidirectional(viewModel.edgeOpacityDecayOnProperty());
+
+ widthDecayToggleSwitch.selectedProperty().addListener((obs, oldVal, newVal) -> {
+ if(newVal){
+ edgeWidthDecayVBox.getChildren().add(edgeWidthDecayStrengthVBox);
+ }else{
+ edgeWidthDecayVBox.getChildren().remove(edgeWidthDecayStrengthVBox);
+ }
+ });
+
+ opacityDecayToggleSwitch.selectedProperty().addListener((obs, oldVal, newVal) -> {
+ if(newVal){
+ edgeOpacityDecayVBox.getChildren().add(edgeOpacityDecayStrengthVBox);
+ }else{
+ edgeOpacityDecayVBox.getChildren().remove(edgeOpacityDecayStrengthVBox);
+ }
+ });
+
+ edgeWidthDecayVBox.getChildren().remove(edgeWidthDecayStrengthVBox);
+ edgeOpacityDecayVBox.getChildren().remove(edgeOpacityDecayStrengthVBox);
+
nodeSizeLabel.textProperty().bind(Bindings.createStringBinding(() ->
String.format("%.1f", nodeSizeSlider.getValue()), nodeSizeSlider.valueProperty()));
@@ -45,6 +71,12 @@ public void initialize(){
edgeWidthLabel.textProperty().bind(Bindings.createStringBinding(()->
String.format("%.2f", edgeWidthSlider.getValue()), edgeWidthSlider.valueProperty()));
+ edgeWidthDecayLabel.textProperty().bind(Bindings.createStringBinding(()->
+ String.format("%.4f", edgeWidthDecaySlider.getValue()), edgeWidthDecaySlider.valueProperty()));
+
+ edgeOpacityDecayLabel.textProperty().bind(Bindings.createStringBinding(()->
+ String.format("%.4f", edgeOpacityDecaySlider.getValue()), edgeOpacityDecaySlider.valueProperty()));
+
nodeLabelChoiceBox.getItems().addAll(NodeLabelMode.values());
edgeWeightChoiceBox.getItems().addAll(EdgeWeightMode.values());
diff --git a/src/main/java/com/todense/view/LayoutView.java b/src/main/java/com/todense/view/LayoutView.java
index de70d9c..799aea6 100644
--- a/src/main/java/com/todense/view/LayoutView.java
+++ b/src/main/java/com/todense/view/LayoutView.java
@@ -14,6 +14,7 @@
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;
import javafx.util.converter.NumberStringConverter;
@@ -23,10 +24,11 @@ public class LayoutView implements FxmlView {
@FXML private TextField stepTextField, toleranceTextField, optDistTextField,
pullStrengthTextField, coolingFactorTextField;
@FXML private Slider toleranceSlider, stepSlider, coolingFactorSlider, pullStrengthSlider;
- @FXML private JFXSlider optDistSlider;
- @FXML private ToggleSwitch pullToggleSwitch, coolingToggleSwitch, multilevelToggleSwitch, barnesHutToggleSwitch;
+ @FXML private JFXSlider optDistSlider, smoothnessSlider;
+ @FXML private ToggleSwitch pullToggleSwitch, coolingToggleSwitch, multilevelToggleSwitch, barnesHutToggleSwitch, smoothToggleSwitch;
@FXML private Button startButton;
@FXML private VBox coolingVBox, pullVBox;
+ @FXML private HBox smoothnessHBox;
@FXML private ChoiceBox longRangeChoiceBox;
@InjectViewModel
@@ -38,11 +40,13 @@ public void initialize(){
optDistSlider.valueProperty().bindBidirectional(viewModel.optDistProperty());
coolingFactorSlider.valueProperty().bindBidirectional(viewModel.coolingStrengthProperty());
pullStrengthSlider.valueProperty().bindBidirectional(viewModel.centerPullStrengthProperty());
+ smoothnessSlider.valueProperty().bindBidirectional(viewModel.smoothnessProperty());
pullToggleSwitch.selectedProperty().bindBidirectional(viewModel.centerPullOnProperty());
coolingToggleSwitch.selectedProperty().bindBidirectional(viewModel.coolingOnProperty());
multilevelToggleSwitch.selectedProperty().bindBidirectional(viewModel.multilevelOnProperty());
barnesHutToggleSwitch.selectedProperty().bindBidirectional(viewModel.barnesHutOnProperty());
+ smoothToggleSwitch.selectedProperty().bindBidirectional(viewModel.smoothnessOnProperty());
bindSliderAndTextField(optDistSlider, optDistTextField);
bindSliderAndTextField(stepSlider, stepTextField);
@@ -52,6 +56,7 @@ public void initialize(){
pullVBox.disableProperty().bind(pullToggleSwitch.selectedProperty().not());
coolingVBox.disableProperty().bind(coolingToggleSwitch.selectedProperty().not());
+ smoothnessHBox.disableProperty().bind(smoothToggleSwitch.selectedProperty().not());
longRangeChoiceBox.valueProperty().bindBidirectional(viewModel.longRangeForceProperty());
longRangeChoiceBox.getItems().addAll(LongRangeForce.values());
@@ -75,14 +80,20 @@ private StringBinding createIntBinding(DoubleProperty property){
String.valueOf(property.getValue().intValue()), property);
}
+
@FXML
private void dynamicLayoutAction() {
- viewModel.start();
+ viewModel.startTask();
}
@FXML
private void stopAlgorithmAction() {
- viewModel.stop();
+ viewModel.stopTask();
+ }
+
+ @FXML
+ private void randomLayoutAction(){
+ viewModel.randomLayout();
}
}
diff --git a/src/main/java/com/todense/view/MainView.java b/src/main/java/com/todense/view/MainView.java
index 8e0972b..d901adc 100644
--- a/src/main/java/com/todense/view/MainView.java
+++ b/src/main/java/com/todense/view/MainView.java
@@ -195,7 +195,7 @@ private void adjustAction() {
@FXML
private void stopAction(){
- viewModel.stop();
+ viewModel.stopAll();
}
@FXML
diff --git a/src/main/java/com/todense/view/NodePopOverView.java b/src/main/java/com/todense/view/NodePopOverView.java
index 5031974..06cab1d 100644
--- a/src/main/java/com/todense/view/NodePopOverView.java
+++ b/src/main/java/com/todense/view/NodePopOverView.java
@@ -6,6 +6,7 @@
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
+import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
@@ -16,6 +17,8 @@ public class NodePopOverView implements FxmlView {
@FXML private TextField nodeLabelTextField;
@FXML private Button startNodeButton;
@FXML private Button goalNodeButton;
+ @FXML private VBox rotationVBox;
+ @FXML private Slider rotationSlider;
@InjectViewModel
@@ -24,8 +27,9 @@ public class NodePopOverView implements FxmlView {
public void initialize(){
this.editNodeColorPicker.valueProperty().bindBidirectional(viewModel.nodeColorProperty());
this.nodeLabelTextField.textProperty().bindBidirectional(viewModel.labelProperty());
+ this.rotationSlider.valueProperty().bindBidirectional(viewModel.rotationProperty());
- //remove buttons if more than one node is selected
+ //remove components if more than one node is selected
viewModel.subscribe("MULTIPLE", (key, payload) -> {
nodeVBox.getChildren().remove(startNodeButton);
nodeVBox.getChildren().remove(goalNodeButton);
diff --git a/src/main/java/com/todense/view/OperationsView.java b/src/main/java/com/todense/view/OperationsView.java
index b81112a..099eb3e 100644
--- a/src/main/java/com/todense/view/OperationsView.java
+++ b/src/main/java/com/todense/view/OperationsView.java
@@ -4,12 +4,19 @@
import de.saxsys.mvvmfx.FxmlView;
import de.saxsys.mvvmfx.InjectViewModel;
import javafx.fxml.FXML;
+import org.controlsfx.control.ToggleSwitch;
public class OperationsView implements FxmlView {
@InjectViewModel
OperationsViewModel viewModel;
+ @FXML private ToggleSwitch editSubgraphToggleSwitch;
+
+ public void initialize(){
+ editSubgraphToggleSwitch.selectedProperty().bindBidirectional(viewModel.editSubgraphProperty());
+ }
+
@FXML private void pathAction() {
viewModel.createPath();
}
diff --git a/src/main/java/com/todense/viewmodel/AlgorithmViewModel.java b/src/main/java/com/todense/viewmodel/AlgorithmViewModel.java
index 0bb618b..6a59575 100644
--- a/src/main/java/com/todense/viewmodel/AlgorithmViewModel.java
+++ b/src/main/java/com/todense/viewmodel/AlgorithmViewModel.java
@@ -5,6 +5,7 @@
import com.todense.model.graph.Node;
import com.todense.viewmodel.algorithm.Algorithm;
import com.todense.viewmodel.algorithm.AlgorithmTask;
+import com.todense.viewmodel.algorithm.AlgorithmTaskManager;
import com.todense.viewmodel.algorithm.task.*;
import com.todense.viewmodel.canvas.DisplayMode;
import com.todense.viewmodel.graph.GraphManager;
@@ -22,7 +23,7 @@
import javax.inject.Inject;
-public class AlgorithmViewModel implements ViewModel {
+public class AlgorithmViewModel extends AlgorithmTaskManager implements ViewModel {
@Inject
NotificationCenter notificationCenter;
@@ -41,8 +42,6 @@ public class AlgorithmViewModel implements ViewModel {
private GraphManager graphManager;
private BooleanProperty connectivityChecksProperty = new SimpleBooleanProperty(true);
-
- private AlgorithmTask task;
private double startTime;
public void initialize(){
@@ -63,22 +62,20 @@ public void initialize(){
});
notificationCenter.subscribe(GraphViewModel.NEW_GRAPH_REQUEST, (key, payload) -> {
- Platform.runLater(this::stop);
+ Platform.runLater(this::stopTask);
startNodeProperty().set(null);
goalNodeProperty().set(null);
});
+
+ super.initialize(taskScope, canvasScope, notificationCenter);
}
- public void start(){
+ @Override
+ protected AlgorithmTask createAlgorithmTask() {
Graph g = graphManager.getGraph();
- AlgorithmTask currentTask = taskScope.getTask();
-
- if((currentTask != null && currentTask.isRunning()) || g.getNodes().size() == 0) return;
-
graphScope.displayModeProperty().set(DisplayMode.ALGORITHMIC);
-
graphManager.resetGraph();
if(algorithmScope.getStartNode() == null){
@@ -94,39 +91,19 @@ public void start(){
boolean customWeight = graphScope.getEdgeWeightMode().equals(EdgeWeightMode.CUSTOM);
+ AlgorithmTask task = null;
+
switch (getAlgorithm()){
case BFS: task = new BFSTask(startNode, g); break;
case DFS: task = new DFSTask(startNode, g); break;
case PRIM: task = new PrimTask(startNode, g, customWeight); break;
case KRUSKAL: task = new KruskalTask(g, customWeight); break;
case DIJKSTRA: task = new DijkstraTask(startNode, goalNode, g, customWeight); break;
- case HCSEARCH: task = new HCSearchTask(startNode, g, connectivityChecksProperty.get()); break;
+ case HCSEARCH: task = new HamiltonianCycleSearchTask(startNode, g, connectivityChecksProperty.get()); break;
case ASTAR: task = new AStarTask(startNode, goalNode, g, customWeight); break;
}
- taskScope.setTask(task);
-
- task.setOnSucceeded(workerStateEvent -> notificationCenter.publish(MainViewModel.TASK_FINISHED,
- getAlgorithm(),
- System.currentTimeMillis()- startTime,
- task.getResultMessage()));
-
- task.setOnCancelled(workerStateEvent ->
- notificationCenter.publish(MainViewModel.TASK_CANCELLED, getAlgorithm()));
-
- task.setPainter(canvasScope.getPainter());
-
- notificationCenter.publish(MainViewModel.TASK_STARTED, getAlgorithm().toString());
-
- startTime = System.currentTimeMillis();
- Thread thread = new Thread(task);
- thread.start();
- }
-
- public void stop(){
- if(task != null){
- task.cancel();
- }
+ return task;
}
@@ -153,4 +130,5 @@ public ObjectProperty goalNodeProperty() {
public BooleanProperty showingEndpointsProperty() {
return algorithmScope.showingEndpointsProperty();
}
+
}
diff --git a/src/main/java/com/todense/viewmodel/AnimationViewModel.java b/src/main/java/com/todense/viewmodel/AnimationViewModel.java
index a52c362..0dc3e48 100644
--- a/src/main/java/com/todense/viewmodel/AnimationViewModel.java
+++ b/src/main/java/com/todense/viewmodel/AnimationViewModel.java
@@ -15,7 +15,6 @@ public void nextStep() {
nextStepProperty().setValue(true);
}
-
public IntegerProperty stepTimeProperty() {
return animationScope.stepTimeProperty();
}
diff --git a/src/main/java/com/todense/viewmodel/AntsViewModel.java b/src/main/java/com/todense/viewmodel/AntsViewModel.java
index d384ee7..55f4742 100644
--- a/src/main/java/com/todense/viewmodel/AntsViewModel.java
+++ b/src/main/java/com/todense/viewmodel/AntsViewModel.java
@@ -1,32 +1,31 @@
package com.todense.viewmodel;
import com.todense.model.graph.Graph;
-import com.todense.viewmodel.algorithm.AlgorithmTask;
+import com.todense.viewmodel.algorithm.AlgorithmTaskManager;
import com.todense.viewmodel.ants.*;
import com.todense.viewmodel.canvas.DisplayMode;
-import com.todense.viewmodel.canvas.drawlayer.layers.AntsDrawLayer;
-import com.todense.viewmodel.scope.AntsScope;
-import com.todense.viewmodel.scope.CanvasScope;
-import com.todense.viewmodel.scope.GraphScope;
-import com.todense.viewmodel.scope.TaskScope;
+import com.todense.viewmodel.scope.*;
import de.saxsys.mvvmfx.InjectScope;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
-import javafx.application.Platform;
-import javafx.beans.property.*;
-import javafx.concurrent.WorkerStateEvent;
-import javafx.event.EventHandler;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
import javafx.scene.paint.Color;
import javax.inject.Inject;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-public class AntsViewModel implements ViewModel {
+public class AntsViewModel extends AlgorithmTaskManager implements ViewModel {
@InjectScope
CanvasScope canvasScope;
+ @InjectScope
+ AlgorithmScope algorithmScope;
+
@InjectScope
AntsScope antsScope;
@@ -39,68 +38,54 @@ public class AntsViewModel implements ViewModel {
@Inject
NotificationCenter notificationCenter;
- private AntColonyAlgorithmTask algorithmTask;
-
DateFormat dateFormat = new SimpleDateFormat("mm:ss:SSS");
- private long startTime;
-
public void initialize(){
- AntsDrawLayer antsDrawLayer = new AntsDrawLayer(antsScope, graphScope);
- Platform.runLater(() -> canvasScope.getPainter().addDrawLayer(antsDrawLayer));
- }
+ //AntsDrawLayer antsDrawLayer = new AntsDrawLayer(antsScope, graphScope);
+ //Platform.runLater(() -> canvasScope.getPainter().addDrawLayer(antsDrawLayer));
- public void startAlgorithm(){
- AlgorithmTask currentTask = taskScope.getTask();
+ super.initialize(taskScope, canvasScope, notificationCenter);
+ }
- if(currentTask != null && currentTask.isRunning()) return;
+ @Override
+ protected AntColonyAlgorithmTask createAlgorithmTask() {
Graph graph = graphScope.getGraphManager().getGraph();
- if(graph.getNodes().size() < 3) return;
+ if(graph.getNodes().size() < 3){
+ throw new RuntimeException("Graph must have at least 3 nodes");
+ }
graphScope.getGraphManager().createCompleteGraph();
- startTime = System.currentTimeMillis();
- notificationCenter.publish(MainViewModel.TASK_STARTED, algorithmProperty().get().toString());
+ //notificationCenter.publish(MainViewModel.TASK_STARTED, algorithmProperty().get().toString());
graphScope.displayModeProperty().set(DisplayMode.ANT_COLONY);
+ AntColonyAlgorithmTask task = null;
+
switch (antsScope.algorithmProperty().get()){
case ACS:
- algorithmTask = new AntColonySystemTask(graph, antsScope);
+ task = new AntColonySystemTask(graph, antsScope, algorithmScope);
break;
case AS:
- algorithmTask = new AntSystemTask(graph, antsScope);
+ task = new AntSystemTask(graph, antsScope, algorithmScope);
break;
case MMAS:
- algorithmTask = new MaxMinAntSystemTask(graph, antsScope);
+ task = new MaxMinAntSystemTask(graph, antsScope, algorithmScope);
break;
case RANK_AS:
- algorithmTask = new RankedAntSystem(graph, antsScope);
+ task = new RankedAntSystem(graph, antsScope, algorithmScope);
break;
}
- this.algorithmTask.setPainter(canvasScope.getPainter());
- this.algorithmTask.bestSolutionLengthProperty().addListener((obs, oldVal, newVal) ->
+
+ task.setPainter(canvasScope.getPainter());
+ AntColonyAlgorithmTask finalTask = task;
+ task.bestSolutionLengthProperty().addListener((obs, oldVal, newVal) ->
notificationCenter.publish(MainViewModel.WRITE,
"Best Length: " + String.format("%.2f", newVal.doubleValue()) +
- " found in "+ dateFormat.format(System.currentTimeMillis()-startTime)+
- " after "+ algorithmTask.getIterationCounter()+ " iterations"));
- taskScope.setTask(this.algorithmTask);
+ " found in "+ dateFormat.format(System.currentTimeMillis() - super.getStartTime())+
+ " after "+ finalTask.getIterationCounter()+ " iterations"));
- EventHandler finishHandler = workerStateEvent ->
- notificationCenter.publish(MainViewModel.TASK_FINISHED,
- algorithmProperty().get().toString(),
- System.currentTimeMillis() - this.algorithmTask.getStartTime(),
- "");
-
- this.algorithmTask.setOnSucceeded(finishHandler);
- this.algorithmTask.setOnCancelled(finishHandler);
- this.algorithmTask.run();
- }
-
- public void stopAlgorithm(){
- if(algorithmTask != null && algorithmTask.isRunning()){
- algorithmTask.cancel();
- }
+ return task;
}
@@ -167,5 +152,4 @@ public IntegerProperty neighbourhoodSizeProperty() {
public IntegerProperty rankSizeProperty() {
return antsScope.rankSizeProperty();
}
-
}
diff --git a/src/main/java/com/todense/viewmodel/CanvasViewModel.java b/src/main/java/com/todense/viewmodel/CanvasViewModel.java
index 751fedc..de7debf 100644
--- a/src/main/java/com/todense/viewmodel/CanvasViewModel.java
+++ b/src/main/java/com/todense/viewmodel/CanvasViewModel.java
@@ -37,6 +37,9 @@ public class CanvasViewModel implements ViewModel {
@InjectScope
AnimationScope animationScope;
+ @InjectScope
+ AntsScope antsScope;
+
@InjectScope
KeysScope keysScope;
@@ -47,7 +50,6 @@ public class CanvasViewModel implements ViewModel {
NotificationCenter notificationCenter;
private MouseHandler mouseHandler;
-
private PopOverManager popOverManager;
public void initialize(){
@@ -70,7 +72,7 @@ public void initialize(){
Platform.runLater(() ->{
LowerDrawLayer lowerDrawLayer = new LowerDrawLayer(inputScope, graphScope);
- UpperDrawLayer upperDrawLayer = new UpperDrawLayer(graphScope, inputScope, canvasScope, backgroundScope, algorithmScope);
+ UpperDrawLayer upperDrawLayer = new UpperDrawLayer(graphScope, inputScope, canvasScope, backgroundScope, algorithmScope, antsScope);
painter.addDrawLayer(lowerDrawLayer);
painter.addDrawLayer(upperDrawLayer);
diff --git a/src/main/java/com/todense/viewmodel/GraphViewModel.java b/src/main/java/com/todense/viewmodel/GraphViewModel.java
index b0929f0..33f32b9 100644
--- a/src/main/java/com/todense/viewmodel/GraphViewModel.java
+++ b/src/main/java/com/todense/viewmodel/GraphViewModel.java
@@ -84,6 +84,10 @@ public void initialize(){
edgeWeightModeProperty().addListener(listener);
nodeBorderProperty().addListener(listener);
edgeVisibilityProperty().addListener(listener);
+ edgeWidthDecayProperty().addListener(listener);
+ edgeOpacityDecayProperty().addListener(listener);
+ edgeWidthDecayOnProperty().addListener(listener);
+ edgeOpacityDecayOnProperty().addListener(listener);
}
public void applyColorToNodes() {
@@ -100,6 +104,7 @@ public void applyColorToEdges() {
notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
}
+
public DoubleProperty nodeSizeProperty() {
return graphScope.nodeSizeProperty();
}
@@ -139,4 +144,20 @@ public BooleanProperty nodeBorderProperty() {
public BooleanProperty edgeVisibilityProperty() {
return graphScope.edgeVisibilityProperty();
}
+
+ public DoubleProperty edgeWidthDecayProperty() {
+ return graphScope.edgeWidthDecayProperty();
+ }
+
+ public BooleanProperty edgeWidthDecayOnProperty(){
+ return graphScope.edgeWidthDecayOnProperty();
+ }
+
+ public DoubleProperty edgeOpacityDecayProperty() {
+ return graphScope.edgeOpacityDecayProperty();
+ }
+
+ public BooleanProperty edgeOpacityDecayOnProperty() {
+ return graphScope.edgeOpacityDecayOnProperty();
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/LayoutViewModel.java b/src/main/java/com/todense/viewmodel/LayoutViewModel.java
index b28d93e..29c7ae3 100644
--- a/src/main/java/com/todense/viewmodel/LayoutViewModel.java
+++ b/src/main/java/com/todense/viewmodel/LayoutViewModel.java
@@ -1,8 +1,12 @@
package com.todense.viewmodel;
+import com.todense.model.graph.Node;
import com.todense.viewmodel.algorithm.AlgorithmTask;
+import com.todense.viewmodel.algorithm.AlgorithmTaskManager;
import com.todense.viewmodel.algorithm.task.ForceDirectedLayoutTask;
import com.todense.viewmodel.layout.LongRangeForce;
+import com.todense.viewmodel.random.Generator;
+import com.todense.viewmodel.random.arrangement.generators.RandomCirclePointGenerator;
import com.todense.viewmodel.scope.CanvasScope;
import com.todense.viewmodel.scope.GraphScope;
import com.todense.viewmodel.scope.TaskScope;
@@ -10,19 +14,20 @@
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
import javafx.beans.property.*;
-import javafx.concurrent.WorkerStateEvent;
-import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javax.inject.Inject;
+import java.util.HashMap;
-public class LayoutViewModel implements ViewModel {
+public class LayoutViewModel extends AlgorithmTaskManager implements ViewModel {
private IntegerProperty optDistProperty = new SimpleIntegerProperty(30);
+ private DoubleProperty smoothnessProperty = new SimpleDoubleProperty(0.9);
private DoubleProperty stepProperty = new SimpleDoubleProperty(5d);
private DoubleProperty toleranceProperty = new SimpleDoubleProperty(0.01);
private BooleanProperty coolingOnProperty = new SimpleBooleanProperty(true);
private BooleanProperty barnesHutOnProperty = new SimpleBooleanProperty(true);
+ private BooleanProperty smoothnessOnProperty = new SimpleBooleanProperty(false);
private DoubleProperty coolingStrengthProperty = new SimpleDoubleProperty(0.02);
private BooleanProperty centerPullOnProperty = new SimpleBooleanProperty(true);
private BooleanProperty multilevelOnProperty = new SimpleBooleanProperty(false);
@@ -41,43 +46,36 @@ public class LayoutViewModel implements ViewModel {
@Inject
NotificationCenter notificationCenter;
- private AlgorithmTask task;
+ private HashMap nodeSmoothedPositionMap;
+
public void initialize(){
- notificationCenter.subscribe("LAYOUT", (key, payload) -> start());
+ notificationCenter.subscribe("LAYOUT", (key, payload) -> super.startTask());
+ super.initialize(taskScope, canvasScope, notificationCenter);
}
- public void start(){
- AlgorithmTask currentTask = taskScope.getTask();
-
- if(currentTask != null && currentTask.isRunning()) return;
-
- task = new ForceDirectedLayoutTask(graphScope.getGraphManager(),
- this,new Point2D(canvasScope.getCanvasWidth()/2,
- canvasScope.getCanvasHeight()/2));
- task.setPainter(canvasScope.getPainter());
- taskScope.setTask(task);
-
- EventHandler handler = workerStateEvent -> {
- notificationCenter.publish(MainViewModel.TASK_FINISHED,
- "Force-Directed Layout",
- System.currentTimeMillis() - task.getStartTime(),
- "");
- };
+ @Override
+ public AlgorithmTask createAlgorithmTask() {
+ return new ForceDirectedLayoutTask(graphScope.getGraphManager(), this, canvasScope.getCanvasCenter());
+ }
- task.setOnSucceeded(handler);
- task.setOnCancelled(handler);
- notificationCenter.publish(MainViewModel.TASK_STARTED, "Force-Directed Layout");
- new Thread(task).start();
+ @Override
+ public void startTask() {
+ nodeSmoothedPositionMap = new HashMap<>();
+ graphScope.setNodePositionFunction(node -> nodeSmoothedPositionMap.get(node) != null ? nodeSmoothedPositionMap.get(node) : node.getPos());
+ super.startTask();
}
- public void stop(){
- if(task != null && task.isRunning()){
- task.cancel();
+ public void randomLayout() {
+ double height = canvasScope.getCanvasHeight() * 0.9;
+ Point2D canvasCenter = new Point2D(canvasScope.getCanvasWidth()/2, canvasScope.getCanvasHeight()/2);
+ Generator generator = new RandomCirclePointGenerator(height/2, canvasCenter);
+ for(Node n: graphScope.getGraphManager().getGraph().getNodes()){
+ n.setPos(generator.next());
}
+ notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
}
-
public int getOptDist() {
return optDistProperty.get();
}
@@ -157,4 +155,25 @@ public LongRangeForce getLongRangeForce() {
public ObjectProperty longRangeForceProperty() {
return longRangeForceProperty;
}
+
+ public double getSmoothness() {
+ return smoothnessProperty.get();
+ }
+
+ public DoubleProperty smoothnessProperty() {
+ return smoothnessProperty;
+ }
+
+ public boolean isSmoothnessOn() {
+ return smoothnessOnProperty.get();
+ }
+
+ public BooleanProperty smoothnessOnProperty() {
+ return smoothnessOnProperty;
+ }
+
+ public HashMap getNodeSmoothedPositionMap() {
+ return nodeSmoothedPositionMap;
+ }
+
}
diff --git a/src/main/java/com/todense/viewmodel/MainViewModel.java b/src/main/java/com/todense/viewmodel/MainViewModel.java
index c315035..183a2f4 100644
--- a/src/main/java/com/todense/viewmodel/MainViewModel.java
+++ b/src/main/java/com/todense/viewmodel/MainViewModel.java
@@ -83,6 +83,7 @@ public void initialize(){
notificationCenter.subscribe(TASK_CANCELLED, (key, payload) ->{
writeInfo("");
write(payload[0]+ " cancelled");
+ graphScope.setNodePositionFunction(GraphScope.NODE_ORDINARY_POSITION_FUNCTION);
workingProperty.set(false);
taskRunningProperty.set(false);
});
@@ -102,12 +103,13 @@ public void initialize(){
write((String) payload[2]); // result message
}
writeInfo("");
+ graphScope.setNodePositionFunction(GraphScope.NODE_ORDINARY_POSITION_FUNCTION);
workingProperty.set(false);
taskRunningProperty.set(false);
});
notificationCenter.subscribe(THREAD_STARTED, (key, payload) -> {
- stop();
+ stopAll();
writeInfo((String) payload[0]);
workingProperty.set(true);
});
@@ -155,8 +157,18 @@ public void openGraph(File file) {
canvasScope.getCanvasHeight() * 0.9); break;
}
assert graphReader != null;
- Graph openedGraph = graphReader.readGraph(file);
+ Graph openedGraph = null;
+ try{
+ openedGraph = graphReader.readGraph(file);
+ } catch (RuntimeException e){
+ if (e.getMessage() != null){
+ notificationCenter.publish(MainViewModel.WRITE,"ERROR: "+e.getMessage());
+ }else{
+ notificationCenter.publish(MainViewModel.WRITE, "Error: File is corrupted");
+ }
+ e.printStackTrace();
+ }
if(openedGraph != null){
notificationCenter.publish(GraphViewModel.NEW_GRAPH_REQUEST, openedGraph);
notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
@@ -165,8 +177,8 @@ public void openGraph(File file) {
}
- public void stop() {
- taskScope.stop();
+ public void stopAll() {
+ taskScope.stopTask();
}
public void setKeyInput(Scene scene){
@@ -198,11 +210,12 @@ public void setKeyInput(Scene scene){
public void write(String s){
Platform.runLater(() -> {
- String text = textProperty.get()
- + "\n"+"["+timeFormatter.format(System.currentTimeMillis())+"]"+" "+s;
+ String message = "["+timeFormatter.format(System.currentTimeMillis())+"]"+" "+s;
+ String text = textProperty.get() + "\n"+message;
textProperty.setValue(text);
- System.out.println(text);
+ System.out.println(message);
});
+
}
public void writeInfo(String s){
@@ -228,6 +241,7 @@ public void adjustCameraToGraph() {
notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
}
+
public ObjectProperty textProperty() {
return textProperty;
}
diff --git a/src/main/java/com/todense/viewmodel/NodePopOverViewModel.java b/src/main/java/com/todense/viewmodel/NodePopOverViewModel.java
index 2907cc5..7127139 100644
--- a/src/main/java/com/todense/viewmodel/NodePopOverViewModel.java
+++ b/src/main/java/com/todense/viewmodel/NodePopOverViewModel.java
@@ -5,7 +5,9 @@
import de.saxsys.mvvmfx.InjectScope;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
+import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.paint.Color;
@@ -16,7 +18,7 @@ public class NodePopOverViewModel implements ViewModel {
private ObjectProperty nodeColorProperty = new SimpleObjectProperty<>(Color.WHITE);
private ObjectProperty labelProperty = new SimpleObjectProperty<>("");
-
+ private DoubleProperty rotationProperty = new SimpleDoubleProperty(0d);
private List nodes;
@InjectScope
@@ -25,7 +27,7 @@ public class NodePopOverViewModel implements ViewModel {
@Inject
NotificationCenter notificationCenter;
- public void bindToNodes(List nodes){
+ public void bindToNodes(Node clickedNode, List nodes){
this.nodes = nodes;
this.nodeColorProperty.addListener((obs, oldVal, newVal) -> {
nodes.forEach((node -> node.setColor(nodeColorProperty.get())));
@@ -35,6 +37,14 @@ public void bindToNodes(List nodes){
nodes.forEach(node -> node.setLabelText(labelProperty.get()));
notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
});
+ this.rotationProperty.addListener((obs, oldVal, newVal) -> {
+ var GM = graphScope.getGraphManager();
+ double angle = Math.toRadians(newVal.doubleValue() - oldVal.doubleValue());
+ for(Node n : nodes){
+ GM.rotateNode(n, clickedNode.getPos(), angle);
+ }
+ notificationCenter.publish(CanvasViewModel.REPAINT_REQUEST);
+ });
//remove buttons if more than one node is selected
if(nodes.size() > 1){
@@ -81,4 +91,11 @@ public ObjectProperty labelProperty() {
return labelProperty;
}
+ public double getRotationProperty() {
+ return rotationProperty.get();
+ }
+
+ public DoubleProperty rotationProperty() {
+ return rotationProperty;
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/OperationsViewModel.java b/src/main/java/com/todense/viewmodel/OperationsViewModel.java
index 6b31e01..26275cd 100644
--- a/src/main/java/com/todense/viewmodel/OperationsViewModel.java
+++ b/src/main/java/com/todense/viewmodel/OperationsViewModel.java
@@ -1,13 +1,17 @@
package com.todense.viewmodel;
+import com.todense.model.graph.Node;
import com.todense.viewmodel.graph.GraphManager;
import com.todense.viewmodel.scope.GraphScope;
import com.todense.viewmodel.scope.TaskScope;
import de.saxsys.mvvmfx.InjectScope;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
import javax.inject.Inject;
+import java.util.List;
public class OperationsViewModel implements ViewModel {
@@ -20,6 +24,8 @@ public class OperationsViewModel implements ViewModel {
@Inject
NotificationCenter notificationCenter;
+ private BooleanProperty editSubgraphProperty = new SimpleBooleanProperty(false);
+
GraphManager graphManager;
public void initialize(){
@@ -27,25 +33,40 @@ public void initialize(){
}
public void createPath() {
- notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createPath());
-
+ notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createPath(getEditedNodes()));
}
+
+
public void createCompleteGraph() {
- notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createCompleteGraph());
+ notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createCompleteGraph(getEditedNodes()));
}
public void createComplementGraph() {
- notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createComplementGraph());
+ notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.createComplementGraph(getEditedNodes()));
}
public void subdivideEdges() {
- notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.subdivideEdges());
+ notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.subdivideEdges(getEditedNodes()));
}
public void deleteEdges() {
- notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.deleteEdges());
+ notificationCenter.publish(MainViewModel.GRAPH_EDIT_REQUEST, (Runnable) () -> graphManager.deleteEdges(getEditedNodes()));
+ }
+
+ public boolean isEditSubgraphOn() {
+ return editSubgraphProperty.get();
+ }
+
+ public BooleanProperty editSubgraphProperty() {
+ return editSubgraphProperty;
+ }
+
+ private List getEditedNodes() {
+ if(isEditSubgraphOn())
+ return graphManager.getSelectedNodes();
+ else return graphManager.getGraph().getNodes();
}
}
diff --git a/src/main/java/com/todense/viewmodel/PropertiesViewModel.java b/src/main/java/com/todense/viewmodel/PropertiesViewModel.java
index 1212025..aabe704 100644
--- a/src/main/java/com/todense/viewmodel/PropertiesViewModel.java
+++ b/src/main/java/com/todense/viewmodel/PropertiesViewModel.java
@@ -72,7 +72,7 @@ public void start(){
calculate();
notificationCenter.publish(MainViewModel.THREAD_FINISHED, "Calculated Properties");
});
- taskScope.setThread(propertiesThread);
+ //taskScope.setThread(propertiesThread);
propertiesThread.start();
}
}
diff --git a/src/main/java/com/todense/viewmodel/RandomGeneratorViewModel.java b/src/main/java/com/todense/viewmodel/RandomGeneratorViewModel.java
index 358ab03..2236a63 100644
--- a/src/main/java/com/todense/viewmodel/RandomGeneratorViewModel.java
+++ b/src/main/java/com/todense/viewmodel/RandomGeneratorViewModel.java
@@ -1,18 +1,20 @@
package com.todense.viewmodel;
import com.todense.model.graph.Graph;
+import com.todense.model.graph.Node;
import com.todense.viewmodel.random.Generator;
import com.todense.viewmodel.random.GeneratorModel;
import com.todense.viewmodel.random.RandomEdgeGenerator;
import com.todense.viewmodel.random.RandomGraphGenerator;
+import com.todense.viewmodel.random.arrangement.NodeArrangement;
import com.todense.viewmodel.random.arrangement.generators.CircularPointGenerator;
import com.todense.viewmodel.random.arrangement.generators.RandomCirclePointGenerator;
-import com.todense.viewmodel.random.arrangement.NodeArrangement;
import com.todense.viewmodel.random.arrangement.generators.RandomSquarePointGenerator;
import com.todense.viewmodel.random.generators.BarabasiAlbertGenerator;
import com.todense.viewmodel.random.generators.ErdosRenyiGenerator;
import com.todense.viewmodel.random.generators.GeometricGenerator;
import com.todense.viewmodel.scope.CanvasScope;
+import com.todense.viewmodel.scope.GraphScope;
import de.saxsys.mvvmfx.InjectScope;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
@@ -50,6 +52,9 @@ public class RandomGeneratorViewModel implements ViewModel {
@InjectScope
CanvasScope canvasScope;
+ @InjectScope
+ GraphScope graphScope;
+
public void initialize(){
notificationCenter.subscribe("RANDOM", (key, payload) -> generate());
}
@@ -106,7 +111,6 @@ private void generateGraph(){
throw new IllegalStateException("Unexpected value: " + generatorProperty.get());
}
-
try{
Graph randomGraph = RandomGraphGenerator.generateGraph(nodeCountProperty.get(), pointGenerator, edgeGenerator, minDist);
notificationCenter.publish(GraphViewModel.NEW_GRAPH_REQUEST, randomGraph);
@@ -122,6 +126,8 @@ public void generate(){
thread.start();
}
+
+
public ObjectProperty generatorProperty() {
return generatorProperty;
}
diff --git a/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTask.java b/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTask.java
index 1af6297..3957472 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTask.java
@@ -6,6 +6,8 @@
public abstract class AlgorithmTask extends Task{
+ protected String algorithmName = "Unnamed Algorithm";
+
protected Graph graph;
protected String resultMessage = "";
protected Painter painter;
@@ -71,7 +73,6 @@ public void setPainter(Painter painter){
}
-
public String getResultMessage() {
return resultMessage;
}
@@ -95,4 +96,8 @@ public double getResult() {
public void setResult(double result) {
this.result = result;
}
+
+ public String getAlgorithmName() {
+ return algorithmName;
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTaskManager.java b/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTaskManager.java
new file mode 100644
index 0000000..9e07f46
--- /dev/null
+++ b/src/main/java/com/todense/viewmodel/algorithm/AlgorithmTaskManager.java
@@ -0,0 +1,66 @@
+package com.todense.viewmodel.algorithm;
+
+import com.todense.viewmodel.MainViewModel;
+import com.todense.viewmodel.scope.CanvasScope;
+import com.todense.viewmodel.scope.TaskScope;
+import de.saxsys.mvvmfx.utils.notifications.NotificationCenter;
+import javafx.concurrent.WorkerStateEvent;
+import javafx.event.EventHandler;
+
+public abstract class AlgorithmTaskManager {
+
+ private AlgorithmTask task;
+ private TaskScope taskScope;
+ private CanvasScope canvasScope;
+ private NotificationCenter notificationCenter;
+
+ private long startTime;
+
+
+ public void initialize(TaskScope taskScope, CanvasScope canvasScope, NotificationCenter notificationCenter){
+ this.taskScope = taskScope;
+ this.canvasScope = canvasScope;
+ this.notificationCenter = notificationCenter;
+
+ }
+
+ public void startTask() {
+ if (!taskScope.isDone())
+ return;
+
+ task = createAlgorithmTask();
+
+ task.setPainter(canvasScope.getPainter());
+
+ EventHandler handler = workerStateEvent -> {
+ notificationCenter.publish(MainViewModel.TASK_FINISHED,
+ task.getAlgorithmName(),
+ System.currentTimeMillis() - task.getStartTime(),
+ "");
+ };
+
+ task.setOnSucceeded(workerStateEvent -> notificationCenter.publish(MainViewModel.TASK_FINISHED,
+ task.getAlgorithmName(),
+ System.currentTimeMillis() - startTime,
+ task.getResultMessage()));
+
+ task.setOnCancelled(workerStateEvent ->
+ notificationCenter.publish(MainViewModel.TASK_CANCELLED, task.getAlgorithmName()));
+
+ startTime = System.currentTimeMillis();
+ notificationCenter.publish(MainViewModel.TASK_STARTED, task.getAlgorithmName());
+ taskScope.start(task);
+ }
+
+ public void stopTask(){
+ if(task != null && task.isRunning()){
+ task.cancel();
+ }
+ }
+
+ protected abstract AlgorithmTask createAlgorithmTask();
+
+ public long getStartTime() {
+ return startTime;
+ }
+}
diff --git a/src/main/java/com/todense/viewmodel/algorithm/TestTask.java b/src/main/java/com/todense/viewmodel/algorithm/TestTask.java
deleted file mode 100644
index fcedf50..0000000
--- a/src/main/java/com/todense/viewmodel/algorithm/TestTask.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.todense.viewmodel.algorithm;
-
-import javafx.concurrent.Task;
-
-public class TestTask extends Task {
-
-
- @Override
- protected Void call() throws Exception {
- return null;
- }
-
- @Override
- protected void running() {
- super.running();
- }
-}
diff --git a/src/main/java/com/todense/viewmodel/algorithm/WalkingAgent.java b/src/main/java/com/todense/viewmodel/algorithm/WalkingAgent.java
new file mode 100644
index 0000000..8a1d8ff
--- /dev/null
+++ b/src/main/java/com/todense/viewmodel/algorithm/WalkingAgent.java
@@ -0,0 +1,26 @@
+package com.todense.viewmodel.algorithm;
+
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+
+public class WalkingAgent {
+
+ DoubleProperty x = new SimpleDoubleProperty();
+ DoubleProperty y = new SimpleDoubleProperty();
+
+ public double getX() {
+ return x.get();
+ }
+
+ public DoubleProperty xProperty() {
+ return x;
+ }
+
+ public double getY() {
+ return y.get();
+ }
+
+ public DoubleProperty yProperty() {
+ return y;
+ }
+}
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/AStarTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/AStarTask.java
index 7062dd5..547b952 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/AStarTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/AStarTask.java
@@ -23,6 +23,7 @@ public AStarTask(Node startNode, Node goalNode, Graph graph, boolean customWeigh
super(graph, customWeight);
this.startNode = startNode;
this.goalNode = goalNode;
+ super.algorithmName = "A* Shortest Path";
}
@Override
@@ -31,6 +32,8 @@ public void perform() throws InterruptedException {
result = super.pathLength;
}
+
+
@Override
protected void init(){
int n = graph.getNodes().size();
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/BFSTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/BFSTask.java
index 33bb685..ca93400 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/BFSTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/BFSTask.java
@@ -14,6 +14,7 @@ public class BFSTask extends AlgorithmTask {
public BFSTask(Node startNode, Graph graph){
super(graph);
this.startNode = startNode;
+ super.algorithmName = "BFS";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/DFSTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/DFSTask.java
index f5f153f..7c44773 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/DFSTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/DFSTask.java
@@ -15,6 +15,7 @@ public class DFSTask extends AlgorithmTask {
public DFSTask(Node startNode, Graph graph){
super(graph);
this.startNode = startNode;
+ super.algorithmName = "DFS";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/DijkstraTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/DijkstraTask.java
index 481d3b2..bcec110 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/DijkstraTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/DijkstraTask.java
@@ -21,6 +21,7 @@ public DijkstraTask(Node startNode, Node goalNode, Graph graph, boolean customWe
super(graph, customWeight);
this.startNode = startNode;
this.goalNode = goalNode;
+ super.algorithmName = "Dijkstra's Algorithm";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/ForceDirectedLayoutTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/ForceDirectedLayoutTask.java
index 1d1d55a..08b4952 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/ForceDirectedLayoutTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/ForceDirectedLayoutTask.java
@@ -12,9 +12,7 @@
import com.todense.viewmodel.layout.barnesHut.QuadTree;
import javafx.geometry.Point2D;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Stack;
+import java.util.*;
public class ForceDirectedLayoutTask extends AlgorithmTask {
@@ -22,6 +20,8 @@ public class ForceDirectedLayoutTask extends AlgorithmTask {
private LayoutViewModel layoutVM;
private int coolingCounter = 0;
+ private double smoothness;
+ private boolean smoothModeOn;
double energy = Double.POSITIVE_INFINITY;
@@ -41,6 +41,7 @@ public class ForceDirectedLayoutTask extends AlgorithmTask {
private double repulsiveStrength;
private final double repulsiveness = 1d;
+ private int counter = 0;
private QuadTree quadTree;
@@ -48,6 +49,8 @@ public class ForceDirectedLayoutTask extends AlgorithmTask {
private LongRangeForce longRangeForce;
private Point2D center;
+ private Random rnd = new Random();
+
public ForceDirectedLayoutTask(GraphManager graphManager, LayoutViewModel layoutVM, Point2D center){
super(graphManager.getGraph());
this.graphManager = graphManager;
@@ -59,30 +62,20 @@ public ForceDirectedLayoutTask(GraphManager graphManager, LayoutViewModel layout
this.tolerance = layoutVM.getTolerance();
this.longRangeForce = layoutVM.getLongRangeForce();
this.repulsiveStrength = getRepulsiveStrength(repulsiveness, optDist, longRangeForce.getExponent() + 1);
+ this.smoothness = layoutVM.getSmoothness();
+ this.smoothModeOn = layoutVM.isSmoothnessOn();
+ super.algorithmName = "Force Directed Layout";
}
@Override
- public void perform() throws InterruptedException {
-
+ public void perform() {
if(layoutVM.isMultilevelOn()){
- GraphCoarsener graphCoarsener = new GraphCoarsener(graphManager);
- graphCoarsener.initGraphSequence();
-
- while(!graphCoarsener.maxLevelReached()){
- graphCoarsener.coarsen();
- painter.sleep();
- }
- optDist = optDist * Math.pow(gamma, graphCoarsener.getGraphSequence().size()-1);
-
- while(graphCoarsener.getGraphSequence().size() > 1){
- optDist = optDist/gamma;
- stepSize = initStep;
- graphCoarsener.reconstruct(0.3 * optDist);
- painter.sleep();
- forceDirectedLayout(graphCoarsener.getGraphSequence().peek());
- }
+ multilevelForceDirectedLayout(graph);
}else{
- forceDirectedLayout(graph);
+ try {
+ forceDirectedLayout(graph);
+ } catch (InterruptedException ignored) {
+ }
}
}
@@ -90,20 +83,51 @@ public void perform() throws InterruptedException {
protected void onFinished() {
}
+
void init(Graph graph){
- int nodeCount = graph.getNodes().size();
+ int nodeCount = graph.getOrder();
repulsiveForces = new double[nodeCount][nodeCount];
attractiveForces = new double[nodeCount][nodeCount];
nodeEnergies = new double[nodeCount];
distances = new double[nodeCount][nodeCount];
+
+ var smoothedNodePositionMap = layoutVM.getNodeSmoothedPositionMap();
+ for (Node n: graph.getNodes()){
+ smoothedNodePositionMap.put(n, n.getPos());
+ }
}
- public int counter = 0;
+ public void multilevelForceDirectedLayout(Graph graph){
+ GraphCoarsener graphCoarsener = new GraphCoarsener(graphManager);
+ graphCoarsener.initGraphSequence();
+ while(!graphCoarsener.maxLevelReached()){
+ graphCoarsener.coarsen();
+ try {
+ painter.sleep();
+ } catch (InterruptedException e) {
+ if(graphManager.getGraph().getOrder() < graphCoarsener.getOriginalGraph().getOrder()){
+ graphManager.setGraph(graphCoarsener.getOriginalGraph());
+ }
+ }
+ }
+ optDist = optDist * Math.pow(gamma, graphCoarsener.getGraphSequence().size()-1);
+ while(graphCoarsener.getGraphSequence().size() > 1){
+ optDist = optDist/gamma;
+ stepSize = initStep;
+ graphCoarsener.reconstruct(0.3 * optDist);
+ try {
+ painter.sleep();
+ forceDirectedLayout(graphCoarsener.getGraphSequence().peek());
+ } catch (InterruptedException e) {
+ if(graphManager.getGraph().getOrder() < graphCoarsener.getOriginalGraph().getOrder()){
+ graphManager.setGraph(graphCoarsener.getOriginalGraph());
+ }
+ }
+ }
+ }
public void forceDirectedLayout(Graph graph) throws InterruptedException {
-
init(graph);
-
while(!super.isCancelled() && stepSize > tolerance * optDist) {
counter++;
@@ -149,6 +173,7 @@ public void forceDirectedLayout(Graph graph) throws InterruptedException {
nodeForceMap = new HashMap<>();
+
//apply forces to every node
graph.getNodes().forEach(n ->{
Point2D force = new Point2D(0, 0);
@@ -160,7 +185,7 @@ public void forceDirectedLayout(Graph graph) throws InterruptedException {
for (Node m : graph.getNodes()) {
double dist = getDistance(n, m);
//if(dist > 0 && dist < 2 * (coarserLevel + 1) * optDist) {
- if(dist > 0 ) {
+ if(dist > 0) {
double rf = repulsiveForces[n.getIndex()][m.getIndex()];
force = force.add(m.getPos().subtract(n.getPos()).multiply(rf/dist));
}
@@ -184,10 +209,22 @@ public void forceDirectedLayout(Graph graph) throws InterruptedException {
nodeEnergies[n.getIndex()] = Math.pow(force.getX(), 2) + Math.pow(force.getY(), 2);
- nodeForceMap.put(n, force.normalize().multiply(stepSize));
+ nodeForceMap.put(n, force.normalize().multiply(stepSize).add(new Point2D(rnd.nextGaussian()/5, rnd.nextGaussian()/5)));
});
- nodeForceMap.forEach((node, force) -> node.setPos(node.getPos().add(force)));
+
+ nodeForceMap.forEach((node, force) -> {
+ Point2D updatedPos = node.getPos().add(force);
+ if(layoutVM.isSmoothnessOn()){
+ double smoothness = layoutVM.getSmoothness();
+ Point2D smoothedPos = updatedPos.multiply(1-smoothness).add(layoutVM.getNodeSmoothedPositionMap().get(node).multiply(smoothness));
+ layoutVM.getNodeSmoothedPositionMap().replace(node, smoothedPos);
+ }
+ else{
+ layoutVM.getNodeSmoothedPositionMap().replace(node, updatedPos);
+ }
+ node.setPos(updatedPos);
+ });
Arrays.stream(nodeEnergies).forEach(e -> energy += e);
@@ -195,12 +232,25 @@ public void forceDirectedLayout(Graph graph) throws InterruptedException {
if(layoutVM.isCoolingOn()) {
stepSize = updateStepLength(energy, prevEnergy);
+ }else{
+ stepSize = layoutVM.getStep();
+ }
+ }
+
+ //transition between smoothed and real position
+ if(smoothModeOn){
+ for(int i = 0; i < 20; i++){
+ for(Node node: graph.getNodes()){
+ var currentPos = layoutVM.getNodeSmoothedPositionMap().get(node);
+ layoutVM.getNodeSmoothedPositionMap().replace(node, node.getPos().add(currentPos.subtract(node.getPos()).multiply(0.8)));
+ }
+ painter.sleep(10);
}
}
- super.repaint();
+ painter.repaint();
}
- private Point2D calcBarnesHutRepulsiveForce(Node node, double strength ,QuadTree quadTree){
+ private Point2D calcBarnesHutRepulsiveForce(Node node, double strength, QuadTree quadTree){
Point2D repulsiveForce = new Point2D(0, 0);
Stack cellStack = new Stack<>();
cellStack.add(quadTree.getRoot());
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/HCSearchTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/HamiltonianCycleSearchTask.java
similarity index 92%
rename from src/main/java/com/todense/viewmodel/algorithm/task/HCSearchTask.java
rename to src/main/java/com/todense/viewmodel/algorithm/task/HamiltonianCycleSearchTask.java
index b6ff765..b3bb6ee 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/HCSearchTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/HamiltonianCycleSearchTask.java
@@ -10,7 +10,7 @@
import java.util.Stack;
-public class HCSearchTask extends AlgorithmTask {
+public class HamiltonianCycleSearchTask extends AlgorithmTask {
ArrayList cycle;
boolean[] visitedDFS;
@@ -20,10 +20,11 @@ public class HCSearchTask extends AlgorithmTask {
private Node startNode;
private boolean checkingConnectivity;
- public HCSearchTask(Node startNode, Graph graph, boolean checkingConnectivity){
+ public HamiltonianCycleSearchTask(Node startNode, Graph graph, boolean checkingConnectivity){
super(graph);
this.startNode = startNode;
this.checkingConnectivity = checkingConnectivity;
+ super.algorithmName = "Hamiltonian Cycle Search";
}
@Override
@@ -56,7 +57,7 @@ boolean HCSearch(Node startNode) throws InterruptedException {
Stack nodeStack = new Stack<>();
- //push node twice : first time for removing from a cycle when backtracking, second time for adding node to a cycle
+ //push node twice: first time for removing from a cycle when backtracking, second time for adding node to a cycle
nodeStack.push(startNode);
nodeStack.push(startNode);
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/KruskalTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/KruskalTask.java
index 1c046c8..5f35cbe 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/KruskalTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/KruskalTask.java
@@ -19,6 +19,7 @@ public class KruskalTask extends WeightedAlgorithmTask {
public KruskalTask(Graph graph, boolean customWeight) {
super(graph, customWeight);
+ super.algorithmName = "Kruskal's algorithm";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/algorithm/task/PrimTask.java b/src/main/java/com/todense/viewmodel/algorithm/task/PrimTask.java
index f475524..01ffa49 100644
--- a/src/main/java/com/todense/viewmodel/algorithm/task/PrimTask.java
+++ b/src/main/java/com/todense/viewmodel/algorithm/task/PrimTask.java
@@ -22,6 +22,7 @@ public class PrimTask extends WeightedAlgorithmTask {
public PrimTask(Node startNode, Graph graph, boolean customWeight) {
super(graph, customWeight);
this.startNode = startNode;
+ super.algorithmName = "Prim's algorithm";
}
diff --git a/src/main/java/com/todense/viewmodel/ants/Ant.java b/src/main/java/com/todense/viewmodel/ants/Ant.java
index 976920c..3caa6c3 100644
--- a/src/main/java/com/todense/viewmodel/ants/Ant.java
+++ b/src/main/java/com/todense/viewmodel/ants/Ant.java
@@ -1,12 +1,11 @@
package com.todense.viewmodel.ants;
-import javafx.beans.property.DoubleProperty;
-import javafx.beans.property.SimpleDoubleProperty;
+import com.todense.viewmodel.algorithm.WalkingAgent;
import java.util.ArrayList;
-public class Ant{
+public class Ant extends WalkingAgent {
private double cycleLength = 0;
@@ -19,10 +18,6 @@ public class Ant{
private int goal;
private int previous;
-
- private DoubleProperty x = new SimpleDoubleProperty();
- private DoubleProperty y = new SimpleDoubleProperty();
-
public Ant(int start){
this.start = start;
}
@@ -43,22 +38,6 @@ public void setCycleLength(double cycleLength) {
this.cycleLength = cycleLength;
}
- public double getX() {
- return x.get();
- }
-
- public DoubleProperty xProperty() {
- return x;
- }
-
- public double getY() {
- return y.get();
- }
-
- public DoubleProperty yProperty() {
- return y;
- }
-
public int getGoal() {
return goal;
}
diff --git a/src/main/java/com/todense/viewmodel/ants/AntColonyAlgorithmTask.java b/src/main/java/com/todense/viewmodel/ants/AntColonyAlgorithmTask.java
index 2b0b31f..2e03725 100644
--- a/src/main/java/com/todense/viewmodel/ants/AntColonyAlgorithmTask.java
+++ b/src/main/java/com/todense/viewmodel/ants/AntColonyAlgorithmTask.java
@@ -4,6 +4,7 @@
import com.todense.model.graph.Graph;
import com.todense.model.graph.Node;
import com.todense.viewmodel.algorithm.AlgorithmTask;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
@@ -25,6 +26,7 @@
public abstract class AntColonyAlgorithmTask extends AlgorithmTask {
final AntsScope antsScope;
+ final AlgorithmScope algorithmScope;
private DoubleProperty bestSolutionLength = new SimpleDoubleProperty(Double.POSITIVE_INFINITY); //global best cycle length
@@ -50,9 +52,10 @@ public abstract class AntColonyAlgorithmTask extends AlgorithmTask {
private Random rnd = new Random();
private final Object lock = new Object();
- public AntColonyAlgorithmTask(Graph graph, AntsScope antsScope){
+ public AntColonyAlgorithmTask(Graph graph, AntsScope antsScope, AlgorithmScope algorithmScope){
super(graph);
this.antsScope = antsScope;
+ this.algorithmScope = algorithmScope;
this.graphOrder = graph.getOrder();
antsScope.getAnts().clear();
@@ -64,7 +67,7 @@ public AntColonyAlgorithmTask(Graph graph, AntsScope antsScope){
antsScope.setGbCycle(new ArrayList<>());
antsScope.setPheromones(new double[graphOrder][graphOrder]);
-
+ algorithmScope.setWalkingAgents(antsScope.getAnts());
}
@Override
@@ -76,7 +79,6 @@ public void perform() {
@Override
protected void onFinished() {
-
}
protected double getInitialPheromoneLevel(){
@@ -165,14 +167,12 @@ else if(antsScope.isWith2Opt()){
protected void moveAnts() {
AtomicBoolean working = new AtomicBoolean(true);
-
for (Ant ant : antsScope.getAnts()) {
ant.setPrevious(ant.getStart());
moveAnt(ant);
}
if(!super.isConnectedToUI())
return;
-
if(painter.isAnimationOn() && antsScope.isAntsAnimationOn()){
ParallelTransition transition = new ParallelTransition();
for (Ant ant : antsScope.getAnts()) {
@@ -190,6 +190,7 @@ protected void moveAnts() {
try {
lock.wait();
} catch (InterruptedException e) {
+ working.set(false);
transition.stop();
antsScope.getAnts().clear();
}
@@ -221,7 +222,6 @@ protected void moveAnt(Ant ant){
else{
ant.setStart(ant.getGoal());
}
-
}
protected int getRandomNeighbour(Ant ant, List availableNeighbours) throws MathArithmeticException {
@@ -389,10 +389,8 @@ private double inPheromoneRange(double value) {
}
private Timeline antMoveTimeline(Ant ant) {
-
Node start = graph.getNodes().get(ant.getPrevious());
Node goal = graph.getNodes().get(ant.getGoal());
-
return new Timeline(
new KeyFrame(Duration.millis(0),
new KeyValue(ant.xProperty(), start.getPos().getX()),
diff --git a/src/main/java/com/todense/viewmodel/ants/AntColonySystemTask.java b/src/main/java/com/todense/viewmodel/ants/AntColonySystemTask.java
index 707d272..fae52a3 100644
--- a/src/main/java/com/todense/viewmodel/ants/AntColonySystemTask.java
+++ b/src/main/java/com/todense/viewmodel/ants/AntColonySystemTask.java
@@ -2,6 +2,7 @@
import com.todense.model.graph.Graph;
import com.todense.model.graph.Node;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
import org.apache.commons.math3.exception.MathArithmeticException;
@@ -12,8 +13,9 @@ public class AntColonySystemTask extends AntColonyAlgorithmTask {
private Random rnd = new Random();
- public AntColonySystemTask(Graph graph, AntsScope antsScope) {
- super(graph, antsScope);
+ public AntColonySystemTask(Graph graph, AntsScope antsScope, AlgorithmScope algorithmScope) {
+ super(graph, antsScope, algorithmScope);
+ super.algorithmName = "Ant Colony System";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/ants/AntSystemTask.java b/src/main/java/com/todense/viewmodel/ants/AntSystemTask.java
index 4c5c3d4..2373c8a 100644
--- a/src/main/java/com/todense/viewmodel/ants/AntSystemTask.java
+++ b/src/main/java/com/todense/viewmodel/ants/AntSystemTask.java
@@ -1,12 +1,14 @@
package com.todense.viewmodel.ants;
import com.todense.model.graph.Graph;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
public class AntSystemTask extends AntColonyAlgorithmTask {
- public AntSystemTask(Graph graph, AntsScope antsScope) {
- super(graph, antsScope);
+ public AntSystemTask(Graph graph, AntsScope antsScope, AlgorithmScope algorithmScope) {
+ super(graph, antsScope, algorithmScope);
+ super.algorithmName = "Ant System";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/ants/MaxMinAntSystemTask.java b/src/main/java/com/todense/viewmodel/ants/MaxMinAntSystemTask.java
index b993a2b..68bed71 100644
--- a/src/main/java/com/todense/viewmodel/ants/MaxMinAntSystemTask.java
+++ b/src/main/java/com/todense/viewmodel/ants/MaxMinAntSystemTask.java
@@ -1,13 +1,15 @@
package com.todense.viewmodel.ants;
import com.todense.model.graph.Graph;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
public class MaxMinAntSystemTask extends AntColonyAlgorithmTask {
- public MaxMinAntSystemTask(Graph graph, AntsScope antsScope) {
- super(graph, antsScope);
+ public MaxMinAntSystemTask(Graph graph, AntsScope antsScope, AlgorithmScope algorithmScope) {
+ super(graph, antsScope, algorithmScope);
+ super.algorithmName = "Max-Min Ant System";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/ants/RankedAntSystem.java b/src/main/java/com/todense/viewmodel/ants/RankedAntSystem.java
index c0c4a65..2f482b2 100644
--- a/src/main/java/com/todense/viewmodel/ants/RankedAntSystem.java
+++ b/src/main/java/com/todense/viewmodel/ants/RankedAntSystem.java
@@ -1,14 +1,16 @@
package com.todense.viewmodel.ants;
import com.todense.model.graph.Graph;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
import java.util.Comparator;
public class RankedAntSystem extends AntColonyAlgorithmTask {
- public RankedAntSystem(Graph graph, AntsScope antsScope) {
- super(graph, antsScope);
+ public RankedAntSystem(Graph graph, AntsScope antsScope, AlgorithmScope algorithmScope) {
+ super(graph, antsScope, algorithmScope);
+ super.algorithmName = "Ranked Ant System";
}
@Override
diff --git a/src/main/java/com/todense/viewmodel/canvas/Camera.java b/src/main/java/com/todense/viewmodel/canvas/Camera.java
index ada3791..a1f7364 100644
--- a/src/main/java/com/todense/viewmodel/canvas/Camera.java
+++ b/src/main/java/com/todense/viewmodel/canvas/Camera.java
@@ -43,7 +43,6 @@ public void adjustToGraph(Graph graph, double canvasWidth, double canvasHeight,
affine.appendTranslation(translation.getX(), translation.getY());
affine.appendScale(1/d, 1/d, center);
-
}
public void translate(Point2D delta) {
@@ -51,7 +50,7 @@ public void translate(Point2D delta) {
affine.appendTranslation(scaledDelta.getX(), scaledDelta.getY());
}
- public Point2D inverse(Point2D point) {
+ public Point2D inverse(Point2D point) {
try {
return affine.inverseTransform(point);
} catch (NonInvertibleTransformException e) {
diff --git a/src/main/java/com/todense/viewmodel/canvas/MouseHandler.java b/src/main/java/com/todense/viewmodel/canvas/MouseHandler.java
index 0dbc1ee..edf4932 100644
--- a/src/main/java/com/todense/viewmodel/canvas/MouseHandler.java
+++ b/src/main/java/com/todense/viewmodel/canvas/MouseHandler.java
@@ -114,6 +114,9 @@ else if(clickedEdge != null){
}
public void onMouseClicked(MouseEvent event) {
+
+ if(inputScope.isEditLocked()) return;
+
if(event.getButton() == MouseButton.PRIMARY && !dragging) { // LEFT MOUSE BUTTON
if(!pressedKeys.contains(KeyCode.SHIFT)){
if(clickedNode == null && clickedEdge == null){ // click on background
@@ -130,11 +133,13 @@ else if(pressedKeys.contains(KeyCode.CONTROL)){
if(pressedKeys.contains(KeyCode.C)){
graphScope.getGraphManager().copySelectedSubgraph();
}
- if(clickedNode != null){
- reverseSelection(clickedNode);
- }
else{
- reverseSelection(clickedEdge);
+ if(clickedNode != null){
+ reverseSelection(clickedNode);
+ }
+ else{
+ reverseSelection(clickedEdge);
+ }
}
}
}
@@ -177,7 +182,7 @@ else if(!inputScope.isSelecting()){
releaseNode.setSelected(true);
GM.getSelectedNodes().add(releaseNode);
}
- popOver = popOverManager.createNodePopOver(graphScope.getGraphManager(),
+ popOver = popOverManager.createNodePopOver(graphScope.getGraphManager(), releaseNode,
GM.getSelectedNodes(), event.getScreenX(), event.getScreenY());
} else if (releaseEdge != null) { //edge popover
if (!releaseEdge.isSelected()) {
@@ -205,17 +210,18 @@ else if(!inputScope.isSelecting()){
}
edgeStartNode = null;
}
+ inputScope.getDummyEdgeStartNodes().clear();
painter.repaint();
}
public void onMouseMoved(MouseEvent event){
- if(inputScope.isEditLocked()) return;
-
Point2D movePt = new Point2D(event.getX(), event.getY());
currentMousePt = movePt;
+ if(inputScope.isEditLocked()) return;
+
Node prevNode = hoverNode;
hoverNode = getNodeFromPoint(movePt);
@@ -261,7 +267,7 @@ public void onMouseDragged(MouseEvent event) {
if(inputScope.isEditLocked()){
camera.translate(delta);
- currentMousePt = new Point2D(event.getX(),event.getY());
+ currentMousePt = new Point2D(event.getX(), event.getY());
painter.repaint();
return;
}
@@ -281,9 +287,15 @@ public void onMouseDragged(MouseEvent event) {
camera.translate(delta);
currentMousePt = new Point2D(event.getX(),event.getY());
}
- else if(clickedNode != null) {
+ else if(clickedNode != null && !pressedKeys.contains(KeyCode.CONTROL)) {
if (!clickedNode.isSelected()) {
- GM.updateNodePosition(clickedNode, delta.multiply(1/ camera.getZoom()));
+ GM.updateNodePosition(clickedNode, delta.multiply(1/camera.getZoom()));
+ }
+ else if(pressedKeys.contains(KeyCode.A)){
+ int clockwise = delta.getY() > 0? 1 : -1;
+ for (Node n : GM.getSelectedNodes()) {
+ GM.rotateNode(n, clickedNode.getPos(), clockwise * 0.02);
+ }
}
else {
for (Node n : GM.getSelectedNodes()) {
@@ -388,6 +400,9 @@ public void selectNodesInRect(Rectangle2D rect){
for(Node n: GM.getGraph().getNodes()){
n.setSelected(rect.contains(camera.transform(n.getPos())));
}
+ for(Edge e: GM.getGraph().getEdges()){
+ e.setMarked(e.getN1().isSelected() && e.getN2().isSelected());
+ }
}
private void reverseSelection(Node n){
@@ -398,6 +413,11 @@ private void reverseSelection(Node n){
n.setSelected(true);
GM.getSelectedNodes().add(n);
}
+ Graph g = GM.getGraph();
+ for(Node m : n.getNeighbours()){
+ Edge e = g.getEdge(n, m);
+ e.setMarked(e.getN1().isSelected() && e.getN2().isSelected());
+ }
}
private void reverseSelection(Edge e){
@@ -419,6 +439,11 @@ public void hidePopOver(){
public void clearSelection(){
for(Edge edge : selectedEdges){
edge.setSelected(false);
+ //edge.setHighlighted(false);
+ //edge.setMarked(false);
+ }
+ for(Edge edge : GM.getGraph().getEdges()){
+ edge.setMarked(false);
}
selectedEdges.clear();
for(Node node : GM.getSelectedNodes()){
diff --git a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/AntsDrawLayer.java b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/AntsDrawLayer.java
deleted file mode 100644
index cb18889..0000000
--- a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/AntsDrawLayer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.todense.viewmodel.canvas.drawlayer.layers;
-
-import com.todense.viewmodel.ants.Ant;
-import com.todense.viewmodel.canvas.DisplayMode;
-import com.todense.viewmodel.canvas.drawlayer.DrawLayer;
-import com.todense.viewmodel.scope.AntsScope;
-import com.todense.viewmodel.scope.GraphScope;
-import javafx.scene.canvas.GraphicsContext;
-
-public class AntsDrawLayer implements DrawLayer {
-
- private AntsScope antsScope;
- private GraphScope graphScope;
-
- public AntsDrawLayer(AntsScope antsScope, GraphScope graphScope){
- this.antsScope = antsScope;
- this.graphScope = graphScope;
- }
-
- @Override
- public void draw(GraphicsContext gc) {
- if(graphScope.getDisplayMode() == DisplayMode.ANT_COLONY) {
- if (antsScope.isAntsAnimationOn()) {
- gc.setFill(antsScope.getAntColor());
- double size = antsScope.getAntSize() * graphScope.getNodeSize();
- for (Ant ant : antsScope.getAnts()){
- gc.fillOval(
- ant.getX() - size,
- ant.getY() - size,
- 2 * size,
- 2 * size
- );
- }
- }
- }
- }
-
- @Override
- public int getOrder() {
- return 3;
- }
-}
diff --git a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/BackgroundDrawLayer.java b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/BackgroundDrawLayer.java
index e8914cd..bd90698 100644
--- a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/BackgroundDrawLayer.java
+++ b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/BackgroundDrawLayer.java
@@ -41,13 +41,18 @@ public void draw(GraphicsContext gc) {
private void drawGrid(GraphicsContext gc, double width, double height){
double gap = backgroundScope.getGridGap();
+ double screenGap = camera.getZoom() * gap;
+ double log2Floor = Math.floor(Math.log(screenGap/gap)/Math.log(2));
+
+ screenGap /= Math.pow(2, log2Floor);
+ gap = screenGap / camera.getZoom();
Point2D center = new Point2D(width/2, height/2);
Point2D start = camera.inverse(new Point2D(0,0));
Point2D end = camera.inverse(new Point2D(width, height));
gc.setStroke(Color.grayRgb(backgroundScope.getGridBrightness()));
- gc.setLineWidth(backgroundScope.getGridWidth());
+ gc.setLineWidth(backgroundScope.getGridWidth()/ camera.getZoom());
//vertical lines
int iMin = (int) ((start.getX() - center.getX())/gap);
diff --git a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/GraphDrawLayer.java b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/GraphDrawLayer.java
index e20a2a4..153bd0a 100644
--- a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/GraphDrawLayer.java
+++ b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/GraphDrawLayer.java
@@ -39,13 +39,15 @@ public void draw(GraphicsContext gc) {
DisplayMode displayMode = graphScope.getDisplayMode();
double defaultEdgeWidth = graphScope.getEdgeWidth() * graphScope.getNodeSize();
double defaultNodeSize = graphScope.getNodeSize();
- boolean selecting = graphScope.getGraphManager().getSelectedNodes().size() > 0 || inputScope.isSelecting();
+ boolean selecting = (inputScope.isSelecting() && graph.getNodes().stream().anyMatch(Node::isSelected)) ||
+ !graphScope.getGraphManager().getSelectedNodes().isEmpty();
if(graphScope.areEdgesVisibile()){
graph.getEdges().stream().filter(e -> !isEdgePrimary(e) && e.isVisible()).forEach(e ->
drawEdge(e, gc, defaultEdgeWidth, displayMode, selecting));
graph.getEdges().stream().filter(this::isEdgePrimary).forEach(e ->
drawEdge(e, gc, defaultEdgeWidth, displayMode, selecting));
}
+
graph.getNodes().forEach(n ->
drawNode(n, gc, defaultNodeSize, displayMode, selecting));
}
@@ -59,24 +61,25 @@ public int getOrder() {
return 3;
}
- private void drawNode(Node node, GraphicsContext gc, double defaultSize ,DisplayMode displayMode, boolean selecting){
+ private void drawNode(Node node, GraphicsContext gc, double defaultSize , DisplayMode displayMode, boolean selecting){
double size = getNodeSize(node, defaultSize, displayMode);
+ Point2D pos = graphScope.getNodePositionFunction().apply(node);
Color color = node.getColor() != null
? getNodeDisplayColor(node.getColor(), node, displayMode, selecting)
: getNodeDisplayColor(graphScope.getNodeColor(), node, displayMode, selecting);
gc.setFill(color);
+
if(graphScope.showingNodeBorder()){
-
double width = graphScope.getEdgeWidth() * graphScope.getNodeSize();
- gc.fillOval(node.getPos().getX() - (size-width)/2,
- node.getPos().getY() - (size-width)/2,
+ gc.fillOval(pos.getX() - (size-width)/2,
+ pos.getY() - (size-width)/2,
size-width,
size-width
);
}else{
- gc.fillOval(node.getPos().getX() - size/2, node.getPos().getY() - size/2, size, size);
+ gc.fillOval(pos.getX() - size/2, pos.getY() - size/2, size, size);
}
if(graphScope.showingNodeBorder()) {
@@ -84,8 +87,8 @@ private void drawNode(Node node, GraphicsContext gc, double defaultSize ,Display
gc.setLineWidth(width);
gc.setStroke(getNodeDisplayColor(graphScope.getEdgeColor(), node, displayMode, selecting));
gc.strokeOval(
- node.getPos().getX() - (size-width)/2,
- node.getPos().getY() - (size-width)/2,
+ pos.getX() - (size-width)/2,
+ pos.getY() - (size-width)/2,
size - width,
size - width
);
@@ -114,33 +117,32 @@ else if(graphScope.getNodeLabelMode() == NodeLabelMode.CUSTOM){
}
private void drawEdge(Edge edge, GraphicsContext gc, double defaultWidth, DisplayMode displayMode, boolean selecting){
- Point2D p1 = edge.getN1().getPos();
- Point2D p2 = edge.getN2().getPos();
+ Point2D p1 = graphScope.getNodePositionFunction().apply(edge.getN1());
+ Point2D p2 = graphScope.getNodePositionFunction().apply(edge.getN2());
double width = getEdgeWidth(edge, defaultWidth, displayMode);
+ if(width == 0)
+ return;
- //makes line shorter when it is wider
- Point2D correctionVector = p1.subtract(p2).normalize().multiply(width/2);
-
+ // ant colony algorithm cycle marker
if(edge.isMarked() && displayMode == DisplayMode.ANT_COLONY) {
gc.setLineWidth(width + graphScope.getNodeSize() * 0.25);
gc.setStroke(antsScope.getCycleColor());
- gc.strokeLine(p1.getX() - correctionVector.getX(),
- p1.getY() - correctionVector.getY(),
- p2.getX() + correctionVector.getX(),
- p2.getY() + correctionVector.getY());
+ gc.strokeLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
+
if(displayMode == DisplayMode.ANT_COLONY && !antsScope.isShowingPheromones()) return;
gc.setLineWidth(width);
- gc.setStroke(getEdgeDisplayColor(edge, displayMode, selecting));
+ Color edgeColor = getEdgeDisplayColor(edge, displayMode, selecting);
- gc.strokeLine(p1.getX() - correctionVector.getX(),
- p1.getY() - correctionVector.getY(),
- p2.getX() + correctionVector.getX(),
- p2.getY() + correctionVector.getY());
+ if(edgeColor.equals(backgroundScope.getBackgroundColor())){
+ return;
+ }
+ gc.setStroke(edgeColor);
+ gc.strokeLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
if(graphScope.getEdgeWeightMode() != EdgeWeightMode.NONE){
if(graphScope.getEdgeWeightMode() == EdgeWeightMode.LENGTH){
@@ -193,7 +195,7 @@ private Color getNodeDisplayColor(Color color, Node node, DisplayMode displayMod
return displayColor;
}
- private double getNodeSize(Node node, double defaultSize ,DisplayMode displayMode) {
+ private double getNodeSize(Node node, double defaultSize, DisplayMode displayMode) {
if(node.isHighlighted()) {
defaultSize = defaultSize * 1.05;
@@ -212,7 +214,7 @@ private double getNodeSize(Node node, double defaultSize ,DisplayMode displayMod
break;
default: defaultSize = 0;
}
- return defaultSize;
+ return defaultSize * graphScope.getNodeScaleFunction().apply(node);
}
private Color getEdgeDisplayColor(Edge edge, DisplayMode displayMode, boolean selecting) {
@@ -238,6 +240,16 @@ else if(edge.isHighlighted() || edge.isSelected() || edge.isMarked()){
break;
default: displayColor = Color.PINK;
}
+
+ if(graphScope.isEdgeOpacityDecayOn()){
+ double decay = getDecayedValue(edge, graphScope.getEdgeOpacityDecay(), graphScope.getNodeSize() * 2);
+ if(decay > 1){
+ decay = 1;
+ }
+ displayColor = displayColor.deriveColor(0,1,1, decay);
+ }
+
+ //return Util.getFaintColor(displayColor, backgroundScope.getBackgroundColor(), decay);
return displayColor;
}
@@ -266,6 +278,21 @@ private double getEdgeWidth(Edge edge, double defaultWidth, DisplayMode displayM
}
break;
}
+
+ if(graphScope.isEdgeWidthDecayOn()){
+ double decay = getDecayedValue(edge, graphScope.getEdgeWidthDecay(), 2*graphScope.getNodeSize());
+ defaultWidth *= decay;
+ }
+
return Math.min(defaultWidth, graphScope.getNodeSize());
}
+
+ private double getDecayedValue(Edge edge, double decay, double maximum){
+ Point2D p1 = graphScope.getNodePositionFunction().apply(edge.getN1());
+ Point2D p2 = graphScope.getNodePositionFunction().apply(edge.getN2());
+ double exponent = decay*(p1.distance(p2)-maximum);
+ return 2 - 2 * (Math.pow(Math.E, exponent)/(1+Math.pow(Math.E, exponent)));
+ }
+
+
}
diff --git a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/LowerDrawLayer.java b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/LowerDrawLayer.java
index b709104..aedd57b 100644
--- a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/LowerDrawLayer.java
+++ b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/LowerDrawLayer.java
@@ -31,7 +31,6 @@ private void drawDummyEdge(GraphicsContext gc, Color dummyColor){
gc.setFill(dummyColor);
gc.setLineWidth(graphScope.getEdgeWidth() * graphScope.getNodeSize());
-
double circleSize = graphScope.getNodeSize() * 0.5;
Point2D endPoint = inputScope.getDummyEdgeEnd();
for(Node node : inputScope.getDummyEdgeStartNodes()){
diff --git a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/UpperDrawLayer.java b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/UpperDrawLayer.java
index 4b83e85..6ed893d 100644
--- a/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/UpperDrawLayer.java
+++ b/src/main/java/com/todense/viewmodel/canvas/drawlayer/layers/UpperDrawLayer.java
@@ -1,6 +1,7 @@
package com.todense.viewmodel.canvas.drawlayer.layers;
import com.todense.model.graph.Node;
+import com.todense.viewmodel.algorithm.WalkingAgent;
import com.todense.viewmodel.canvas.DisplayMode;
import com.todense.viewmodel.canvas.drawlayer.DrawLayer;
import com.todense.viewmodel.scope.*;
@@ -17,17 +18,20 @@ public class UpperDrawLayer implements DrawLayer {
private CanvasScope canvasScope;
private BackgroundScope backgroundScope;
private AlgorithmScope algorithmScope;
+ private AntsScope antsScope;
public UpperDrawLayer(GraphScope graphScope,
InputScope inputScope,
CanvasScope canvasScope,
BackgroundScope backgroundScope,
- AlgorithmScope algorithmScope){
+ AlgorithmScope algorithmScope,
+ AntsScope antsScope){
this.graphScope = graphScope;
this.inputScope = inputScope;
this.canvasScope = canvasScope;
this.backgroundScope = backgroundScope;
this.algorithmScope = algorithmScope;
+ this.antsScope = antsScope;
}
@@ -68,6 +72,8 @@ public void draw(GraphicsContext gc) {
}
/*
+ // quad tree debugger
+
Graph graph = graphScope.getGraphManager().getGraph();
if(graph.getNodes().size() < 2) return;
@@ -110,6 +116,21 @@ public void draw(GraphicsContext gc) {
*/
}
+ if(graphScope.getDisplayMode() == DisplayMode.ANT_COLONY){
+ if (antsScope.isAntsAnimationOn()) {
+ gc.setFill(antsScope.getAntColor());
+ double size = antsScope.getAntSize() * graphScope.getNodeSize();
+ for(WalkingAgent agent: algorithmScope.getWalkingAgents()) {
+ gc.fillOval(
+ agent.getX() - size,
+ agent.getY() - size,
+ 2 * size,
+ 2 * size
+ );
+ }
+ }
+ }
+
gc.setTransform(new Affine());
//select rectangle
@@ -142,7 +163,7 @@ private void drawSelectRect(GraphicsContext gc){
Color rectColor = backgroundScope.getBackgroundColor()
.invert()
.grayscale()
- .deriveColor(0,1,1,0.4);
+ .deriveColor(0,1,1,0.2);
Rectangle2D rect = inputScope.getSelectRect();
gc.setFill(rectColor);
diff --git a/src/main/java/com/todense/viewmodel/file/format/ogr/OgrReader.java b/src/main/java/com/todense/viewmodel/file/format/ogr/OgrReader.java
index 7067e9a..fc55dd7 100644
--- a/src/main/java/com/todense/viewmodel/file/format/ogr/OgrReader.java
+++ b/src/main/java/com/todense/viewmodel/file/format/ogr/OgrReader.java
@@ -33,6 +33,7 @@ public Graph readGraph(File file) {
int edgeCount = Integer.parseInt(edgeCountLine[1]);
Graph graph = new Graph(name);
+
for (int i = 0; i < nodeCount; i++) {
scanner.nextInt();
Point2D pos = new Point2D(Double.parseDouble(scanner.next()), Double.parseDouble(scanner.next()));
diff --git a/src/main/java/com/todense/viewmodel/graph/GraphManager.java b/src/main/java/com/todense/viewmodel/graph/GraphManager.java
index ac3b133..4a7714e 100644
--- a/src/main/java/com/todense/viewmodel/graph/GraphManager.java
+++ b/src/main/java/com/todense/viewmodel/graph/GraphManager.java
@@ -36,43 +36,45 @@ public void resetGraph() {
selectedNodes = new ArrayList<>();
}
- public void createPath(){
- for(int i = 0; i < graph.getNodes().size()-1; i++) {
- Node n1 = graph.getNodes().get(i);
- Node n2 = graph.getNodes().get(i+1);
+ public void createPath(List nodes){
+ for(int i = 0; i < nodes.size()-1; i++) {
+ Node n1 = nodes.get(i);
+ Node n2 = nodes.get(i+1);
if(!isEdgeBetween(n1,n2)) {
graph.addEdge(n1, n2);
}
}
}
+ public void createPath(){
+ this.createPath(this.graph.getNodes());
+ }
+
+ public void createCompleteGraph(List nodes){
+ graph.applyToAllPairOfNodes(nodes, (n, m) -> {
+ if(!isEdgeBetween(n, m))
+ graph.addEdge(n, m);
+ });
+ }
+
public void createCompleteGraph(){
- for(int i = 0; i < graph.getNodes().size()-1; i++) {
- for(int j = i + 1; j < graph.getNodes().size(); j++) {
- Node n1 = graph.getNodes().get(i);
- Node n2 = graph.getNodes().get(j);
- if(!isEdgeBetween(n1,n2)) {
- graph.addEdge(n1, n2);
- }
- }
- }
+ this.createCompleteGraph(this.graph.getNodes());
+ }
+
+ public void createComplementGraph(List nodes) {
+ graph.applyToAllPairOfNodes(nodes, (n, m) -> {
+ if(!isEdgeBetween(n, m))
+ graph.addEdge(n, m);
+ else
+ graph.removeEdge(n, m);
+ });
}
public void createComplementGraph() {
- for(int i = 0; i < graph.getNodes().size(); i++){
- Node n = graph.getNodes().get(i);
- for (int j = i+1; j < graph.getNodes().size(); j++) {
- Node m = graph.getNodes().get(j);
- if(!isEdgeBetween(n, m)){
- graph.addEdge(n, m);
- }
- else{
- graph.removeEdge(n, m);
- }
- }
- }
+ this.createComplementGraph(this.graph.getNodes());
}
+
public void subdivideEdge(Edge e){
graph.removeEdge(e);
Node n = e.getN1();
@@ -83,18 +85,20 @@ public void subdivideEdge(Edge e){
graph.addEdge(m, k);
}
- public void subdivideEdges() {
- List edgesCopy = new ArrayList<>(graph.getEdges());
- graph.removeAllEdges();
-
- for (Edge edge : edgesCopy) {
- Node n = edge.getN1();
- Node m = edge.getN2();
+ public void subdivideEdges(List nodes) {
+ ArrayList nodesCopy = new ArrayList<>(nodes);
+ graph.applyToAllConnectedPairOfNodes(nodesCopy, (n, m) -> {
+ Edge e = graph.getEdge(n, m);
Point2D midpoint = n.getPos().midpoint(m.getPos());
Node k = graph.addNode(midpoint);
+ graph.removeEdge(n, m);
graph.addEdge(n, k);
graph.addEdge(m, k);
- }
+ });
+ }
+
+ public void subdivideEdges() {
+ this.subdivideEdges(this.graph.getNodes());
}
public void contractEdge(Edge e) {
@@ -123,7 +127,7 @@ public void addSubgraph(Point2D center){
}
}
- public Graph getSubgraphFromSelectedNodes(){
+ public Graph getSelectedSubgraph(){
Graph subGraph = new Graph();
for (Node n : selectedNodes) {
subGraph.addNode(n.getPos(), n.getColor());
@@ -139,11 +143,15 @@ public Graph getSubgraphFromSelectedNodes(){
}
public void copySelectedSubgraph(){
- clipboardGraph = getSubgraphFromSelectedNodes();
+ clipboardGraph = getSelectedSubgraph();
+ }
+
+ public void deleteEdges(List nodes) {
+ graph.removeEdges(nodes);
}
- public void deleteEdges() {
- graph.removeAllEdges();
+ public void deleteEdges(){
+ this.deleteEdges(this.graph.getNodes());
}
public boolean isEdgeBetween(Node n1, Node n2) {
@@ -154,6 +162,13 @@ public void updateNodePosition(Node n, Point2D d){
n.setPos(n.getPos().add(d));
}
+ public void rotateNode(Node n, Point2D pivot, double angle){
+ Point2D u = n.getPos().subtract(pivot);
+ double x = u.getX() * Math.cos(angle) - u.getY() * Math.sin(angle);
+ double y = u.getX() * Math.sin(angle) + u.getY() * Math.cos(angle);
+ n.setPos(new Point2D(x, y).add(pivot));
+ }
+
private List selectedNodes = new ArrayList<>();
public List getSelectedNodes() {
diff --git a/src/main/java/com/todense/viewmodel/layout/GraphCoarsener.java b/src/main/java/com/todense/viewmodel/layout/GraphCoarsener.java
index 7900e61..ba8c670 100644
--- a/src/main/java/com/todense/viewmodel/layout/GraphCoarsener.java
+++ b/src/main/java/com/todense/viewmodel/layout/GraphCoarsener.java
@@ -13,6 +13,7 @@
public class GraphCoarsener {
+ private Graph originalGraph;
private GraphManager graphManager;
private Stack graphSequence = new Stack<>();
private Stack> nodeMaps = new Stack<>();
@@ -22,6 +23,7 @@ public class GraphCoarsener {
public GraphCoarsener(GraphManager graphManager){
this.graphManager = graphManager;
+ this.originalGraph = graphManager.getGraph().copy();
}
public void reconstruct(double variation) {
@@ -105,4 +107,8 @@ public Stack getGraphSequence() {
public boolean maxLevelReached() {
return (graphSequence.peek().getEdges().size() <= 1 || reductionRate > 0.75);
}
+
+ public Graph getOriginalGraph() {
+ return originalGraph;
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/popover/PopOverManager.java b/src/main/java/com/todense/viewmodel/popover/PopOverManager.java
index eeeb5a5..f188463 100644
--- a/src/main/java/com/todense/viewmodel/popover/PopOverManager.java
+++ b/src/main/java/com/todense/viewmodel/popover/PopOverManager.java
@@ -23,12 +23,12 @@ public class PopOverManager {
private javafx.scene.Node owner;
private Context context;
- public PopOver createNodePopOver(GraphManager graphManager, List nodes, double x, double y){
+ public PopOver createNodePopOver(GraphManager graphManager, Node clickedNode, List nodes, double x, double y){
final ViewTuple viewTuple =
FluentViewLoader.fxmlView(NodePopOverView.class).context(context).load();
PopOver popOver = new PopOver(viewTuple.getView());
- viewTuple.getViewModel().bindToNodes(nodes);
+ viewTuple.getViewModel().bindToNodes(clickedNode, nodes);
popOver.animatedProperty().set(false);
popOver.detachableProperty().set(false);
popOver.show(owner, x, y);
diff --git a/src/main/java/com/todense/viewmodel/scope/AlgorithmScope.java b/src/main/java/com/todense/viewmodel/scope/AlgorithmScope.java
index 3a44215..a18e395 100644
--- a/src/main/java/com/todense/viewmodel/scope/AlgorithmScope.java
+++ b/src/main/java/com/todense/viewmodel/scope/AlgorithmScope.java
@@ -2,12 +2,16 @@
import com.todense.model.graph.Node;
import com.todense.viewmodel.algorithm.Algorithm;
+import com.todense.viewmodel.algorithm.WalkingAgent;
import de.saxsys.mvvmfx.Scope;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
+import java.util.ArrayList;
+import java.util.List;
+
public class AlgorithmScope implements Scope {
private ObjectProperty startNodeProperty = new SimpleObjectProperty<>();
@@ -15,6 +19,8 @@ public class AlgorithmScope implements Scope {
private ObjectProperty algorithmProperty = new SimpleObjectProperty<>();
private BooleanProperty showingEndpointsProperty = new SimpleBooleanProperty(true);
+ private List extends WalkingAgent> walkingAgents = new ArrayList<>();
+
public ObjectProperty startNodeProperty() {
return startNodeProperty;
}
@@ -54,4 +60,12 @@ public boolean isShowingEndpoints() {
public BooleanProperty showingEndpointsProperty() {
return showingEndpointsProperty;
}
+
+ public List extends WalkingAgent> getWalkingAgents() {
+ return walkingAgents;
+ }
+
+ public void setWalkingAgents(List extends WalkingAgent> walkingAgents) {
+ this.walkingAgents = walkingAgents;
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/scope/AntsScope.java b/src/main/java/com/todense/viewmodel/scope/AntsScope.java
index 4ed3584..536dd0b 100644
--- a/src/main/java/com/todense/viewmodel/scope/AntsScope.java
+++ b/src/main/java/com/todense/viewmodel/scope/AntsScope.java
@@ -8,12 +8,13 @@
import javafx.scene.paint.Color;
import java.util.ArrayList;
+import java.util.List;
public class AntsScope implements Scope {
- private ArrayList ants = new ArrayList<>();
+ private List ants = new ArrayList<>();
- ArrayList gbCycle = new ArrayList<>();
+ ArrayList gbCycle = new ArrayList<>(); //globally best cycle
private double[][] pheromones;
@@ -57,7 +58,7 @@ public double getPheromone(int i, int j){
return pheromones[i][j];
}
- public ArrayList getAnts() {
+ public List getAnts() {
return ants;
}
diff --git a/src/main/java/com/todense/viewmodel/scope/CanvasScope.java b/src/main/java/com/todense/viewmodel/scope/CanvasScope.java
index f564304..d1cabe0 100644
--- a/src/main/java/com/todense/viewmodel/scope/CanvasScope.java
+++ b/src/main/java/com/todense/viewmodel/scope/CanvasScope.java
@@ -7,6 +7,7 @@
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
+import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
public class CanvasScope implements Scope {
@@ -54,4 +55,9 @@ public Color getBorderColor() {
public ObjectProperty borderColorProperty() {
return borderColorProperty;
}
+
+ public Point2D getCanvasCenter(){
+ return new Point2D(canvasWidthProperty.get()/2, canvasHeightProperty.get()/2);
+ }
+
}
diff --git a/src/main/java/com/todense/viewmodel/scope/GraphScope.java b/src/main/java/com/todense/viewmodel/scope/GraphScope.java
index cab2acd..abf9a37 100644
--- a/src/main/java/com/todense/viewmodel/scope/GraphScope.java
+++ b/src/main/java/com/todense/viewmodel/scope/GraphScope.java
@@ -2,21 +2,30 @@
import com.todense.model.EdgeWeightMode;
import com.todense.model.NodeLabelMode;
+import com.todense.model.graph.Node;
import com.todense.viewmodel.canvas.DisplayMode;
import com.todense.viewmodel.graph.GraphManager;
import de.saxsys.mvvmfx.Scope;
import javafx.beans.property.*;
+import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
+import java.util.function.Function;
+
public class GraphScope implements Scope {
private final Color INITIAL_NODE_COLOR = Color.rgb(50,90,170);
private final Color INITIAL_EDGE_COLOR = Color.rgb(120,160,200);
+ public static Function NODE_ORDINARY_POSITION_FUNCTION = Node::getPos;
private DoubleProperty nodeSizeProperty = new SimpleDoubleProperty(30d);
private DoubleProperty edgeWidthProperty = new SimpleDoubleProperty(0.15);
+ private DoubleProperty edgeWidthDecayProperty = new SimpleDoubleProperty(0.06);
+ private DoubleProperty edgeOpacityDecayProperty = new SimpleDoubleProperty(0.06);
private BooleanProperty nodeBorderProperty = new SimpleBooleanProperty(false);
private BooleanProperty edgeVisibilityProperty = new SimpleBooleanProperty(true);
+ private BooleanProperty edgeWidthDecayOnProperty = new SimpleBooleanProperty(false);
+ private BooleanProperty edgeOpacityDecayOnProperty = new SimpleBooleanProperty(false);
private ObjectProperty nodeColorProperty = new SimpleObjectProperty<>(INITIAL_NODE_COLOR);
private ObjectProperty edgeColorProperty = new SimpleObjectProperty<>(INITIAL_EDGE_COLOR);
private ObjectProperty nodeLabelColorProperty = new SimpleObjectProperty<>(Color.WHITE);
@@ -25,6 +34,9 @@ public class GraphScope implements Scope {
private ObjectProperty edgeWeightModeProperty = new SimpleObjectProperty<>(EdgeWeightMode.NONE);
private ObjectProperty displayModeProperty = new SimpleObjectProperty<>(DisplayMode.DEFAULT);
+ private Function nodeScaleFunction = node -> 1.0;
+ private Function nodeCustomPositionFunction = Node::getPos;
+
private GraphManager graphManager = new GraphManager();
public double getNodeSize() {
@@ -118,4 +130,52 @@ public boolean areEdgesVisibile() {
public BooleanProperty edgeVisibilityProperty() {
return edgeVisibilityProperty;
}
+
+ public Function getNodeScaleFunction() {
+ return nodeScaleFunction;
+ }
+
+ public void setNodeScaleFunction(Function nodeScaleFunction) {
+ this.nodeScaleFunction = nodeScaleFunction;
+ }
+
+ public Function getNodePositionFunction() {
+ return nodeCustomPositionFunction;
+ }
+
+ public void setNodePositionFunction(Function nodeCustomPositionFunction) {
+ this.nodeCustomPositionFunction = nodeCustomPositionFunction;
+ }
+
+ public DoubleProperty edgeWidthDecayProperty() {
+ return edgeWidthDecayProperty;
+ }
+
+ public double getEdgeWidthDecay(){
+ return edgeWidthDecayProperty.get();
+ }
+
+ public boolean isEdgeWidthDecayOn() {
+ return edgeWidthDecayOnProperty.get();
+ }
+
+ public BooleanProperty edgeWidthDecayOnProperty() {
+ return edgeWidthDecayOnProperty;
+ }
+
+ public double getEdgeOpacityDecay() {
+ return edgeOpacityDecayProperty.get();
+ }
+
+ public DoubleProperty edgeOpacityDecayProperty() {
+ return edgeOpacityDecayProperty;
+ }
+
+ public boolean isEdgeOpacityDecayOn() {
+ return edgeOpacityDecayOnProperty.get();
+ }
+
+ public BooleanProperty edgeOpacityDecayOnProperty() {
+ return edgeOpacityDecayOnProperty;
+ }
}
diff --git a/src/main/java/com/todense/viewmodel/scope/TaskScope.java b/src/main/java/com/todense/viewmodel/scope/TaskScope.java
index 4eb5b01..48e85d0 100644
--- a/src/main/java/com/todense/viewmodel/scope/TaskScope.java
+++ b/src/main/java/com/todense/viewmodel/scope/TaskScope.java
@@ -3,28 +3,28 @@
import com.todense.viewmodel.algorithm.AlgorithmTask;
import de.saxsys.mvvmfx.Scope;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
public class TaskScope implements Scope {
+ private ExecutorService executor = Executors.newSingleThreadExecutor();
+ private Future> future;
private AlgorithmTask task;
- private Thread thread;
-
- public AlgorithmTask getTask() {
- return task;
- }
-
- public void setTask(AlgorithmTask task) {
- if(task != null && task.isRunning()){
- task.cancel();
+ public boolean start(AlgorithmTask task){
+ if(isDone()){
+ this.executor = Executors.newSingleThreadExecutor();
+ this.future = executor.submit(task);
+ this.task = task;
+ return true;
}
- this.task = task;
+ return false;
}
- public void setThread(Thread thread){
- if(this.thread != null && this.thread.isAlive()){
- this.thread.interrupt();
- }
- this.thread = thread;
+ public boolean isDone(){
+ return this.future == null || this.future.isCancelled() || this.future.isDone();
}
public void stopTask(){
@@ -33,16 +33,9 @@ public void stopTask(){
}
}
- public void stopThread(){
- if(thread != null && thread.isAlive()){
- thread.interrupt();
- System.out.println(thread.getState());
- }
+ public AlgorithmTask getTask() {
+ return task;
}
- public void stop(){
- stopTask();
- stopThread();
- }
}
diff --git a/src/main/resources/application.css b/src/main/resources/application.css
index 910c4f8..df775fe 100644
--- a/src/main/resources/application.css
+++ b/src/main/resources/application.css
@@ -182,6 +182,10 @@
-fx-pref-height:3;
}
+.slider .axis {
+ -fx-tick-label-fill: fx-text-dark;
+}
+
.slider .fill {
-fx-padding: 0.083333em; /* 1 */
}
diff --git a/src/main/resources/com/todense/view/BackgroundView.fxml b/src/main/resources/com/todense/view/BackgroundView.fxml
index 4077740..b86e2f1 100644
--- a/src/main/resources/com/todense/view/BackgroundView.fxml
+++ b/src/main/resources/com/todense/view/BackgroundView.fxml
@@ -36,7 +36,7 @@
-
+
-
+
-
-
+
+
diff --git a/src/main/resources/com/todense/view/NodePopOverView.fxml b/src/main/resources/com/todense/view/NodePopOverView.fxml
index 922e725..3370589 100644
--- a/src/main/resources/com/todense/view/NodePopOverView.fxml
+++ b/src/main/resources/com/todense/view/NodePopOverView.fxml
@@ -4,12 +4,13 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/todense/view/OperationsView.fxml b/src/main/resources/com/todense/view/OperationsView.fxml
index 6281dce..91294b9 100644
--- a/src/main/resources/com/todense/view/OperationsView.fxml
+++ b/src/main/resources/com/todense/view/OperationsView.fxml
@@ -6,12 +6,13 @@
+
-
+
-
+
@@ -19,6 +20,11 @@
+
+
+
+
+
diff --git a/src/main/resources/com/todense/view/PropertiesView.fxml b/src/main/resources/com/todense/view/PropertiesView.fxml
index a70e8e0..b7e87d2 100644
--- a/src/main/resources/com/todense/view/PropertiesView.fxml
+++ b/src/main/resources/com/todense/view/PropertiesView.fxml
@@ -171,14 +171,6 @@
-
diff --git a/src/main/resources/com/todense/view/RandomGeneratorView.fxml b/src/main/resources/com/todense/view/RandomGeneratorView.fxml
index d681e9a..884d2cd 100644
--- a/src/main/resources/com/todense/view/RandomGeneratorView.fxml
+++ b/src/main/resources/com/todense/view/RandomGeneratorView.fxml
@@ -11,7 +11,7 @@
-
+
@@ -20,7 +20,7 @@
-
+
@@ -44,6 +44,9 @@
+
+
+
diff --git a/src/main/resources/manual.txt b/src/main/resources/manual.txt
index bcbcdb4..70aea40 100644
--- a/src/main/resources/manual.txt
+++ b/src/main/resources/manual.txt
@@ -2,15 +2,17 @@ OmniGraph
1. Basic mouse controls
-- Zoom in\out: mouse scroll
- Add node: left click on background
- Add edge: right click on first node and drag mouse to second node
-- Remove node/edge: middle click on node/edge or open context menu -> delete
+- Remove node/edge: middle click on node/edge or right click on node -> delete
- Open node/edge context menu: right click on node/edge
-- Select nodes: right click on canvas and drag mouse to create selection area
+- Select nodes: right click on background and drag mouse to create selection area
- Select/deselect node/edge: CTRL + left click on node/edge
-- Drag one node or all selected nodes: left click on node and drag the mouse
-- Move camera: SHIFT + left mouse drag
+- Drag one node or all selected nodes: left click on node + drag mouse
+- Zoom in\out: mouse scroll
+- Move camera: left mouse click on background + drag mouse
+- Copy selected subgraph: CTRL+C+left mouse click one of selected nodes or right click on one of selected nodes -> copy subgraph
+- Paste copied graph: CTRL+V+left mouse click on background or right click on background -> paste subgraph
2. Keyboard shortcuts
@@ -18,6 +20,7 @@ OmniGraph
CTRL + DEL - delete graph
CTRL + Q - adjust camera to graph
CTRL + R - create random graph
+CTRL + E - create preset graph
CTRL + L - start graph layout
CTRL + P - create path
CTRL + K - add all edges
diff --git a/src/test/java/com/todense/model/graph/GraphTest.java b/src/test/java/com/todense/model/graph/GraphTest.java
index 18ea3e6..2204344 100644
--- a/src/test/java/com/todense/model/graph/GraphTest.java
+++ b/src/test/java/com/todense/model/graph/GraphTest.java
@@ -34,8 +34,6 @@ void test(){
graph.removeEdge(e2);
- assertThrows(AssertionError.class, () -> graph.removeEdge(e1.getN1(), e2.getN2()));
-
assertEquals(graph.getEdges().size(), 1);
graph.removeNode(n1);
diff --git a/src/test/java/com/todense/viewmodel/algorithm/AlgorithmTaskTest.java b/src/test/java/com/todense/viewmodel/algorithm/AlgorithmTaskTest.java
index 7d1e8e1..dd610aa 100644
--- a/src/test/java/com/todense/viewmodel/algorithm/AlgorithmTaskTest.java
+++ b/src/test/java/com/todense/viewmodel/algorithm/AlgorithmTaskTest.java
@@ -28,7 +28,7 @@ void hamiltonianCycleTest() {
graph.addEdge(n, m);
}
}
- HCSearchTask hcService = new HCSearchTask(graph.getNodes().get(0),graph, true);
+ HamiltonianCycleSearchTask hcService = new HamiltonianCycleSearchTask(graph.getNodes().get(0),graph, true);
assertDoesNotThrow(hcService::perform, () -> "HC Service should not throw exceptions");
assertTrue(hcService.isCycleFound(), () -> "Hamiltonian Cycle should be found");
}
diff --git a/src/test/java/com/todense/viewmodel/ants/AntColonyAlgoritmsTest.java b/src/test/java/com/todense/viewmodel/ants/AntColonyAlgoritmsTest.java
index 4d6732b..4666f9e 100644
--- a/src/test/java/com/todense/viewmodel/ants/AntColonyAlgoritmsTest.java
+++ b/src/test/java/com/todense/viewmodel/ants/AntColonyAlgoritmsTest.java
@@ -4,6 +4,7 @@
import com.todense.model.graph.Node;
import com.todense.viewmodel.file.format.tsp.TspReader;
import com.todense.viewmodel.graph.GraphManager;
+import com.todense.viewmodel.scope.AlgorithmScope;
import com.todense.viewmodel.scope.AntsScope;
import javafx.geometry.Point2D;
import org.junit.jupiter.api.Assertions;
@@ -33,6 +34,7 @@ void antTest(){
}
double trails = 1;
AntsScope antScope = new AntsScope();
+ AlgorithmScope algorithmScope = new AlgorithmScope();
antScope.betaProperty().setValue(8.2);
antScope.neighbourhoodSizeProperty().setValue(25);
antScope.antCountProperty().setValue(20);
@@ -50,7 +52,7 @@ void antTest(){
double explorSum = 0;
for (int j = 0; j < trails; j++) {
antScope.betaProperty().set(d);
- AntColonyAlgorithmTask antService = new AntSystemTask(graph, antScope);
+ AntColonyAlgorithmTask antService = new AntSystemTask(graph, antScope, algorithmScope);
antService.setMaxTimeSec(10);
antService.setMinSolution(6111);
antService.perform();
@@ -73,6 +75,7 @@ void antTest(){
@Test
void cycleLengthTest(){
AntsScope antsScope = new AntsScope();
+ AlgorithmScope algorithmScope = new AlgorithmScope();
GraphManager GM = new GraphManager();
Graph graph = GM.getGraph();
graph.addNode(new Point2D(0, 0));
@@ -84,10 +87,10 @@ void cycleLengthTest(){
antsScope.with2OptProperty().setValue(false);
List algorithms = new ArrayList<>(Arrays.asList(
- new AntSystemTask(graph, antsScope),
- new AntColonySystemTask(graph, antsScope),
- new MaxMinAntSystemTask(graph, antsScope),
- new RankedAntSystem(graph, antsScope)));
+ new AntSystemTask(graph, antsScope, algorithmScope),
+ new AntColonySystemTask(graph, antsScope, algorithmScope),
+ new MaxMinAntSystemTask(graph, antsScope, algorithmScope),
+ new RankedAntSystem(graph, antsScope, algorithmScope)));
for(var algorithm : algorithms){
algorithm.setMaxTimeSec(0.2);
|