package jcgp.gui.population; import java.util.ArrayList; import javafx.scene.control.ScrollPane; import javafx.scene.layout.Pane; import javafx.scene.shape.Line; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; import jcgp.backend.population.Node; import jcgp.backend.resources.Resources; import jcgp.gui.GUI; import jcgp.gui.constants.Constants; import jcgp.gui.handlers.GUIHandlers; /** * This extension of {@code ScrollPane} contains a series of * nodes, inputs and outputs spread across a grid. It also contains * all of the connection lines overlaid over the nodes, inputs and outputs. * * * @author Eduardo Pedroni * */ public class ChromosomePane extends ScrollPane { private GUINode[][] guiNodes; private GUIInput[] guiInputs; private GUIOutput[] guiOutputs; private ArrayList connectionLines; private Pane content; private int rows, columns; private boolean target = false; public ChromosomePane(Chromosome chromosome) { super(); final Resources resources = GUI.resources; connectionLines = new ArrayList(); rows = resources.rows(); columns = resources.columns(); content = new Pane(); content.setId("content pane for genes"); // generate the GUIGenes /* * inputs */ guiInputs = new GUIInput[resources.inputs()]; for (int i = 0; i < guiInputs.length; i++) { // make the GUI elements guiInputs[i] = new GUIInput(chromosome.getInput(i)); guiInputs[i].relocate(Constants.NODE_RADIUS, (chromosome.getInput(i).getIndex() * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS); GUIHandlers.addHandlers(guiInputs[i]); } content.getChildren().addAll(guiInputs); /* * nodes */ guiNodes = new GUINode[rows][columns]; double angle, xPos, yPos; for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { // make the connection lines Line lines[] = new Line[resources.arity()]; for (int l = 0; l < lines.length; l++) { angle = ((((double) (l + 1)) / ((double) (lines.length + 1))) * Constants.THETA) - (Constants.THETA / 2); xPos = (-Math.cos(angle) * Constants.NODE_RADIUS) + (((c + 1) * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS); yPos = (Math.sin(angle) * Constants.NODE_RADIUS) + ((r * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS); lines[l] = new Line(xPos, yPos, xPos, yPos); lines[l].setMouseTransparent(true); //lines[l].setVisible(false); connectionLines.add(lines[l]); } // make the GUI elements guiNodes[r][c] = new GUINode(chromosome.getNode(r, c), lines) { @Override public GUIConnection getGUIConnection(Connection connection) { if (connection instanceof Input) { return guiInputs[((Input) connection).getIndex()]; } else if (connection instanceof Node) { return guiNodes[((Node) connection).getRow()][((Node) connection).getColumn()]; } else { // something bad happened! throw new ClassCastException(); } } }; guiNodes[r][c].relocate(((chromosome.getNode(r, c).getColumn() + 1) * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS, (chromosome.getNode(r, c).getRow() * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS); GUIHandlers.addHandlers(guiNodes[r][c]); } content.getChildren().addAll(guiNodes[r]); } /* * outputs */ guiOutputs = new GUIOutput[resources.outputs()]; for (int i = 0; i < guiOutputs.length; i++) { // make the GUI elements guiOutputs[i] = new GUIOutput(chromosome.getOutput(i)) { @Override public GUIConnection getGUIConnection(Connection connection) { if (connection instanceof Input) { return guiInputs[((Input) connection).getIndex()]; } else if (connection instanceof Node) { return guiNodes[((Node) connection).getRow()][((Node) connection).getColumn()]; } else { // something bad happened! throw new ClassCastException(); } } }; guiOutputs[i].relocate(((resources.columns() + 1) * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS, (chromosome.getOutput(i).getIndex() * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.NODE_RADIUS); GUIHandlers.addHandlers(guiOutputs[i]); } content.getChildren().addAll(guiOutputs); // add lines to the pane as on top of genes content.getChildren().addAll(connectionLines); setPrefWidth(620); setContent(content); } // protected 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(); // } // } protected boolean isTarget() { return target; } protected void setTarget(boolean newValue) { target = newValue; } public void updateGenes(Chromosome chr) { for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { guiNodes[r][c].setNode(chr.getNode(r, c)); } } for (int i = 0; i < guiOutputs.length; i++) { guiOutputs[i].setOutput(chr.getOutput(i)); } } public static boolean isAllowed(GUIMutable source, GUIConnection target) { if (source instanceof GUINode) { // if the source is a node, all inputs and some nodes are valid if (target instanceof GUIInput) { return true; } else if (target instanceof GUINode) { // target and source are nodes, let's look at levels back Node t = ((GUINode) target).getNode(), s = ((GUINode) source).getNode(); if (s.getColumn() - t.getColumn() > 0 && s.getColumn() - t.getColumn() <= GUI.resources.levelsBack()) { return true; } } return false; } else if (source instanceof GUIOutput) { // if the source is an output, any node or input is valid if (target instanceof GUINode || target instanceof GUIInput) { return true; } else { // this should never happen... return false; } } // if the source was neither node nor output, something bad is happening throw new ClassCastException("Source was neither GUINode nor GUIOutput."); } }