/** * This helper method calculates the repulsive forces acting on a node from all the other nodes in * the graph. BIG O( number of nodes ) * * <p>There is a repulsive force between every nodes depending on the distance separating them and * their size. * * @param current node to calculate forces for. */ private void calculateNodeRepulsiveForces(Node current) { Iterator<Node> inner = controller.getNodeIterator(); int current_radius, n_radius, dx, dy; Node n; current_radius = (int) Math.sqrt(Math.pow(current.getWidth(), 2) + Math.pow(current.getHeight(), 2)); while (inner.hasNext()) { n = inner.next(); if (n != current) { dx = current.getX() - n.getX(); dy = current.getY() - n.getY(); n_radius = (int) Math.sqrt(Math.pow(n.getWidth(), 2) + Math.pow(n.getHeight(), 2)); // only repel if nodes are connected or within diameter * MAX_REPEL_DISTANCE // if (Math.sqrt(dx * dx + dy * dy) < (Math.max(current_radius, n_radius) * // MAX_REPEL_MULTIPLIER)) { double l = (dx * dx + dy * dy) + .1; if (l > 0) { // current.setVX(current.getVX() + dx * (current_radius * SPACING) / l); // current.setVY(current.getVY() + dy * (current_radius * SPACING) / l); current.accelx += (dx * REPULSION / (l)) / current.weight; current.accely += (dy * REPULSION / (l)) / current.weight; // current.accelx += (dx * SPACING / (l * .5)) / current.weight; // current.accely += (dy * SPACING / (l * .5)) / current.weight; // n.accelx += (dx * SPACING / (l * -0.5)) / n.weight; // n.accely += (dy * SPACING / (l * -0.5)) / n.weight; } // } } } }
private double calculateDistance(Node node1, Node node2) { double totalDistance = 0; double node1x = node1.getX(); double node1y = node1.getX(); double node2x = node2.getX(); double node2y = node2.getX(); for (double[][][] RADAR_LINE : RADARS) { for (double[][] LINE : RADAR_LINE) { if (Line2D.linesIntersect( LINE[POINT_1][X], LINE[POINT_1][Y], LINE[POINT_2][X], LINE[POINT_2][Y], node1x, node1y, node2x, node2y)) { totalDistance += FEE_IN_RADAR_RANGE; } } } double distanceX = (node1.getX() - node2.getX()); double distanceY = (node1.getY() - node2.getY()); double distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY) * FEE_DISTANCE_FACTOR; return distance + totalDistance; }
/** * Determine the distance between two neighbor Nodes as used by the AStar algorithm. * * @param node1 any Node * @param node2 any of Node1's neighbors * @return Float - the distance between the two neighbors */ public float getDistanceBetween(Node node1, Node node2) { // if the nodes are on top or next to each other, return 1 if (node1.getX() == node2.getX() || node1.getY() == node2.getY()) { return 1; // *(mapHeight+mapWith); } else { // if they are diagonal to each other return diagonal distance: sqrt(1^2+1^2) return (float) 1.9; // *(mapHeight+mapWith); } }
@Test( dataProvider = "doubleNodes", dataProviderClass = NodeProvider.class, groups = {"arithmetic"}) public void additionTest(Node a, Node b) { Node added = a.add(b); assert Rounding.isEqual(added.getX(), a.getX() + b.getX()); assert Rounding.isEqual(added.getY(), a.getY() + b.getY()); }
@Test( dataProvider = "doubleNodes", dataProviderClass = NodeProvider.class, groups = {"arithmetic"}) public void subtractionTest(Node a, Node b) { Node subtracted = a.subtract(b); assert Rounding.isEqual(subtracted.getX(), a.getX() - b.getX()); assert Rounding.isEqual(subtracted.getY(), a.getY() - b.getY()); }
public boolean shouldAdd(Node n, int carWidth) { for (int i = 0; i < this.size(); i++) { Node current = this.get(i); if (Math.sqrt(Math.pow(current.getX() - n.getX(), 2) + Math.pow(current.getY() - n.getY(), 2)) < carWidth) { return true; } } return false; }
@Test( dataProvider = "doubleNodes", dataProviderClass = NodeProvider.class, dependsOnMethods = {"subtractionTest"}) public void distanceTest(Node a, Node b) { Node subtracted = a.subtract(b); double distance = a.getDistance(b); assert distance > 0.; assert distance > Math.abs(subtracted.getX()); assert distance > Math.abs(subtracted.getY()); assert distance < Math.abs(subtracted.getX()) + Math.abs(subtracted.getY()); }
public double calcEdgeLength() { double firstX = source.getX(); double firstY = source.getY(); double secondX = destination.getX(); double secondY = destination.getY(); // Do some pythagoras double cathetusX = Math.abs(firstX - secondX); double cathetusY = Math.abs(firstY - secondY); double hypotenuse = Math.hypot(cathetusX, cathetusY); return hypotenuse; }
public ArrayList<Node> RegionQuery(Node P, ArrayList<Node> points, int eps) { int x2 = P.getX(); int y2 = P.getY(); ArrayList<Node> neighbors = new ArrayList<>(); for (int i = 0; i < points.size(); i++) { Node temp = points.get(i); int x1 = temp.getX(); int y1 = temp.getY(); if ((Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) < Math.pow(eps, 2)) { neighbors.add(temp); } } return neighbors; }
public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.CYAN); // draw basic board for (int i = 0, j = 0; j < 17; i += BLANK_WIDTH, j++) { g.drawLine(0, i, 640, i); g.drawLine(i, 0, i, 640); } // draw nodes ArrayList<Node> nodeList = NodeList.getList(); for (Node point : nodeList) { int x = (point.getX() - 1) * BLANK_WIDTH; int y = (point.getY() - 1) * BLANK_WIDTH; // draw black if (point.getColor() == Node.BLACK) { g.setColor(new Color(255, 192, 203)); } // draw white else if (point.getColor() == Node.WHITE) { g.setColor(Color.WHITE); } g.fillOval(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2); // newly point if (point.equals(NodeList.getLastNode())) { g.setColor(Color.RED); g.drawRect(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2); } } }
/** * This helper calculates all the attractive forces onto a node. Attractive forces from from the * edges pulling nodes towards each other, this will love through the edges of this node. * * @param current Node to calculate forces for. */ private void calculateNodeAttractiveForce(Node current) { // get all the edges of the current node ArrayList<Edge> nodeEdgeList = current.getEdgeList(); // of each of this node's edge do attactive forces Iterator<Edge> nodeEdges = nodeEdgeList.iterator(); /// int numOfEdgesWeight = 10 * (int) Math.round(nodeEdgeList.size() + SPACING); // Loop through edges and find edges containing current node while (nodeEdges.hasNext()) { Edge e = nodeEdges.next(); double edgeStrength = e.getStrength(); Node n; int dx, dy; double sign = 1.0; if (current == e.getNode1()) { n = e.getNode2(); dx = current.getX() - n.getX(); dy = current.getY() - n.getY(); } else { n = e.getNode1(); dx = current.getX() - n.getX(); dy = current.getY() - n.getY(); sign = -1.0; } double distance = Math.sqrt(dx * dx + dy * dy) + .1; // multiply by the strength of edge // current.setVX(current.getVX() - dx / numOfEdgesWeight * edgeStrength); // current.setVY(current.getVY() - dy / numOfEdgesWeight * edgeStrength); current.accelx += sign * (dx * STIFFNESS * (SPRING_LENGTH - distance)) / current.weight; current.accely += sign * (dy * STIFFNESS * (SPRING_LENGTH - distance)) / current.weight; // current.accelx += sign * (dx * (e.getStrength() + 1) * (SPRING_LENGTH - distance) * 0.5) / // current.weight; // current.accely += sign * (dy * (e.getStrength() + 1) * (SPRING_LENGTH - distance) * 0.5) / // current.weight; // n.accelx += sign * (dx * (e.getStrength() + 1) * (SPRING_LENGTH - distance) * 0.5) / // n.weight; // n.accely += sign * (dy * (e.getStrength() + 1) * (SPRING_LENGTH - distance) * 0.5) / // n.weight; } }
/* initialize nodes and links. the graph is complete ! :) */ public void initRandomGraph(Integer xMax, Integer yMax, Integer nbNode) { Random rand = new Random(); /* init nodes at random positions */ for (Integer i = 0; i < nbNode; i++) { Integer x = rand.nextInt(xMax); Integer y = rand.nextInt(yMax); Node n = new Node(x, y); nodes.add(n); } /* remove nodes that unfortunately spawned at the exact same position */ List<Node> doublons = new ArrayList<Node>(); for (Node source : nodes) { for (Node dest : nodes) { if (!source.equals(dest) && source.getX().equals(dest.getX()) && source.getY().equals(dest.getY())) { doublons.add(source); } } } if (!doublons.isEmpty()) { nodes.removeAll(doublons); System.out.println( "Lors de la génération aléatoire du graphes, " + doublons.size() + " doublons ont étés supprimés"); } /* init links for a complete graph */ for (Node source : nodes) { for (Node dest : nodes) { if (!source.equals(dest)) { Link link1 = new Link(source, dest); source.getLinks().add(link1); Link link2 = new Link(dest, source); dest.getLinks().add(link2); links.add(link1); links.add(link2); } } } }
@Test( dataProvider = "singleNode", dataProviderClass = NodeProvider.class, dependsOnGroups = {"arithmetic"}) public void equalityTest(Node n) { assert n.equals(n); assert n.equals(new Node(n.getX(), n.getY())); assert !n.equals(n.add(new Node(1., 1.))); assert !n.equals(n.subtract(new Node(1., 1.))); // test strictness Node tinyDiff = new Node(Rounding.EQUALITY_DIFFERENCE / 2., Rounding.EQUALITY_DIFFERENCE / 2.); assert !n.equals(n.add(tinyDiff)); assert !n.equals(n.subtract(tinyDiff)); assert n.equals(n.add(tinyDiff), false); assert n.equals(n.subtract(tinyDiff), false); }
/** * The graph was resize so the algorithm must be adapted to the new size. Then mark dirty. * * @param w new width * @param h new height */ private void setGraphSize(int w, int h) { int oldWidth = width; int oldHeight = height; double relativeWidth, relativeHeight; int newX, newY; width = w; height = h; // Move the pinned nodes to adjust to the new size ArrayList<Node> pinnedNodes = controller.getGraphPinned(); if (pinnedNodes != null) { for (Node n : pinnedNodes) { relativeWidth = (double) n.getX() / oldWidth; relativeHeight = (double) n.getY() / oldHeight; newX = (int) Math.round(width * relativeWidth); newY = (int) Math.round(height * relativeHeight); n.setX(newX); n.setY(newY); } } }
public int getManhattanDistanceTo(Node n) { int dx = Math.abs(n.getX() - getX()); int dy = Math.abs(n.getY() - getY()); return dx + dy; }
public int getDx() { if (prev == null) { return 0; } return getX() - prev.getX(); }
/** * Layout core logic. * * <p>This iterates over all the nodes and determines their velocities based on a force directed * layout approach, performs collision detection/avoidance and then ultimately their new positions * as they move. */ private void doLayout() { double maxVelocity = 100; double numOfIterations = 0; double step = 100; double skip = step; int counter = 1; boolean dividerChanged = false; // active = true; while (maxVelocity > 1 && active && (numOfIterations < MAX_NUM_OF_ITERATIONS)) { counter++; maxVelocity = 0; numOfIterations++; Iterator<Node> outer = controller.getNodeIterator(); startTime = System.currentTimeMillis(); double systemMovement = 0; double kineticEnergy = 0; /* Iterate over all nodes and calculate velocity */ while (outer.hasNext()) { Node current = outer.next(); current.resetVelocity(); current.resetAcceleration(); /* * If current node is not pinned or selected, * perform force directed layout calculations here. */ if (!((current == controller.getGraphSelected()) || current.isPinned())) { calculateNodeAttractiveForce(current); calculateNodeRepulsiveForces(current); // applyNodeFriction(current); // if (IS_COOLING) { // calculateNodeCooling(current, numOfIterations); // } // calculate velocities current.setVX(current.getVX() + current.accelx * TIMESTEP * DAMPING); current.setVY(current.getVY() + current.accely * TIMESTEP * DAMPING); double speedSquared = current.getVX() * current.getVX() + current.getVY() * current.getVY(); kineticEnergy += 0.5 * current.weight * speedSquared; // cap the velocity if (current.getVX() >= 0) { current.setVX(Math.min(current.getVX(), MAX_DIST_PER_MOVE)); } else { current.setVX(Math.max(current.getVX(), -MAX_DIST_PER_MOVE)); } if (current.getVY() >= 0) { current.setVY(Math.min(current.getVY(), MAX_DIST_PER_MOVE)); } else { current.setVY(Math.max(current.getVY(), -MAX_DIST_PER_MOVE)); } // System.out.println("vy "+ current.getVY() + ", vx " + current.getVX()); } } /* Iterate over all nodes move them after all the velocities are set */ outer = controller.getNodeIterator(); while (outer.hasNext()) { Node current = outer.next(); int xStart = current.getX(); int yStart = current.getY(); /* update node position */ int xEnd = current.getX() + (int) current.getVX(); int yEnd = current.getY() + (int) current.getVY(); int dX = Math.abs(xStart - xEnd); int dY = Math.abs(yStart - yEnd); // systemMovement += dX; // systemMovement += dY; // if(dX + dY > 6) { controller.moveNode(current, xEnd, yEnd); // } // controller.moveNode(current, Math.min(current.getX() + (int) // current.getVX(),MAX_DIST_PER_MOVE), Math.min(current.getY() + (int) current.getVY(), // MAX_DIST_PER_MOVE)); /* compute maxVelocity for layout iteration */ maxVelocity = Math.max( maxVelocity, Math.sqrt(Math.pow(current.getVX(), 2) + Math.pow(current.getVY(), 2))); } if (kineticEnergy < ENERGY_THRESHOLD) { numOfIterations = MAX_NUM_OF_ITERATIONS; } /* Make animation slower */ try { Thread.sleep(sleepInterval); } catch (InterruptedException ex) { } /* Calculate how long the iteration took */ stopTime = System.currentTimeMillis(); long duration = stopTime - startTime; if ((duration > MAX_ITERATION_TIME) && (sleepInterval > 5)) { sleepInterval -= 5; } else if (duration < MIN_ITERATION_TIME) { sleepInterval += 5; } if (numOfIterations > skip) { skip += step; System.out.print('.'); } } /* We've reached a stable layout, hold on for now */ stable = true; // System.out.println("ran in " + numOfIterations + " iterations."); }