private void getMinMax(double p1, double p2, double p3, double p4, double[] minMax) { if (p4 > p1) { minMax[0] = p1; minMax[1] = p4; } else { minMax[0] = p4; minMax[1] = p1; } double c0 = 3 * (p2 - p1); double c1 = 6 * (p3 - p2); double c2 = 3 * (p4 - p3); double[] eqn = {c0, c1 - 2 * c0, c2 - c1 + c0}; int roots = QuadCurve2D.solveQuadratic(eqn); for (int r = 0; r < roots; r++) { double tv = eqn[r]; if ((tv <= 0) || (tv >= 1)) continue; tv = ((1 - tv) * (1 - tv) * (1 - tv) * p1 + 3 * tv * (1 - tv) * (1 - tv) * p2 + 3 * tv * tv * (1 - tv) * p3 + tv * tv * tv * p4); if (tv < minMax[0]) minMax[0] = tv; else if (tv > minMax[1]) minMax[1] = tv; } }
@Override public Point2D calculatePosition(Point2D pos, double speed) { if (isBackWard) {} PathIterator p = fCurve.getPathIterator(null); FlatteningPathIterator f = new FlatteningPathIterator(p, reduceCarSpeed(speed)); while (!f.isDone()) { float[] pts = new float[6]; switch (f.currentSegment(pts)) { case PathIterator.SEG_MOVETO: case PathIterator.SEG_LINETO: Point2D point = new Point2D.Float(pts[0], pts[1]); if (point.distance(pos) == 0) { f.next(); if (!f.isDone()) { pts = new float[6]; f.currentSegment(pts); return new Point2D.Float(pts[0], pts[1]); } else { return new Point2D.Double(-1, -1); } } } f.next(); } return new Point2D.Double(-1, -1); }
/** Initializes object to draw given edge. */ private void updateCurve(VisualEdge e) { Vec2 fromPos = e.getFrom().getVisibleAncestor().getPos(); Vec2 toPos = e.getTo().getVisibleAncestor().getPos(); Vec2 curveCenter = e.getPos(); // second control point double px = 2 * (curveCenter.x - 0.25 * fromPos.x - 0.25 * toPos.x); double py = 2 * (curveCenter.y - 0.25 * fromPos.y - 0.25 * toPos.y); if (curve == null) curve = new QuadCurve2D.Double(); curve.setCurve(fromPos.x, fromPos.y, px, py, toPos.x, toPos.y); }
private static CubicCurve2D _toCubicCurve(Shape seg, CubicCurve2D cub) { if (cub == null) { cub = new CubicCurve2D.Double(); } if (seg instanceof Line2D) { Line2D src = (Line2D) seg; cub.setCurve( src.getX1(), src.getY1(), src.getX1(), src.getY1(), src.getX2(), src.getY2(), src.getX2(), src.getY2()); } else if (seg instanceof Ellipse2D) { throw new InternalError("Can't convert Ellipse2D to CubicCurve2D"); } else if (seg instanceof Arc2D) { throw new InternalError("Can't convert Arc2D to CubicCurve2D"); } else if (seg instanceof QuadCurve2D) { QuadCurve2D src = (QuadCurve2D) seg; cub.setCurve( src.getX1(), src.getY1(), src.getCtrlX(), src.getCtrlY(), src.getCtrlX(), src.getCtrlY(), src.getX2(), src.getY2()); } else { CubicCurve2D src = (CubicCurve2D) seg; cub.setCurve( src.getX1(), src.getY1(), src.getCtrlX1(), src.getCtrlY1(), src.getCtrlX2(), src.getCtrlY2(), src.getX2(), src.getY2()); } return cub; }
@Override public boolean contains(Location loc, boolean assumeFilled) { Object type = getPaintType(); if (assumeFilled && type == DrawAttr.PAINT_STROKE) { type = DrawAttr.PAINT_STROKE_FILL; } if (type != DrawAttr.PAINT_FILL) { int stroke = getStrokeWidth(); double[] q = toArray(loc); double[] p0 = toArray(this.p0); double[] p1 = toArray(this.p1); double[] p2 = toArray(this.p2); double[] p = CurveUtil.findNearestPoint(q, p0, p1, p2); if (p == null) { return false; } int thr; if (type == DrawAttr.PAINT_STROKE) { thr = Math.max(Line.ON_LINE_THRESH, stroke / 2); } else { thr = stroke / 2; } if (LineUtil.distanceSquared(p[0], p[1], q[0], q[1]) < thr * thr) { return true; } } if (type != DrawAttr.PAINT_STROKE) { QuadCurve2D curve = getCurve(null); if (curve.contains(loc.getX(), loc.getY())) { return true; } } return false; }
/** * determines whether the car is still on this lane * * @param fCar car to test with * @param lane * @return */ public boolean carOnLane(Car fCar, Lane lane) { PathIterator p = fCurve.getPathIterator(null); FlatteningPathIterator f = new FlatteningPathIterator(p, reduceCarSpeed(fCar.getSpeed())); while (!f.isDone()) { float[] pts = new float[6]; switch (f.currentSegment(pts)) { case PathIterator.SEG_MOVETO: case PathIterator.SEG_LINETO: Point2D point = new Point2D.Float(pts[0], pts[1]); if (point.distance(fCar.getPosition()) <= 1) { return true; } } f.next(); } return false; }
@Override public double getLength() { if (fLength == 0) { PathIterator iter = fCurve.getPathIterator(null, 0.5); double[] curSeg = new double[2]; iter.currentSegment(curSeg); iter.next(); double x0 = curSeg[0]; double y0 = curSeg[1]; while (!iter.isDone()) { iter.currentSegment(curSeg); fLength += Math.sqrt((curSeg[0] - x0) * (curSeg[0] - x0) + (curSeg[1] - y0) * (curSeg[1] - y0)); x0 = curSeg[0]; y0 = curSeg[1]; iter.next(); } } return fLength; }
@Override public void relocate(Car fCar) { PathIterator p = fCurve.getPathIterator(null); FlatteningPathIterator f = new FlatteningPathIterator(p, reduceCarSpeed(fCar.getSpeed())); Point2D nearestPoint = null; double distance = 1000; while (!f.isDone()) { float[] pts = new float[6]; switch (f.currentSegment(pts)) { case PathIterator.SEG_MOVETO: case PathIterator.SEG_LINETO: Point2D point = new Point2D.Float(pts[0], pts[1]); double distance1 = point.distance(fCar.getPosition()); if (distance1 < distance) { nearestPoint = point; distance = distance1; } } f.next(); } if (nearestPoint != null) { fCar.setPosition(nearestPoint); } }
/** @see prefuse.render.AbstractShapeRenderer#getRawShape(prefuse.visual.VisualItem) */ @Override protected Shape getRawShape(VisualItem item) { EdgeItem e = (EdgeItem) item; VisualItem source = e.getSourceItem(); VisualItem target = e.getTargetItem(); int type = m_edgeType; int edgeIndex = -1; getAlignedPoint(m_tmpPoints[0], source.getBounds(), m_xAlign1, m_yAlign1); getAlignedPoint(m_tmpPoints[1], target.getBounds(), m_xAlign2, m_yAlign2); m_curWidth = (float) (m_width * getLineWidth(item)); boolean curveCtrlPtsReady = false; Polygon arrowHead; // create the arrow head, if needed if (isDirected(e) && m_edgeArrow != Constants.EDGE_ARROW_NONE && (arrowHead = getArrowHead(e)) != null) { // get starting and ending edge endpoints boolean forward = (m_edgeArrow == Constants.EDGE_ARROW_FORWARD); Point2D start = null, end = null; start = m_tmpPoints[forward ? 0 : 1]; end = m_tmpPoints[forward ? 1 : 0]; // compute the intersection with the source/target bounding box VisualItem src = getSourceItem(e, forward); VisualItem dest = getTargetItem(e, forward); if (edgeBounded && !e.isAggregating()) { adjustEndingPoint(start, end, src, dest); } else if (GraphicsLib.intersectLineRectangle(start, end, dest.getBounds(), m_isctPoints) > 0) { end.setLocation(m_isctPoints[0]); } // create the arrow head shape AffineTransform arrowTrans; if (multipleEdge) { edgeIndex = adjustEndingPointByMultipleEdge(e, start, end); if (lineForSingleEdge && edgeIndex < 0) { type = Constants.EDGE_TYPE_LINE; arrowTrans = getArrowTrans(start, end, m_curWidth); } else { getCurveControlPoints( edgeIndex, m_ctrlPoints, start.getX(), start.getY(), end.getX(), end.getY()); curveCtrlPtsReady = true; arrowTrans = getArrowTrans(m_ctrlPoints[0], end, m_curWidth); } } else { arrowTrans = getArrowTrans(start, end, m_curWidth); } m_curArrow = m_tmpArrow.set(arrowHead, arrowTrans); // update the endpoints for the edge shape // need to bias this by arrow head size adjustLineEndByArrowHead(e, end); arrowTrans.transform(end, end); } else { m_curArrow = null; if (edgeBounded && !e.isAggregating()) { adjustEndingPoint(m_tmpPoints[0], m_tmpPoints[1], source, target); } if (multipleEdge) { edgeIndex = adjustEndingPointByMultipleEdge(e, m_tmpPoints[0], m_tmpPoints[1]); if (lineForSingleEdge && edgeIndex < 0) { type = Constants.EDGE_TYPE_LINE; } else { getCurveControlPoints( edgeIndex, m_ctrlPoints, m_tmpPoints[0].getX(), m_tmpPoints[0].getY(), m_tmpPoints[1].getX(), m_tmpPoints[1].getY()); curveCtrlPtsReady = true; } } } // create the edge shape Shape shape = null; double sx = m_tmpPoints[0].getX(); double sy = m_tmpPoints[0].getY(); double ex = m_tmpPoints[1].getX(); double ey = m_tmpPoints[1].getY(); switch (type) { case Constants.EDGE_TYPE_LINE: m_line.setLine(sx, sy, ex, ey); shape = m_line; break; case Constants.EDGE_TYPE_CURVE: if (!curveCtrlPtsReady) { getCurveControlPoints(e, m_ctrlPoints, sx, sy, ex, ey); } m_quad.setCurve(sx, sy, m_ctrlPoints[0].getX(), m_ctrlPoints[0].getY(), ex, ey); shape = m_quad; break; default: throw new IllegalStateException("Unknown edge type"); } // return the edge shape return shape; }
public QuadCurve2D evaluate(QuadCurve2D v0, QuadCurve2D v1, float fraction) { double x1 = v0.getX1() + ((v1.getX1() - v0.getX1()) * fraction); double y1 = v0.getY1() + ((v1.getY1() - v0.getY1()) * fraction); double x2 = v0.getX2() + ((v1.getX2() - v0.getX2()) * fraction); double y2 = v0.getY2() + ((v1.getY2() - v0.getY2()) * fraction); double ctrlx = v0.getCtrlX() + ((v1.getCtrlX() - v0.getCtrlX()) * fraction); double ctrly = v0.getCtrlY() + ((v1.getCtrlY() - v0.getCtrlY()) * fraction); QuadCurve2D value = (QuadCurve2D) v0.clone(); value.setCurve(x1, y1, ctrlx, ctrly, x2, y2); return value; }