private static Shape makeLine(Vector2D base, Vector2D disp) { double x1 = base.getX(); double y1 = base.getY(); double x2 = x1 + disp.getX(); double y2 = y1 + disp.getY(); return new Line2D.Double(x1, y1, x2, y2); }
/** * Get the bounding rectangle * * @return minimum bounding rectangle */ public BoundingRectangle2D getBounds() { if (boundsChanged == true) { boolean first = true; double minX = 0; double maxX = 0; double minY = 0; double maxY = 0; for (Enumeration e = vertices.elements(); e.hasMoreElements(); ) { Vector2D vertex = (Vector2D) e.nextElement(); if (first) { minX = vertex.getX(); maxX = vertex.getX(); minY = vertex.getY(); maxY = vertex.getY(); first = false; } else { minX = Math.min(minX, vertex.getX()); maxX = Math.max(maxX, vertex.getX()); minY = Math.min(minY, vertex.getY()); maxY = Math.max(maxY, vertex.getY()); } } bounds.set(minX, minY, Math.abs(maxX - minX), Math.abs(maxY - minY)); boundsChanged = false; } return bounds; }
/** * Rotate the polygon clockwise about a point by an arbritray angle. * * @param x X ordinate of point to rotate about * @param y Y ordinate of point to rotate about * @param angle Angle in radians */ public void rotate(double x, double y, double angle) { double theta = -angle; for (Enumeration e = vertices(); e.hasMoreElements(); ) { Vector2D vertex = (Vector2D) e.nextElement(); // translate to origin double tmpX = vertex.getX() - x; double tmpY = vertex.getY() - y; // rotate double sin = Math.sin(theta); double cos = Math.cos(theta); double newX = tmpX * cos - tmpY * sin; double newY = tmpX * sin + tmpY * cos; // translate back to old location newX += x; newY += y; // set teh point to be where we calculated it should be vertex.setXY(newX, newY); } flagModified(); }
/** Generate the edges of this polygon */ private void generateEdges() { if (haveEdgesChanged == true) { edges.removeAllElements(); Vector2D first = null; Vector2D lastChecked = null; double x = 0; double y = 0; for (Enumeration e = vertices.elements(); e.hasMoreElements(); ) { Vector2D vertex = (Vector2D) e.nextElement(); x += vertex.getX(); y += vertex.getY(); if (lastChecked == null) { first = vertex; lastChecked = first; } else { edges.addElement(new Line2D(lastChecked, vertex)); lastChecked = vertex; } } if (first != null) { edges.addElement(new Line2D(lastChecked, first)); } } haveEdgesChanged = false; }
/** * Check if a point is contained within this polygon * * @param point * @return true if contained, false otherwise */ public boolean contains(Vector2D point) { if (!getBounds().contains(point)) { System.out.println("AAA: " + point); return false; } Line2D verticalRay = new Line2D(point, new Vector2D(point.getX(), Double.POSITIVE_INFINITY)); int intersectionCount = 0; boolean contains = false; generateEdges(); for (Enumeration e = edges.elements(); e.hasMoreElements(); ) { Line2D testLine = (Line2D) e.nextElement(); double minY = Math.min(testLine.getStart().getY(), testLine.getEnd().getY()); double maxY = Math.max(testLine.getStart().getY(), testLine.getEnd().getY()); if (testLine.getGradient() == Double.POSITIVE_INFINITY) { if (point.getX() == testLine.getStart().getX() && point.getY() >= minY && point.getY() <= maxY) { contains = true; } } else { if (verticalRay.intersects(testLine)) { intersectionCount++; } } } return (contains || (intersectionCount % 2 == 1)); }
/** * Translate the polygon by a vector offset * * @param offset */ public void translate(Vector2D offset) { Enumeration e = vertices(); while (e.hasMoreElements()) { Vector2D v = (Vector2D) e.nextElement(); v.add(offset); } flagModified(); }
/** * Compute the (inward) normal of each node by taking a weighted average of the (inward) surface * normals of the edges connected to it. Longer edges are given more weight. */ private void computeWeightedNormals() { for (int i = 0, n = nodeList.size(); i < n; i++) { Node prevNode = nodeList.get(i); Node curNode = nodeList.get((i + 1) % n); Node nextNode = nodeList.get((i + 2) % n); Vector2D prevVector = curNode.getPosition().subtract(prevNode.getPosition()).rotate270(); Vector2D nextVector = nextNode.getPosition().subtract(curNode.getPosition()).rotate270(); normals.put(curNode, prevVector.add(nextVector).normalize()); } }
private final void computeArea() { // The area of a quadrilateral is 0.5*p*q*sin(theta) // Where p and q are the length of the 2 diagonals and theta is the angle between them // If we rotate P in the right direction, then area = 0.5*p*q*cos(theta) where theta is // the angle between Q and the rotated P, but this is simply 0.5 * dot product of P' and Q // Note, it is possible because of the cos to get a negative area, when this happens, it means // that the quadrilateral has flipped and that the normally inward pointing normals are // now pointing outward, so if we get a negative area, we should flip the force vectors... Vector2D P = tv.getPosition().subtract(d.getPosition()); Vector2D Q = dt.getPosition().subtract(v.getPosition()); area = 0.5 * P.rotate90().dot(Q); if (Math.signum(area) != Math.signum(desiredArea) && desiredArea != 0) { System.err.println( "Compartment:" + this.toString() + " has flipped inside out. Area:" + area); } }
/** * Compute the (inward) normal at each node by averaging the unit direction vectors of the two * edges connected to it. */ private void computeNormals() { for (int i = 0, n = nodeList.size(); i < n; i++) { Node prevNode = nodeList.get(i); Node curNode = nodeList.get((i + 1) % n); Node nextNode = nodeList.get((i + 2) % n); Vector2D prevEdge = curNode.getPosition().subtract(prevNode.getPosition()); Vector2D nextEdge = nextNode.getPosition().subtract(curNode.getPosition()); double crossProd = prevEdge.crossMag(nextEdge); Vector2D normal = prevEdge.normalize().subtract(nextEdge.normalize()).scaleTo(Math.signum(crossProd)); normals.put(curNode, normal); } }
public void update() { // See Compute Area for reason of the absolute value and signum of area... double pressureForce = Constants.get().getPressure() * (Math.abs(area) - Math.abs(desiredArea)); pressureForce = Math.signum(area) * Math.signum(pressureForce) * Math.sqrt(Math.abs(pressureForce)); // The pressure is applied on every segment proportionally to its area. for (int i = 0, n = nodeList.size(); i < n; i++) { Node prevNode = nodeList.get(i); Node curNode = nodeList.get((i + 1) % n); Node nextNode = nodeList.get((i + 2) % n); Vector2D prevVector = curNode.getPosition().subtract(prevNode.getPosition()).rotate270(); Vector2D nextVector = nextNode.getPosition().subtract(curNode.getPosition()).rotate270(); forces.put(curNode, prevVector.scale(pressureForce).add(nextVector.scale(pressureForce))); } }
/** * Get the midpoint of this polygon * * @return Midpoint */ public Vector2D midPoint() { if (isMidPointChanged == true) { double x = 0; double y = 0; for (Enumeration e = vertices.elements(); e.hasMoreElements(); ) { Vector2D vertex = (Vector2D) e.nextElement(); x += vertex.getX(); y += vertex.getY(); } midPoint = new Vector2D(x / vertices.size(), y / vertices.size()); isMidPointChanged = false; return midPoint; } else { return midPoint; } }
public void update() { Vector2D prevVector = main.getPosition().subtract(previous.getPosition()); Vector2D nextVector = next.getPosition().subtract(main.getPosition()); double angleRad = Math.acos(prevVector.dot(nextVector) / (prevVector.norm() * nextVector.norm())); double angle = Math.toDegrees(angleRad); if (prevVector.crossMag(nextVector) > 0) { angle = 360.0 - angle; } double forceMag = ANGLE_CONSTANT * (angle - 90.0); forces.put(previous, prevVector.rotate270().scaleTo(NEIGHBOR_ANGLE_SCALE * forceMag)); forces.put(main, normals.get(main).scaleTo(forceMag)); forces.put(next, nextVector.rotate270().scaleTo(NEIGHBOR_ANGLE_SCALE * forceMag)); }
/** * Rotate the polygon clockwise about a point by an arbritray angle. * * @param v Point vector to rotate about * @param angle Angle in radians */ public void rotate(Vector2D v, double angle) { rotate(v.getX(), v.getY(), angle); }