// calculate the coordinates of the startpoint (endpoint) if parameter is // true (false) of the arrow when drawing this link private Point calcCoord(boolean startpoint) { if (!startpoint && (end == null)) return openEnd; int deltaX; int deltaY; if (end == null) { deltaX = start.getX() - openEnd.x; deltaY = start.getY() - openEnd.y; } else { deltaX = start.getX() - end.getX(); deltaY = start.getY() - end.getY(); } double dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY); double prop = (Client.RADIUS) / dist; int offsetX = (int) Math.round(deltaX * prop); int offsetY = (int) Math.round(deltaY * prop); if (startpoint) { return new Point(start.getX() - offsetX, start.getY() - offsetY); } else return new Point(end.getX() + offsetX, end.getY() + offsetY); }
// returns the endpoint which is closer to (x,y) than the other one public Client getPointNear(int x, int y) { if (start == null || end == null) throw new RuntimeException("ERROR: getPointNear() not allowed on open links"); int distToStart = (int) Math.pow(start.getX() - x, 2) + (int) Math.pow(start.getY() - y, 2); int distToEnd = (int) Math.pow(end.getX() - x, 2) + (int) Math.pow(end.getY() - y, 2); if (distToStart < distToEnd) { return start; } else { return end; } }
// get the delay of the next packet public int getDelay() { switch (delayType) { case NO_DELAY: return 0; case CONST_DELAY: return constDelayMs; case DIST_DELAY: // calculate distance between start and end node int x = start.getX() - end.getX(); int y = start.getY() - end.getY(); float dist = (float) Math.sqrt(x * x + y * y); return (int) (dist * distDelayFactor); default: throw new RuntimeException("ERROR: Illegal delay type " + delayType); } }
// returns true if (x,y) is close to the link public boolean intersects(int x0, int y0) { if (end == null) throw new RuntimeException("ERROR: intersect() not allowed on open links"); int x1, x2, y1, y2; x1 = start.getX(); x2 = end.getX(); y1 = start.getY(); y2 = end.getY(); // calculate the distance between the direct start-end connection and the point double o = Math.abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)); double u = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2)); if ((o / u) < INTERSECTION_DISTANCE) { return true; } return false; }
// draw the link public void draw(Graphics g1D) { // don't draw an open link if the end is inside of its startpoint if ((end == null) && (openEnd.distance(start.getX(), start.getY()) < Client.RADIUS)) return; // activate anti aliasing Graphics2D g = (Graphics2D) g1D; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // set correct color if ((end != null) && start.isRunning() && end.isRunning()) g.setColor(RUNNING_LINK_COLOR); else g.setColor(SLEEPING_LINK_COLOR); // calculate start- & endpoint and link length Point s = new Point(); Point e = new Point(); double dist; s.x = start.getX(); s.y = start.getY(); if (end == null) { e.x = openEnd.x; e.y = openEnd.y; dist = s.distance(e) + Client.RADIUS; } else { e.x = end.getX(); e.y = end.getY(); dist = s.distance(e); } int fact = 1; // fact = +/- 1 (needed if s not on the left of e) if (s.x > e.x) fact = -1; // rotate g so that we can draw horizontally double theta = Math.atan(((float) (e.y - s.y)) / (e.x - s.x)); g.rotate(theta, s.x, s.y); // draw the link Stroke old = g.getStroke(); if (getErrorType() == NO_ERROR) { g.setStroke(normal); } else { g.setStroke(dashed); } if (this.isBidirectional) { g.drawLine( s.x + fact * (Client.RADIUS + ARROW_LENGTH), s.y, (s.x + fact * ((int) dist - Client.RADIUS - ARROW_LENGTH)), s.y); } else { g.drawLine( s.x + fact * Client.RADIUS, s.y, (s.x + fact * ((int) dist - Client.RADIUS - ARROW_LENGTH)), s.y); } g.setStroke(old); // draw the arrows // // /| |\ ^ W = ARROW_WIDTH // < ------ > W L = ARROW_LENGTH // \| |/ v // // <L> // <-- dist --> int arrowX[] = new int[3]; int arrowY[] = new int[3]; arrowX[0] = s.x + fact * (Client.RADIUS); arrowX[1] = s.x + fact * (Client.RADIUS + ARROW_LENGTH); arrowX[2] = s.x + fact * (Client.RADIUS + ARROW_LENGTH); arrowY[0] = s.y; arrowY[1] = s.y - ARROW_WIDTH / 2; arrowY[2] = s.y + ARROW_WIDTH / 2; if (this.isBidirectional) { if (flashingStart) { g.setColor(USED_LINK_COLOR); g.fillPolygon(arrowX, arrowY, 3); g.setColor(RUNNING_LINK_COLOR); } else { g.fillPolygon(arrowX, arrowY, 3); } } else { } arrowX[0] = s.x + fact * ((int) dist - Client.RADIUS); arrowX[1] = s.x + fact * ((int) dist - Client.RADIUS - ARROW_LENGTH); arrowX[2] = s.x + fact * ((int) dist - Client.RADIUS - ARROW_LENGTH); if (flashingEnd) { g.setColor(USED_LINK_COLOR); g.fillPolygon(arrowX, arrowY, 3); g.setColor(RUNNING_LINK_COLOR); } else { g.fillPolygon(arrowX, arrowY, 3); } // write delay & packet info to the link if (end != null) { // write delay above the link String delayText = Integer.toString(getDelay()) + " ms"; if (delayText.equals("0 ms")) { delayText = "no delay"; } int delayWidth = g.getFontMetrics().stringWidth(delayText); // draw the text only if there is enough space if (delayWidth < dist - 2 * Client.RADIUS) g.drawString(delayText, (int) (s.x + fact * dist / 2 - delayWidth / 2), s.y - 8); // write sent/lost packets below the link String packetText = "sent: " + Integer.toString(succCount) + " lost: " + Integer.toString(lostCount); String packetTextShort = Integer.toString(succCount) + " / " + Integer.toString(lostCount); int packetWidth = g.getFontMetrics().stringWidth(packetText); int packetWidthShort = g.getFontMetrics().stringWidth(packetTextShort); // draw the text only if there is enough space if (packetWidth < dist - 2 * Client.RADIUS) g.drawString(packetText, (int) (s.x + fact * dist / 2 - packetWidth / 2), s.y + 15); else if (packetWidthShort < dist - 2 * Client.RADIUS) g.drawString( packetTextShort, (int) (s.x + fact * dist / 2 - packetWidthShort / 2), s.y + 15); } // rotate g back g.rotate(-theta, s.x, s.y); }