From bc4fafb9d3c60993253f7e78c10338c901de653a Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Mon, 24 Mar 2014 17:16:51 +0000 Subject: Node grid all done and apparently stable. --- src/jcgp/CGP.java | 287 ------------------------ src/jcgp/GUI.java | 22 +- src/jcgp/JCGP.java | 287 ++++++++++++++++++++++++ src/jcgp/gui/SettingsPane.java | 6 +- src/jcgp/gui/population/ChromosomePane.java | 62 +++-- src/jcgp/gui/population/GUIGene.java | 18 ++ src/jcgp/gui/population/GUIInput.java | 116 +++++++--- src/jcgp/gui/population/GUINode.java | 230 +++++++++++-------- src/jcgp/gui/population/GUIOutput.java | 107 +++++---- src/jcgp/modules/Module.java | 2 +- src/jcgp/modules/ea/EvolutionaryAlgorithm.java | 2 +- src/jcgp/modules/ea/StandardEA.java | 2 +- src/jcgp/modules/fitness/FitnessFunction.java | 2 +- src/jcgp/modules/fitness/TestCaseEvaluator.java | 2 +- src/jcgp/modules/mutator/Mutator.java | 2 +- src/jcgp/modules/mutator/PointMutator.java | 2 +- src/jcgp/population/Chromosome.java | 2 +- src/jcgp/population/Population.java | 2 +- src/jcgp/tests/ChromosomeTests.java | 2 +- src/jcgp/tests/NodeTests.java | 2 +- src/jcgp/tests/OutputTests.java | 2 +- src/jcgp/tests/PopulationTests.java | 2 +- 22 files changed, 671 insertions(+), 490 deletions(-) delete mode 100644 src/jcgp/CGP.java create mode 100644 src/jcgp/JCGP.java diff --git a/src/jcgp/CGP.java b/src/jcgp/CGP.java deleted file mode 100644 index 32fb1f0..0000000 --- a/src/jcgp/CGP.java +++ /dev/null @@ -1,287 +0,0 @@ -package jcgp; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; - -import javafx.beans.property.Property; -import jcgp.function.Arithmetic; -import jcgp.function.BitwiseLogic; -import jcgp.function.BooleanLogic; -import jcgp.function.Function; -import jcgp.function.FunctionSet; -import jcgp.modules.ea.EvolutionaryAlgorithm; -import jcgp.modules.ea.StandardEA; -import jcgp.modules.fitness.FitnessFunction; -import jcgp.modules.fitness.TestCase; -import jcgp.modules.fitness.TestCaseEvaluator; -import jcgp.modules.mutator.Mutator; -import jcgp.modules.mutator.PointMutator; -import jcgp.parameters.BooleanParameter; -import jcgp.parameters.IntegerParameter; -import jcgp.parameters.Parameter; -import jcgp.population.Population; - -public class CGP { - - /** - * - * - * @author Eduardo Pedroni - * - */ - public static class Resources { - private HashMap moduleParameters = new HashMap(); - private HashMap coreParameters = new HashMap(); - private HashMap allParameters = new HashMap(); - - private Random numberGenerator; - - // function sets - private FunctionSet[] functionSets = new FunctionSet[] { - new Arithmetic(), - new BitwiseLogic(), - new BooleanLogic() }; - private FunctionSet functionSet = functionSets[0]; - - private TestCase[] testCases; - - public Resources() { - createCoreParameters(); - - numberGenerator = new Random((int) get("seed")); - functionSet = functionSets[0]; - - set("arity", functionSet.getMaxArity()); - } - - public Object get(String key) { - return allParameters.get(key).getValue(); - } - - public void set(String key, Object value) { - allParameters.get(key).setValue(value); - } - - public Property getProperty(String key) { - return allParameters.get(key).valueProperty(); - } - - public void setManagedParameter(String key, boolean value) { - allParameters.get(key).setManaged(value); - } - - public void setHiddenParameter(String key, boolean value) { - allParameters.get(key).setHidden(value); - } - - public boolean contains(String key) { - return allParameters.containsKey(key); - } - - private void createCoreParameters() { - coreParameters.put("rows", new IntegerParameter(9, "Rows")); - coreParameters.put("columns", new IntegerParameter(10, "Columns")); - coreParameters.put("inputs", new IntegerParameter(3, "Inputs")); - coreParameters.put("outputs", new IntegerParameter(3, "Outputs")); - coreParameters.put("popSize", new IntegerParameter(5, "Population")); - coreParameters.put("levelsBack", new IntegerParameter(2, "Levels back")); - - coreParameters.put("nodes", new IntegerParameter(90, "Nodes", true, true)); - - coreParameters.put("generations", new IntegerParameter(1000000, "Generations")); - coreParameters.put("currentGen", new IntegerParameter(0, "Generation")); - coreParameters.put("runs", new IntegerParameter(5, "Runs")); - - coreParameters.put("arity", new IntegerParameter(0, "Max arity", true, true)); - - coreParameters.put("seed", new IntegerParameter(123, "Random seed", true, true)); - - coreParameters.put("debug", new BooleanParameter(false, "Debug")); - - allParameters.putAll(coreParameters); - } - - private void resetParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { - Iterator> it = coreParameters.entrySet().iterator(); - while (it.hasNext()) { - ((Parameter) ((Map.Entry) it.next()).getValue()).reset(); - } - - allParameters.clear(); - allParameters.putAll(coreParameters); - addModuleParameters(ea, mu, ff); - } - - private void addModuleParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { - moduleParameters.clear(); - moduleParameters.putAll(ea.activate(this)); - moduleParameters.putAll(mu.activate(this)); - moduleParameters.putAll(ff.activate(this)); - - allParameters.putAll(moduleParameters); - } - - public Set> getEntries() { - return allParameters.entrySet(); - } - - /* - * Utility functions - */ - public int getRandomInt(int limit) { - return numberGenerator.nextInt(limit); - } - - public double getRandomDouble(int limit) { - return numberGenerator.nextDouble() * limit; - } - - public double getRandomDouble() { - return numberGenerator.nextDouble(); - } - - /* - * Function set functions - */ - public Function getRandomFunction() { - return functionSet.getFunction(numberGenerator.nextInt(functionSet.getFunctionCount())); - } - - public Function getFunction(int index) { - return functionSet.getFunction(index); - } - - public void setFunctionSet(int index) { - functionSet = functionSets[index]; - } - - /* - * Test cases - */ - public void setTestCases(TestCase ... testCases) { - this.testCases = testCases; - } - - public TestCase getTestCase(int index) { - return testCases[index]; - } - - public int getTestCaseCount() { - return testCases.length; - } - } - - private Resources resources = new Resources(); - - /* - * The following arrays contain all available modules. These collections are read by the GUI - * when generating menus, so modules not added here will *NOT* be selectable in the GUI. - * - * Each array is accompanied by a field which contains a reference to the currently selected - * module, 0 by default. - */ - // mutators - private Mutator[] mutators = new Mutator[] { - new PointMutator() }; - private Mutator mutator = mutators[0]; - - // evolutionary algorithms - private EvolutionaryAlgorithm[] evolutionaryAlgorithms = new EvolutionaryAlgorithm[] { - new StandardEA() }; - private EvolutionaryAlgorithm evolutionaryAlgorithm = evolutionaryAlgorithms[0]; - - // fitness evaluators - private FitnessFunction[] fitnessFunctions = new FitnessFunction[] { - new TestCaseEvaluator() }; - private FitnessFunction fitnessFunction = fitnessFunctions[0]; - - // the population of chromosomes - private Population population = new Population(resources); - - - public CGP() { - resources.addModuleParameters(evolutionaryAlgorithm, mutator, fitnessFunction); - - resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}), - new TestCase(new Integer[]{1, 12, 4}, new Integer[]{6, 21, 2})); - -// for (int i = 0; i < (int) resources.get("generations"); i++) { -// -// resources.set("currentGen", ((int) resources.get("currentGen")) + 1); -// -// fitnessFunction.evaluate(population, resources); -// evolutionaryAlgorithm.evolve(population, mutator, resources); -// -// System.out.println("fitness: " + evolutionaryAlgorithm.getFittestChromosome().getFitness()); -// -// if (evolutionaryAlgorithm.getFittestChromosome().getFitness() >= 6) { -// System.out.println("solution found"); -// evolutionaryAlgorithm.getFittestChromosome().printNodes(); -// break; -// } -// } - } - - - public Resources getResources() { - return resources; - } - - - public Population getPopulation() { - return population; - } - - - /** - * @return the mutators - */ - public Mutator[] getMutators() { - return mutators; - } - - - /** - * @return the mutator - */ - public Mutator getMutator() { - return mutator; - } - - - /** - * @return the evolutionaryAlgorithms - */ - public EvolutionaryAlgorithm[] getEvolutionaryAlgorithms() { - return evolutionaryAlgorithms; - } - - - /** - * @return the evolutionaryAlgorithm - */ - public EvolutionaryAlgorithm getEvolutionaryAlgorithm() { - return evolutionaryAlgorithm; - } - - - /** - * @return the fitnessFunctions - */ - public FitnessFunction[] getFitnessFunctions() { - return fitnessFunctions; - } - - - /** - * @return the fitnessFunction - */ - public FitnessFunction getFitnessFunction() { - return fitnessFunction; - } - -} diff --git a/src/jcgp/GUI.java b/src/jcgp/GUI.java index 284f9ae..669a4e2 100644 --- a/src/jcgp/GUI.java +++ b/src/jcgp/GUI.java @@ -8,26 +8,26 @@ import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TabPane.TabClosingPolicy; import javafx.scene.input.MouseDragEvent; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.gui.Console; import jcgp.gui.SettingsPane; import jcgp.gui.population.ChromosomePane; import jcgp.gui.population.GUIGene; -import jcgp.gui.population.GUINode; -import jcgp.gui.population.GUIOutput; public class GUI extends Application { public static final String NEUTRAL_COLOUR = "#FFFFFF"; - public static final String HARD_HIGHLIGHT_COLOUR = "#89AAD6"; + public static final String HARD_HIGHLIGHT_COLOUR = "#5496FF"; + public static final String MEDIUM_HIGHLIGHT_COLOUR = "#89AAD6"; public static final String SOFT_HIGHLIGHT_COLOUR = "#C7DFFF"; public static final String GOOD_SELECTION_COLOUR = "#BDFFC2"; public static final String NEUTRAL_SELECTION_COLOUR = "#FBFFB8"; public static final String BAD_SELECTION_COLOUR = "#FF9C9C"; - private static CGP cgp; + private static JCGP cgp; public static Resources resources; @@ -41,7 +41,7 @@ public class GUI extends Application { public static void main(String[] args) { - cgp = new CGP(); + cgp = new JCGP(); resources = cgp.getResources(); launch(); @@ -62,7 +62,7 @@ public class GUI extends Application { chromosomes = new ChromosomePane[(int) cgp.getResources().get("popSize")]; Tab tab; for (int i = 0; i < chromosomes.length; i++) { - chromosomes[i] = new ChromosomePane(cgp.getPopulation().getChromosome(i), cgp.getResources()); + chromosomes[i] = new ChromosomePane(cgp.getPopulation().getChromosome(i)); tab = new Tab("Chr " + i); tab.setContent(chromosomes[i]); mainPane.getTabs().add(tab); @@ -92,14 +92,12 @@ public class GUI extends Application { } event.consume(); ((GUIGene) event.getGestureSource()).resetState(); - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).updateLines(); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).updateLine(); - } + ((GUIGene) event.getGestureSource()).updateLines(); + } }); + primaryStage.setMinHeight(600); primaryStage.setMinWidth(800); diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java new file mode 100644 index 0000000..21161fa --- /dev/null +++ b/src/jcgp/JCGP.java @@ -0,0 +1,287 @@ +package jcgp; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; + +import javafx.beans.property.Property; +import jcgp.function.Arithmetic; +import jcgp.function.BitwiseLogic; +import jcgp.function.BooleanLogic; +import jcgp.function.Function; +import jcgp.function.FunctionSet; +import jcgp.modules.ea.EvolutionaryAlgorithm; +import jcgp.modules.ea.StandardEA; +import jcgp.modules.fitness.FitnessFunction; +import jcgp.modules.fitness.TestCase; +import jcgp.modules.fitness.TestCaseEvaluator; +import jcgp.modules.mutator.Mutator; +import jcgp.modules.mutator.PointMutator; +import jcgp.parameters.BooleanParameter; +import jcgp.parameters.IntegerParameter; +import jcgp.parameters.Parameter; +import jcgp.population.Population; + +public class JCGP { + + /** + * + * + * @author Eduardo Pedroni + * + */ + public static class Resources { + private HashMap moduleParameters = new HashMap(); + private HashMap coreParameters = new HashMap(); + private HashMap allParameters = new HashMap(); + + private Random numberGenerator; + + // function sets + private FunctionSet[] functionSets = new FunctionSet[] { + new Arithmetic(), + new BitwiseLogic(), + new BooleanLogic() }; + private FunctionSet functionSet = functionSets[0]; + + private TestCase[] testCases; + + public Resources() { + createCoreParameters(); + + numberGenerator = new Random((int) get("seed")); + functionSet = functionSets[0]; + + set("arity", functionSet.getMaxArity()); + } + + public Object get(String key) { + return allParameters.get(key).getValue(); + } + + public void set(String key, Object value) { + allParameters.get(key).setValue(value); + } + + public Property getProperty(String key) { + return allParameters.get(key).valueProperty(); + } + + public void setManagedParameter(String key, boolean value) { + allParameters.get(key).setManaged(value); + } + + public void setHiddenParameter(String key, boolean value) { + allParameters.get(key).setHidden(value); + } + + public boolean contains(String key) { + return allParameters.containsKey(key); + } + + private void createCoreParameters() { + coreParameters.put("rows", new IntegerParameter(9, "Rows")); + coreParameters.put("columns", new IntegerParameter(10, "Columns")); + coreParameters.put("inputs", new IntegerParameter(3, "Inputs")); + coreParameters.put("outputs", new IntegerParameter(3, "Outputs")); + coreParameters.put("popSize", new IntegerParameter(5, "Population")); + coreParameters.put("levelsBack", new IntegerParameter(2, "Levels back")); + + coreParameters.put("nodes", new IntegerParameter(90, "Nodes", true, true)); + + coreParameters.put("generations", new IntegerParameter(1000000, "Generations")); + coreParameters.put("currentGen", new IntegerParameter(0, "Generation")); + coreParameters.put("runs", new IntegerParameter(5, "Runs")); + + coreParameters.put("arity", new IntegerParameter(0, "Max arity", true, true)); + + coreParameters.put("seed", new IntegerParameter(123, "Random seed", true, true)); + + coreParameters.put("debug", new BooleanParameter(false, "Debug")); + + allParameters.putAll(coreParameters); + } + + private void resetParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { + Iterator> it = coreParameters.entrySet().iterator(); + while (it.hasNext()) { + ((Parameter) ((Map.Entry) it.next()).getValue()).reset(); + } + + allParameters.clear(); + allParameters.putAll(coreParameters); + addModuleParameters(ea, mu, ff); + } + + private void addModuleParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { + moduleParameters.clear(); + moduleParameters.putAll(ea.activate(this)); + moduleParameters.putAll(mu.activate(this)); + moduleParameters.putAll(ff.activate(this)); + + allParameters.putAll(moduleParameters); + } + + public Iterator> iterator() { + return allParameters.entrySet().iterator(); + } + + /* + * Utility functions + */ + public int getRandomInt(int limit) { + return numberGenerator.nextInt(limit); + } + + public double getRandomDouble(int limit) { + return numberGenerator.nextDouble() * limit; + } + + public double getRandomDouble() { + return numberGenerator.nextDouble(); + } + + /* + * Function set functions + */ + public Function getRandomFunction() { + return functionSet.getFunction(numberGenerator.nextInt(functionSet.getFunctionCount())); + } + + public Function getFunction(int index) { + return functionSet.getFunction(index); + } + + public void setFunctionSet(int index) { + functionSet = functionSets[index]; + } + + /* + * Test cases + */ + public void setTestCases(TestCase ... testCases) { + this.testCases = testCases; + } + + public TestCase getTestCase(int index) { + return testCases[index]; + } + + public int getTestCaseCount() { + return testCases.length; + } + } + + private Resources resources = new Resources(); + + /* + * The following arrays contain all available modules. These collections are read by the GUI + * when generating menus, so modules not added here will *NOT* be selectable in the GUI. + * + * Each array is accompanied by a field which contains a reference to the currently selected + * module, 0 by default. + */ + // mutators + private Mutator[] mutators = new Mutator[] { + new PointMutator() }; + private Mutator mutator = mutators[0]; + + // evolutionary algorithms + private EvolutionaryAlgorithm[] evolutionaryAlgorithms = new EvolutionaryAlgorithm[] { + new StandardEA() }; + private EvolutionaryAlgorithm evolutionaryAlgorithm = evolutionaryAlgorithms[0]; + + // fitness evaluators + private FitnessFunction[] fitnessFunctions = new FitnessFunction[] { + new TestCaseEvaluator() }; + private FitnessFunction fitnessFunction = fitnessFunctions[0]; + + // the population of chromosomes + private Population population = new Population(resources); + + + public JCGP() { + resources.addModuleParameters(evolutionaryAlgorithm, mutator, fitnessFunction); + + resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}), + new TestCase(new Integer[]{1, 12, 4}, new Integer[]{6, 21, 2})); + +// for (int i = 0; i < (int) resources.get("generations"); i++) { +// +// resources.set("currentGen", ((int) resources.get("currentGen")) + 1); +// +// fitnessFunction.evaluate(population, resources); +// evolutionaryAlgorithm.evolve(population, mutator, resources); +// +// System.out.println("fitness: " + evolutionaryAlgorithm.getFittestChromosome().getFitness()); +// +// if (evolutionaryAlgorithm.getFittestChromosome().getFitness() >= 6) { +// System.out.println("solution found"); +// evolutionaryAlgorithm.getFittestChromosome().printNodes(); +// break; +// } +// } + } + + + public Resources getResources() { + return resources; + } + + + public Population getPopulation() { + return population; + } + + + /** + * @return the mutators + */ + public Mutator[] getMutators() { + return mutators; + } + + + /** + * @return the mutator + */ + public Mutator getMutator() { + return mutator; + } + + + /** + * @return the evolutionaryAlgorithms + */ + public EvolutionaryAlgorithm[] getEvolutionaryAlgorithms() { + return evolutionaryAlgorithms; + } + + + /** + * @return the evolutionaryAlgorithm + */ + public EvolutionaryAlgorithm getEvolutionaryAlgorithm() { + return evolutionaryAlgorithm; + } + + + /** + * @return the fitnessFunctions + */ + public FitnessFunction[] getFitnessFunctions() { + return fitnessFunctions; + } + + + /** + * @return the fitnessFunction + */ + public FitnessFunction getFitnessFunction() { + return fitnessFunction; + } + +} diff --git a/src/jcgp/gui/SettingsPane.java b/src/jcgp/gui/SettingsPane.java index 06c35ec..f7e7767 100644 --- a/src/jcgp/gui/SettingsPane.java +++ b/src/jcgp/gui/SettingsPane.java @@ -6,21 +6,21 @@ import java.util.Map.Entry; import javafx.scene.layout.VBox; import javafx.scene.text.Text; -import jcgp.CGP; +import jcgp.JCGP; import jcgp.gui.settings.GUIIntegerParameter; import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; public class SettingsPane extends VBox { - public SettingsPane(CGP cgp) { + public SettingsPane(JCGP cgp) { super(); setPrefSize(180, 500); Text parameters = new Text("Parameters"); getChildren().add(parameters); - Iterator> it = cgp.getResources().getEntries().iterator(); + Iterator> it = cgp.getResources().iterator(); while (it.hasNext()) { Parameter p = (Parameter) ((Map.Entry) it.next()).getValue(); if (p instanceof IntegerParameter) { diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java index 546314e..0c7b3d2 100644 --- a/src/jcgp/gui/population/ChromosomePane.java +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -5,8 +5,11 @@ import java.util.ArrayList; import javafx.scene.control.ScrollPane; import javafx.scene.layout.Pane; import javafx.scene.shape.Line; -import jcgp.CGP.Resources; +import jcgp.GUI; import jcgp.population.Chromosome; +import jcgp.population.Connection; +import jcgp.population.Input; +import jcgp.population.Node; public class ChromosomePane extends ScrollPane { @@ -19,7 +22,9 @@ public class ChromosomePane extends ScrollPane { private ArrayList connectionLines; - public ChromosomePane(Chromosome chromosome, Resources resources) { + private boolean target = false; + + public ChromosomePane(Chromosome chromosome) { super(); connectionLines = new ArrayList(); @@ -28,19 +33,19 @@ public class ChromosomePane extends ScrollPane { // generate the GUIGenes // inputs - guiInputs = new GUIInput[(int) resources.get("inputs")]; + guiInputs = new GUIInput[(int) GUI.resources.get("inputs")]; for (int i = 0; i < guiInputs.length; i++) { // make the GUI elements guiInputs[i] = new GUIInput(this, chromosome.getInput(i)); content.getChildren().addAll(guiInputs[i]); } // nodes - guiNodes = new GUINode[(int) resources.get("rows")][(int) resources.get("columns")]; + guiNodes = new GUINode[(int) GUI.resources.get("rows")][(int) GUI.resources.get("columns")]; double angle, xPos, yPos; for (int r = 0; r < guiNodes.length; r++) { for (int c = 0; c < guiNodes[r].length; c++) { // make the connection lines - Line lines[] = new Line[(int) resources.get("arity")]; + Line lines[] = new Line[(int) GUI.resources.get("arity")]; for (int l = 0; l < lines.length; l++) { angle = ((((double) (l + 1)) / ((double) (lines.length + 1))) * GUIGene.THETA) - (GUIGene.THETA / 2); xPos = (-Math.cos(angle) * GUIGene.NODE_RADIUS) + (((c + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)) + GUIGene.NODE_RADIUS); @@ -52,15 +57,15 @@ public class ChromosomePane extends ScrollPane { connectionLines.add(lines[l]); } // make the GUI elements - guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), resources, lines); + guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), lines); } content.getChildren().addAll(guiNodes[r]); } // outputs - guiOutputs = new GUIOutput[(int) resources.get("outputs")]; + guiOutputs = new GUIOutput[(int) GUI.resources.get("outputs")]; for (int i = 0; i < guiOutputs.length; i++) { - xPos = (((int) resources.get("columns") + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)); + xPos = (((int) GUI.resources.get("columns") + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)); yPos = (chromosome.getOutput(i).getIndex() * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)) + GUIGene.NODE_RADIUS; // make the line Line line = new Line(xPos, yPos, xPos, yPos); @@ -68,7 +73,7 @@ public class ChromosomePane extends ScrollPane { line.setVisible(false); connectionLines.add(line); // make the GUI elements - guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), resources, line); + guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), line); content.getChildren().addAll(guiOutputs[i]); } @@ -78,20 +83,41 @@ public class ChromosomePane extends ScrollPane { } - public GUINode getGuiNode(int row, int column) { - return guiNodes[row][column]; - } - - public GUIInput getGuiInput(int index) { - return guiInputs[index]; - } +// public GUINode getGuiNode(int row, int column) { +// return guiNodes[row][column]; +// } +// +// public GUIInput getGuiInput(int index) { +// return guiInputs[index]; +// } +// +// public GUIOutput getGuiOutput(int index) { +// return guiOutputs[index]; +// } - public GUIOutput getGuiOutput(int index) { - return guiOutputs[index]; + public GUIGene getGuiGene(Connection gene) { + if (gene instanceof Input) { + return guiInputs[((Input) gene).getIndex()]; + } else if (gene instanceof Node) { + return guiNodes[((Node) gene).getRow()][((Node) gene).getColumn()]; + } else { + // something bad happened! + throw new ClassCastException(); + } + } public Pane getContentPane() { return content; } + + + public boolean isTarget() { + return target; + } + + public void setTarget(boolean newValue) { + target = newValue; + } } diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 830192c..1be662e 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -4,6 +4,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Group; import javafx.scene.shape.Circle; import javafx.scene.text.Text; +import jcgp.population.Connection; import jcgp.population.Gene; enum GUIGeneState { @@ -11,6 +12,7 @@ enum GUIGeneState { HOVER, INDIRECT_HOVER, ACTIVE_HOVER, + LOCKED_HOVER, SOURCE, TARGET, NO_CHANGE_TARGET, @@ -52,13 +54,29 @@ public abstract class GUIGene extends Group { return locked > 0; } + public int getLocks() { + return locked; + } + public abstract void setLocked(boolean value); + public abstract void addLocks(int value); + + public abstract void removeLocks(int value); + + public abstract void updateLines(); + public abstract Gene getGene(); + + public abstract void setChangingConnection(Connection newConnection); + + public abstract Connection getChangingConnection(); public abstract void setConnections(GUIGeneState newState); public abstract void resetState(); + public abstract void setConnectionLine(GUIGene gene); + } diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index bf872dc..ac1a775 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -12,8 +12,8 @@ import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import jcgp.GUI; +import jcgp.population.Connection; import jcgp.population.Input; -import jcgp.population.Node; import jcgp.population.Output; public class GUIInput extends GUIGene { @@ -54,13 +54,13 @@ public class GUIInput extends GUIGene { public void handle(MouseDragEvent event) { // the drag has entered this node, react appropriately // this happens even if we are the source of the drag + ((GUIGene) event.getGestureSource()).setConnectionLine((GUIGene) event.getSource()); + if (event.getGestureSource() instanceof GUINode) { - Node source = ((GUINode) event.getGestureSource()).getGene(); - for (int i = 0; i < (int) GUI.resources.get("arity"); i++) { - if (input == source.getConnection(i)) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); - return; - } + Connection source = ((GUINode) event.getGestureSource()).getChangingConnection(); + if (input == source) { + stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + return; } } else if (event.getGestureSource() instanceof GUIOutput) { Output source = ((GUIOutput) event.getGestureSource()).getGene(); @@ -77,28 +77,45 @@ public class GUIInput extends GUIGene { public void handle(MouseDragEvent event) { // the drag has exited this node, react appropriately // this happens even if we are the source of the drag - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); - } else { - stateProperty.set(GUIGeneState.NEUTRAL); + parent.setTarget(false); + if (event.isPrimaryButtonDown()) { + if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { + stateProperty.set(GUIGeneState.INDIRECT_HOVER); + } else { + stateProperty.set(GUIGeneState.NEUTRAL); + ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); + } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler() { @Override public void handle(MouseDragEvent event) { + GUIGene source = ((GUIGene) event.getGestureSource()); // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); - stateProperty.set(GUIGeneState.HOVER); + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + // the user released the drag gesture on this node, react appropriately - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).setChangingConnection(input); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).getGene().setConnection(0, input); - } + if (source.isLocked()) { + // remove locks from the old connection, add the to the new + // note that the old connection may still have locks after this + parent.getGuiGene(source.getChangingConnection()).removeLocks(source.getLocks()); + source.setChangingConnection(input); + addLocks(source.getLocks()); + } else { + source.setChangingConnection(input); + } + + source.updateLines(); + stateProperty.set(GUIGeneState.HOVER); } }); @@ -107,7 +124,7 @@ public class GUIInput extends GUIGene { public void handle(MouseEvent event) { // cursor has entered this node without dragging, or it is dragging and this is the source if (stateProperty.get() == GUIGeneState.NEUTRAL) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); + stateProperty.set(GUIGeneState.HOVER); } } }); @@ -116,7 +133,7 @@ public class GUIInput extends GUIGene { @Override public void handle(MouseEvent event) { // cursor has left this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.INDIRECT_HOVER) { + if (stateProperty.get() == GUIGeneState.HOVER) { stateProperty.set(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } @@ -129,27 +146,40 @@ public class GUIInput extends GUIGene { switch (newValue) { case ACTIVE_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + if (locked > 0) { + stateProperty().set(GUIGeneState.LOCKED_HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + } break; case FORBIDDEN_TARGET: mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); break; + case LOCKED_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); break; case INDIRECT_HOVER: mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); break; case NEUTRAL: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + if (locked > 0) { + stateProperty.set(GUIGeneState.HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + } break; case NO_CHANGE_TARGET: + parent.setTarget(true); mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); break; case SOURCE: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); break; case TARGET: + parent.setTarget(true); mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); break; default: @@ -179,11 +209,43 @@ public class GUIInput extends GUIGene { @Override public void resetState() { stateProperty.set(GUIGeneState.NEUTRAL); - } @Override public void setLocked(boolean value) { locked += value ? 1 : -1; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + } + + @Override + public void setChangingConnection(Connection newConnection) { + // do nothing + } + + @Override + public Connection getChangingConnection() { + return null; + } + + @Override + public void addLocks(int value) { + locked += value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + } + + @Override + public void updateLines() { + // nothing + } + + @Override + public void removeLocks(int value) { + locked -= value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + } + + @Override + public void setConnectionLine(GUIGene gene) { + // nothing } } diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index c5ab43a..dd20006 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -13,7 +13,6 @@ import javafx.scene.shape.Line; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; -import jcgp.CGP.Resources; import jcgp.GUI; import jcgp.function.Function; import jcgp.population.Connection; @@ -22,7 +21,7 @@ import jcgp.population.Node; import jcgp.population.Output; public class GUINode extends GUIGene { - + private Circle[] sockets; private Circle output; @@ -31,23 +30,23 @@ public class GUINode extends GUIGene { private Label connectionNumber; private Node node; - - private int connectionIndex; - - public GUINode(ChromosomePane parentRef, final Node node, Resources resources, Line[] connectionLines) { + + private int connectionIndex = 0; + + public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines) { // store references this.parent = parentRef; this.node = node; this.lines = connectionLines; - + // move the GUIGene to the right position relocate(((node.getColumn() + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, (node.getRow() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); // set the line ends correctly updateLines(); - + connectionNumber = new Label(); connectionNumber.setStyle("-fx-background-color:rgb(255, 255, 255); -fx-border-color:rgba(0, 0, 0, 0.5); "); connectionNumber.setVisible(false); @@ -73,20 +72,20 @@ public class GUINode extends GUIGene { text.setX(-NODE_RADIUS); text.setVisible(true); - sockets = new Circle[(int) resources.get("arity")]; + sockets = new Circle[(int) GUI.resources.get("arity")]; double angle, xPos, yPos; for (int l = 0; l < sockets.length; l++) { - angle = ((((double) (l + 1)) / ((double) ((int) resources.get("arity") + 1))) * THETA) - (THETA / 2); + angle = ((((double) (l + 1)) / ((double) ((int) GUI.resources.get("arity") + 1))) * THETA) - (THETA / 2); xPos = -Math.cos(angle) * NODE_RADIUS; yPos = Math.sin(angle) * NODE_RADIUS; sockets[l] = new Circle(xPos, yPos, GUIGene.SOCKET_RADIUS, Paint.valueOf("white")); sockets[l].setId(String.valueOf(l)); sockets[l].setStroke(Paint.valueOf("black")); - + final Circle s = sockets[l]; final int index = l; - + /* * Mouse event handlers on sockets * @@ -98,7 +97,7 @@ public class GUINode extends GUIGene { startFullDrag(); } }); - + s.addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler() { @Override public void handle(MouseEvent event) { @@ -108,7 +107,7 @@ public class GUINode extends GUIGene { connectionNumber.setVisible(true); } }); - + s.addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler() { @Override public void handle(MouseEvent event) { @@ -116,24 +115,26 @@ public class GUINode extends GUIGene { connectionNumber.setVisible(false); } }); - + s.addEventFilter(MouseDragEvent.MOUSE_PRESSED, new EventHandler() { @Override public void handle(MouseEvent event) { // mouse was pressed on the socket stateProperty.set(GUIGeneState.SOURCE); connectionIndex = index; - } + } }); - + s.addEventFilter(MouseDragEvent.MOUSE_DRAGGED, new EventHandler() { @Override public void handle(MouseEvent event) { - lines[connectionIndex].setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); - lines[connectionIndex].setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + if (!parent.isTarget()) { + lines[connectionIndex].setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); + lines[connectionIndex].setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + } } }); - + s.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler() { @Override public void handle(MouseEvent event) { @@ -142,10 +143,10 @@ public class GUINode extends GUIGene { updateLine(index); stateProperty.set(GUIGeneState.HOVER); } - } + } }); } - + /* * Mouse event handlers on whole gene */ @@ -155,13 +156,12 @@ public class GUINode extends GUIGene { // the drag has entered this node, react appropriately // this happens even if we are the source of the drag if (isAllowed((GUIGene) event.getGestureSource(), (GUIGene) event.getSource())) { + ((GUIGene) event.getGestureSource()).setConnectionLine((GUIGene) event.getSource()); if (event.getGestureSource() instanceof GUINode) { - Node source = ((GUINode) event.getGestureSource()).getGene(); - for (int i = 0; i < lines.length; i++) { - if (node == source.getConnection(i)) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); - return; - } + Connection source = ((GUINode) event.getGestureSource()).getChangingConnection(); + if (node == source) { + stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + return; } } else if (event.getGestureSource() instanceof GUIOutput) { Output source = ((GUIOutput) event.getGestureSource()).getGene(); @@ -181,6 +181,7 @@ public class GUINode extends GUIGene { public void handle(MouseDragEvent event) { // the drag has exited this node, react appropriately // this happens even if we are the source of the drag + parent.setTarget(false); if (event.isPrimaryButtonDown()) { if (event.getGestureSource() == event.getSource()) { stateProperty.set(GUIGeneState.SOURCE); @@ -189,58 +190,74 @@ public class GUINode extends GUIGene { stateProperty.set(GUIGeneState.INDIRECT_HOVER); } else { stateProperty.set(GUIGeneState.NEUTRAL); + ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); } } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler() { @Override public void handle(MouseDragEvent event) { + GUIGene source = ((GUIGene) event.getGestureSource()); // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); - stateProperty.set(GUIGeneState.HOVER); + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + // the user released the drag gesture on this node, react appropriately if (isAllowed((GUIGene) event.getGestureSource(), (GUIGene) event.getSource())) { - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).setChangingConnection(node); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).getGene().setConnection(0, node); + if (source.isLocked()) { + // remove locks from the old connection, add the to the new + // note that the old connection may still have locks after this + parent.getGuiGene(source.getChangingConnection()).removeLocks(source.getLocks()); + source.setChangingConnection(node); + addLocks(source.getLocks()); + } else { + if (source instanceof GUIOutput) { + source.resetState(); + } + source.setChangingConnection(node); } + } - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).updateLines(); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).updateLine(); - } - + source.updateLines(); + stateProperty.set(GUIGeneState.HOVER); } }); - - + + addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler() { @Override public void handle(MouseEvent event) { // cursor has entered this node without dragging, or it is dragging and this is the source if (stateProperty.get() == GUIGeneState.NEUTRAL) { stateProperty.set(GUIGeneState.HOVER); + } else if (locked > 0) { + setConnections(GUIGeneState.LOCKED_HOVER); } } }); - + addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler() { @Override public void handle(MouseEvent event) { // cursor has left this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.HOVER) { - if (isLocked()) { - + if (stateProperty.get() == GUIGeneState.HOVER && locked <= 0) { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); + } else if (locked > 0) { + if (stateProperty.get() == GUIGeneState.SOURCE || stateProperty.get() == GUIGeneState.FORBIDDEN_TARGET) { + setConnections(GUIGeneState.INDIRECT_HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.HOVER); } + } } }); @@ -248,54 +265,67 @@ public class GUINode extends GUIGene { getChildren().addAll(mainCircle, text); getChildren().addAll(sockets); getChildren().addAll(output, connectionNumber); - + stateProperty.addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, GUIGeneState oldValue, GUIGeneState newValue) { - + switch (newValue) { case ACTIVE_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - showLines(true); + if (locked > 0) { + stateProperty().set(GUIGeneState.LOCKED_HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + showLines(true); + } setConnections(GUIGeneState.ACTIVE_HOVER); break; + case LOCKED_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; case FORBIDDEN_TARGET: mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); break; case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); showLines(true); - if (!isLocked()) { + if ((oldValue != GUIGeneState.LOCKED_HOVER || oldValue != GUIGeneState.SOURCE) && locked <= 0) { setConnections(GUIGeneState.INDIRECT_HOVER); + } else { + setConnections(GUIGeneState.HOVER); } - break; case INDIRECT_HOVER: mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); break; case NEUTRAL: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); - showLines(false); - if (oldValue == GUIGeneState.ACTIVE_HOVER) { - setConnections(GUIGeneState.NEUTRAL); + if (locked > 0) { + stateProperty.set(GUIGeneState.HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + showLines(false); + if (oldValue == GUIGeneState.ACTIVE_HOVER) { + setConnections(GUIGeneState.NEUTRAL); + } } break; case NO_CHANGE_TARGET: + parent.setTarget(true); mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); break; case SOURCE: mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); break; case TARGET: + parent.setTarget(true); mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); break; default: break; - } } }); - + for (int c = 0; c < lines.length; c++) { final int i = c; node.connections().get(c).addListener(new ChangeListener() { @@ -306,10 +336,15 @@ public class GUINode extends GUIGene { } }); } - + } - - + + @Override + public Connection getChangingConnection() { + return node.getConnection(connectionIndex); + } + + private boolean isAllowed(GUIGene source, GUIGene target) { if (source instanceof GUINode) { // if the source is a node, all inputs and some nodes are valid @@ -368,7 +403,7 @@ public class GUINode extends GUIGene { updateLine(c); } } - + /** * Toggle visibility of all connection lines. * @@ -389,22 +424,11 @@ public class GUINode extends GUIGene { @Override public void setConnections(GUIGeneState newState) { for (int i = 0; i < lines.length; i++) { - if (node.getConnection(i) instanceof Node) { - if (!parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).isLocked()) { - parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).setState(newState); - } - } else if (node.getConnection(i) instanceof Input) { - if (!parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).isLocked()) { - parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).setState(newState); - } - } + parent.getGuiGene(node.getConnection(i)).setState(newState); } } - - /** - * This method sets the connection currently being changed to the - * specified value. - */ + + @Override public void setChangingConnection(Connection newConnection) { node.setConnection(connectionIndex, newConnection); } @@ -412,22 +436,48 @@ public class GUINode extends GUIGene { @Override public void resetState() { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); - } + if (locked > 0) { + stateProperty.set(GUIGeneState.HOVER); + } else { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); + } + } @Override public void setLocked(boolean value) { locked += value ? 1 : -1; stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); - + for (int i = 0; i < lines.length; i++) { - if (node.getConnection(i) instanceof Node) { - parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).setLocked(value); - } else if (node.getConnection(i) instanceof Input) { - parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).setLocked(value); - } + parent.getGuiGene(node.getConnection(i)).setLocked(value); + } + } + + @Override + public void addLocks(int value) { + locked += value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + + for (int i = 0; i < lines.length; i++) { + parent.getGuiGene(node.getConnection(i)).addLocks(value); + } + } + + @Override + public void removeLocks(int value) { + locked -= value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + + for (int i = 0; i < lines.length; i++) { + parent.getGuiGene(node.getConnection(i)).removeLocks(value); } } + + @Override + public void setConnectionLine(GUIGene gene) { + lines[connectionIndex].setEndX(gene.getLayoutX() + NODE_RADIUS); + lines[connectionIndex].setEndY(gene.getLayoutY()); + } } diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index 415d0fd..87d420e 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -14,7 +14,6 @@ import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import jcgp.GUI; -import jcgp.CGP.Resources; import jcgp.population.Connection; import jcgp.population.Input; import jcgp.population.Node; @@ -30,17 +29,17 @@ public class GUIOutput extends GUIGene { private Output output; - public GUIOutput(ChromosomePane parentRef, final Output output, Resources resources, Line line) { + public GUIOutput(ChromosomePane parentRef, final Output output, Line line) { this.parent = parentRef; this.output = output; this.sourceLine = line; - relocate((((int) resources.get("columns") + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, + relocate((((int) GUI.resources.get("columns") + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, (output.getIndex() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); - + // set the line ends correctly - updateLine(); + updateLines(); mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); mainCircle.setStroke(Paint.valueOf("black")); @@ -56,7 +55,7 @@ public class GUIOutput extends GUIGene { socket = new Circle(-NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); socket.setId(String.valueOf(0)); socket.setStroke(Paint.valueOf("black")); - + connectionLabel = new Label("S"); connectionLabel.setStyle("-fx-background-color:rgb(255, 255, 255); -fx-border-color:rgba(0, 0, 0, 0.5); "); connectionLabel.relocate(socket.getCenterX() + 5, socket.getCenterY() - 10); @@ -111,13 +110,13 @@ public class GUIOutput extends GUIGene { public void handle(MouseEvent event) { if (event.isDragDetect()) { // mouse was released before dragging out of the socket - updateLine(); + updateLines(); stateProperty.set(GUIGeneState.HOVER); } } }); - + /* * Mouse event handlers on whole gene */ @@ -138,28 +137,33 @@ public class GUIOutput extends GUIGene { if (event.getGestureSource() == event.getSource()) { stateProperty.set(GUIGeneState.SOURCE); } else { - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); - } else { - stateProperty.set(GUIGeneState.NEUTRAL); - } + stateProperty.set(isLocked() ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler() { @Override public void handle(MouseDragEvent event) { // making a connection to an output is illegal // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); + GUIGene source = ((GUIGene) event.getGestureSource()); + + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + + source.updateLines(); stateProperty.set(GUIGeneState.HOVER); } }); - - + + addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler() { @Override public void handle(MouseEvent event) { @@ -169,7 +173,7 @@ public class GUIOutput extends GUIGene { } } }); - + addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler() { @Override public void handle(MouseEvent event) { @@ -188,11 +192,11 @@ public class GUIOutput extends GUIGene { stateProperty.set(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } - + } } }); - + getChildren().addAll(mainCircle, text, socket, connectionLabel); @@ -208,9 +212,11 @@ public class GUIOutput extends GUIGene { mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); break; case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); sourceLine.setVisible(true); - setConnections(GUIGeneState.ACTIVE_HOVER); + if (!isLocked()) { + setConnections(GUIGeneState.ACTIVE_HOVER); + } break; case INDIRECT_HOVER: mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); @@ -224,28 +230,31 @@ public class GUIOutput extends GUIGene { break; case SOURCE: mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + setConnections(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.INDIRECT_HOVER); break; case TARGET: mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); break; default: break; - + } } }); - + output.sourceProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Connection oldValue, Connection newValue) { - updateLine(); + updateLines(); } }); } - public void updateLine() { + @Override + public void updateLines() { if (output.getSource() instanceof Node) { int row = ((Node) output.getSource()).getRow(), column = ((Node) output.getSource()).getColumn(); @@ -265,11 +274,7 @@ public class GUIOutput extends GUIGene { @Override public void setConnections(GUIGeneState newState) { - if (output.getSource() instanceof Node) { - parent.getGuiNode(((Node) output.getSource()).getRow(), ((Node) output.getSource()).getColumn()).setState(newState); - } else if (output.getSource() instanceof Input) { - parent.getGuiInput(((Input) output.getSource()).getIndex()).setState(newState); - } + parent.getGuiGene(output.getSource()).setState(newState); } @Override @@ -280,15 +285,37 @@ public class GUIOutput extends GUIGene { @Override public void setLocked(boolean value) { - //stateProperty.set(GUIGeneState.HOVER); locked += value ? 1 : -1; setConnections(value ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); - - if (output.getSource() instanceof Node) { - parent.getGuiNode(((Node) output.getSource()).getRow(), ((Node) output.getSource()).getColumn()).setLocked(value); - } else if (output.getSource() instanceof Input) { - parent.getGuiInput(((Input) output.getSource()).getIndex()).setLocked(value); - } - + + parent.getGuiGene(output.getSource()).setLocked(value); + + } + + @Override + public void setChangingConnection(Connection newConnection) { + output.setConnection(0, newConnection); } + + @Override + public Connection getChangingConnection() { + return output.getSource(); + } + + @Override + public void addLocks(int value) { + locked += value; + } + + @Override + public void removeLocks(int value) { + locked -= value; + } + + @Override + public void setConnectionLine(GUIGene gene) { + sourceLine.setEndX(gene.getLayoutX() + NODE_RADIUS); + sourceLine.setEndY(gene.getLayoutY()); + } + } diff --git a/src/jcgp/modules/Module.java b/src/jcgp/modules/Module.java index 5ce96b9..4997ce7 100644 --- a/src/jcgp/modules/Module.java +++ b/src/jcgp/modules/Module.java @@ -2,7 +2,7 @@ package jcgp.modules; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.parameters.Parameter; public interface Module { diff --git a/src/jcgp/modules/ea/EvolutionaryAlgorithm.java b/src/jcgp/modules/ea/EvolutionaryAlgorithm.java index d3fa709..3bc7fcf 100644 --- a/src/jcgp/modules/ea/EvolutionaryAlgorithm.java +++ b/src/jcgp/modules/ea/EvolutionaryAlgorithm.java @@ -1,6 +1,6 @@ package jcgp.modules.ea; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.modules.mutator.Mutator; import jcgp.population.Chromosome; diff --git a/src/jcgp/modules/ea/StandardEA.java b/src/jcgp/modules/ea/StandardEA.java index f2473f5..7e77977 100644 --- a/src/jcgp/modules/ea/StandardEA.java +++ b/src/jcgp/modules/ea/StandardEA.java @@ -2,7 +2,7 @@ package jcgp.modules.ea; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.mutator.Mutator; import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; diff --git a/src/jcgp/modules/fitness/FitnessFunction.java b/src/jcgp/modules/fitness/FitnessFunction.java index 509c230..f0800b0 100644 --- a/src/jcgp/modules/fitness/FitnessFunction.java +++ b/src/jcgp/modules/fitness/FitnessFunction.java @@ -1,6 +1,6 @@ package jcgp.modules.fitness; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.population.Population; diff --git a/src/jcgp/modules/fitness/TestCaseEvaluator.java b/src/jcgp/modules/fitness/TestCaseEvaluator.java index 1dade74..cd131b5 100644 --- a/src/jcgp/modules/fitness/TestCaseEvaluator.java +++ b/src/jcgp/modules/fitness/TestCaseEvaluator.java @@ -2,7 +2,7 @@ package jcgp.modules.fitness; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.parameters.Parameter; import jcgp.population.Population; diff --git a/src/jcgp/modules/mutator/Mutator.java b/src/jcgp/modules/mutator/Mutator.java index 5234f45..8dfa0f9 100644 --- a/src/jcgp/modules/mutator/Mutator.java +++ b/src/jcgp/modules/mutator/Mutator.java @@ -1,6 +1,6 @@ package jcgp.modules.mutator; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.population.Chromosome; diff --git a/src/jcgp/modules/mutator/PointMutator.java b/src/jcgp/modules/mutator/PointMutator.java index ea1ed32..51a4390 100644 --- a/src/jcgp/modules/mutator/PointMutator.java +++ b/src/jcgp/modules/mutator/PointMutator.java @@ -4,7 +4,7 @@ import java.util.HashMap; import jcgp.parameters.DoubleParameter; import jcgp.parameters.Parameter; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.MutableElement; import jcgp.population.Node; diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java index a7f2ed3..6f50025 100644 --- a/src/jcgp/population/Chromosome.java +++ b/src/jcgp/population/Chromosome.java @@ -2,7 +2,7 @@ package jcgp.population; import java.util.ArrayList; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.exceptions.ParameterMismatchException; public class Chromosome { diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java index bc9c9e8..586f556 100644 --- a/src/jcgp/population/Population.java +++ b/src/jcgp/population/Population.java @@ -1,6 +1,6 @@ package jcgp.population; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; public class Population { diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java index 6323b88..f4ed79c 100644 --- a/src/jcgp/tests/ChromosomeTests.java +++ b/src/jcgp/tests/ChromosomeTests.java @@ -2,7 +2,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Connection; import jcgp.population.Input; diff --git a/src/jcgp/tests/NodeTests.java b/src/jcgp/tests/NodeTests.java index 330ef7a..7ce5701 100644 --- a/src/jcgp/tests/NodeTests.java +++ b/src/jcgp/tests/NodeTests.java @@ -1,7 +1,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.function.Arithmetic; import jcgp.function.Function; import jcgp.population.Chromosome; diff --git a/src/jcgp/tests/OutputTests.java b/src/jcgp/tests/OutputTests.java index 00cfea3..8658fa4 100644 --- a/src/jcgp/tests/OutputTests.java +++ b/src/jcgp/tests/OutputTests.java @@ -2,7 +2,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Connection; import jcgp.population.Output; diff --git a/src/jcgp/tests/PopulationTests.java b/src/jcgp/tests/PopulationTests.java index 474b8d5..ca737d6 100644 --- a/src/jcgp/tests/PopulationTests.java +++ b/src/jcgp/tests/PopulationTests.java @@ -1,7 +1,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Population; -- cgit v1.2.3