public List<Vector2D> getShapeForDrawing() { List<Vector2D> theList = new ArrayList<Vector2D>(); theList.add(d.getPosition()); for (Node n : Arrays.asList(dt, tv, v)) { theList.add(n.getPosition()); } return theList; }
public Shape getShape() { GeneralPath gp = new GeneralPath(); gp.moveTo((float) d.getPosition().getX(), (float) d.getPosition().getY()); for (Node n : Arrays.asList(dt, tv, v)) { gp.lineTo((float) n.getPosition().getX(), (float) n.getPosition().getY()); } gp.closePath(); return gp; }
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); } }
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)); }
/** used for cut and paste. */ public void addObjectFromClipboard(String a_value) throws CircularIncludeException { Reader reader = new StringReader(a_value); Document document = null; try { document = UJAXP.getDocument(reader); } catch (Exception e) { e.printStackTrace(); return; } // try-catch Element root = document.getDocumentElement(); if (!root.getNodeName().equals("clipboard")) { return; } // if Node child; for (child = root.getFirstChild(); child != null; child = child.getNextSibling()) { if (!(child instanceof Element)) { continue; } // if Element element = (Element) child; IGlyphFactory factory = GlyphFactory.getFactory(); if (XModule.isMatch(element)) { EModuleInvoke module = (EModuleInvoke) factory.createXModule(element); addModule(module); continue; } // if if (XContour.isMatch(element)) { EContour contour = (EContour) factory.createXContour(element); addContour(contour); continue; } // if if (XInclude.isMatch(element)) { EIncludeInvoke include = (EIncludeInvoke) factory.createXInclude(element); addInclude(include); continue; } // if } // while }
/** * 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()); } }
@Override public SVGDocument toSVG(ConcreteDiagram cd) { /* * Use a Plain drawer to generate an SVG Document, then * "post-process" any SVG circles in the document to convert them * into "sketches". */ SVGDocument document = (new PlainCircleSVGDrawer()).toSVG(cd); // return document; // find each circle in the document and turn it into a sketch. We // need to keep track of the circles and their eventual replacements // as each circle is replaced by 10's of smaller circles, thus the // DOM updates and we get the 10's of circles in our NodeList circles. NodeList circles = document.getElementsByTagName("circle"); List<Node> replaceable = nodeListToList(circles); for (Node n : replaceable) { Node circleAsSketch = circleToSketch(document, (SVGCircleElement) n); n.getParentNode().replaceChild(circleAsSketch, n); } return document; }
/** * 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))); } }
/** * Constructs a new compartment from four nodes * * @param d Dorsal node * @param dt Dorsal transversal Node * @param tv Ventral transversal node * @param v Ventral node */ public Compartment(Node d, Node dt, Node tv, Node v) { this.d = d; this.dt = dt; this.tv = tv; this.v = v; nodeList = Arrays.asList(d, dt, tv, v); // Internal pressures pressure = new PressureInfluence(); for (Node n : nodeList) { n.addInfluence(pressure); } // Muscles dorsal = new LongitudinalMuscleInfluence(d, dt, dt.getPosition().subtract(tv.getPosition()).norm()); d.addInfluence(dorsal); dt.addInfluence(dorsal); transversal = new TransversalMuscleInfluence(dt, tv, dt.getPosition().subtract(d.getPosition()).norm()); dt.addInfluence(transversal); tv.addInfluence(transversal); ventral = new LongitudinalMuscleInfluence(tv, v, dt.getPosition().subtract(tv.getPosition()).norm()); tv.addInfluence(ventral); v.addInfluence(ventral); // Friction dorsalFriction = new AxialFrictionInfluence(dt, d); dt.addInfluence(dorsalFriction); ventralFriction = new AxialFrictionInfluence(tv, v); tv.addInfluence(ventralFriction); normals = new HashMap<Node, Vector2D>(); pressureShapes = new ArrayList<Polygon>(); computeArea(); desiredArea = area; }