/** * Draws a corner relative to the current point of the GeneralPath. Note the radius denotes the * distance from the cornerPoint to where the curve starts on the line formed from the cornerPoint * to the current point on the gp and where the curve ends on the line from the cornerPoint to the * nextCornerPoint. In other words, */ private static void makeCornerTo( GeneralPath gp, Point2D cornerPoint, Point2D nextCornerPoint, float radius) { Point2D currentPoint = gp.getCurrentPoint(); // get fractional to the corner where the line first starts to curve double distance = currentPoint.distance(cornerPoint); double fraction = (distance - radius) / distance; // calculate these distance from the current point double xDistance = (cornerPoint.getX() - currentPoint.getX()) * fraction; double yDistance = (cornerPoint.getY() - currentPoint.getY()) * fraction; // draw a line to the point where the line first starts to curve lineToRelative(gp, (float) xDistance, (float) yDistance); Point2D startCurvePoint = gp.getCurrentPoint(); // get fractional to the corner where the line first starts to curve double distanceFromCornerToNextCorner = cornerPoint.distance(nextCornerPoint); double fractionToNextCorner = radius / distanceFromCornerToNextCorner; // calculate these distance from the current point double xDistanceFromCornerToEndCurve = (nextCornerPoint.getX() - cornerPoint.getX()) * fractionToNextCorner; double yDistanceFromCornerToEndCurve = (nextCornerPoint.getY() - cornerPoint.getY()) * fractionToNextCorner; Point2D endCurvePoint = new Point2D.Double( cornerPoint.getX() + xDistanceFromCornerToEndCurve, cornerPoint.getY() + yDistanceFromCornerToEndCurve); // finally draw the cornerShape cornerShape( gp, // start at: (float) startCurvePoint.getX(), (float) startCurvePoint.getY(), // corner at: (float) cornerPoint.getX(), (float) cornerPoint.getY(), // end at: (float) endCurvePoint.getX(), (float) endCurvePoint.getY()); // System.out.println("StartCurve at: " + startCurvePoint); // System.out.println("Corner at: " + cornerPoint); // System.out.println("EndCurve at: " + endCurvePoint); // System.out.println("NextCorner at: " + nextCornerPoint); }
/** * Draws a curve segment relative to the current point of the GeneralPath. * * <p>Adds a curved segment, defined by three new points, to the path by drawing a Bezier curve * that intersects both the current coordinates and the coordinates (x3, y3), using the specified * points (x1, y1) and (x2, y2) as Bezier control points. */ public static void curveTo( GeneralPath gp, float x1, float y1, float x2, float y2, float x3, float y3) { Point2D currentPoint = gp.getCurrentPoint(); gp.curveTo( x1 + (float) currentPoint.getX(), y1 + (float) currentPoint.getY(), x2 + (float) currentPoint.getX(), y2 + (float) currentPoint.getY(), x3 + (float) currentPoint.getX(), y3 + (float) currentPoint.getY()); }
private void addToGeneralPath(Point2D q, boolean lineTo) { Point2D p = gp.getCurrentPoint(); if (p != null && p.distance(q) < TOLERANCE) { return; } if (lineTo && p != null) { try { gp.lineTo((float) q.getX(), (float) q.getY()); } catch (Exception e) { gp.moveTo((float) q.getX(), (float) q.getY()); } } else { gp.moveTo((float) q.getX(), (float) q.getY()); } }
/** * if the edge is reflexive its painted as a cyclic edge if there are 2 controlpoints the * connection is painted as a straight line from the source to the targetanchor if there are more * as 2 controlpoints the connection path between 2 control points is painted as bezier curve */ @Override protected void paintWidget() { List<Point> contrPoints = this.getControlPoints(); int listSize = contrPoints.size(); Graphics2D gr = getGraphics(); if (listSize <= 2) { if (isReflexive()) { // special case for reflexive connection widgets Widget related = this.getTargetAnchor().getRelatedWidget(); int position = this.edgeBalance(related); Rectangle bounds = related.convertLocalToScene(related.getBounds()); gr.setColor(getLineColor()); Point first = new Point(); Point last = new Point(); double centerX = bounds.getCenterX(); first.x = (int) (centerX + bounds.width / 4); first.y = bounds.y + bounds.height; last.x = first.x; last.y = bounds.y; gr.setStroke(this.getStroke()); double cutDistance = this.getTargetAnchorShape().getCutDistance(); double anchorAngle = Math.PI / -3.0; double cutX = Math.abs(Math.cos(anchorAngle) * cutDistance); double cutY = Math.abs(Math.sin(anchorAngle) * cutDistance); int ydiff = first.y - last.y; int endy = -ydiff; double height = bounds.getHeight(); double cy = height / 4.0; double cx = bounds.getWidth() / 5.0; double dcx = cx * 2; GeneralPath gp = new GeneralPath(); gp.moveTo(0, 0); gp.quadTo(0, cy, cx, cy); gp.quadTo(dcx, cy, dcx, -height / 2.0); gp.quadTo(dcx, endy - cy, cy, -(cy + ydiff)); gp.quadTo(cutX * 1.5, endy - cy, cutX, endy - cutY); AffineTransform af = new AffineTransform(); AnchorShape anchorShape = this.getTargetAnchorShape(); if (position < 0) { first.x = (int) (centerX - bounds.width / 4); af.translate(first.x, first.y); af.scale(-1.0, 1.0); last.x = first.x; } else { af.translate(first.x, first.y); } Shape s = gp.createTransformedShape(af); gr.draw(s); if (last != null) { AffineTransform previousTransform = gr.getTransform(); gr.translate(last.x, last.y); if (position < 0) gr.rotate(Math.PI - anchorAngle); else gr.rotate(anchorAngle); anchorShape.paint(gr, false); gr.setTransform(previousTransform); } } else { super.paintWidget(); } return; } // bezier curve... GeneralPath curvePath = new GeneralPath(); Point lastControlPoint = null; double lastControlPointRotation = 0.0; Point prev = null; for (int i = 0; i < listSize - 1; i++) { Point cur = contrPoints.get(i); Point next = contrPoints.get(i + 1); Point nextnext = null; if (i < listSize - 2) { nextnext = contrPoints.get(i + 2); } double len = cur.distance(next); double scale = len * BEZIER_SCALE; Point bezierFrom = null; // first ControlPoint Point bezierTo = null; // second ControlPoint if (prev == null) { // first point curvePath.moveTo(cur.x, cur.y); // startpoint bezierFrom = cur; } else { bezierFrom = new Point(next.x - prev.x, next.y - prev.y); bezierFrom = scaleVector(bezierFrom, scale); bezierFrom.translate(cur.x, cur.y); } if (nextnext == null) { // next== last point (curve to) lastControlPoint = next; bezierTo = next; // set 2nd intermediate point to endpoint GeneralPath lastseg = this.subdivide(cur, bezierFrom, bezierTo, next); if (lastseg != null) curvePath.append(lastseg, true); break; } else { bezierTo = new Point(cur.x - nextnext.x, cur.y - nextnext.y); bezierTo = scaleVector(bezierTo, scale); bezierTo.translate(next.x, next.y); } curvePath.curveTo( bezierFrom.x, bezierFrom.y, // controlPoint1 bezierTo.x, bezierTo.y, // controlPoint2 next.x, next.y); prev = cur; } Point2D cur = curvePath.getCurrentPoint(); Point next = lastControlPoint; lastControlPointRotation = // anchor anchorAngle Math.atan2(cur.getY() - next.y, cur.getX() - next.x); Color previousColor = gr.getColor(); gr.setColor(getLineColor()); Stroke s = this.getStroke(); gr.setStroke(s); gr.setColor(this.getLineColor()); gr.draw(curvePath); AffineTransform previousTransform = gr.getTransform(); gr.translate(lastControlPoint.x, lastControlPoint.y); gr.rotate(lastControlPointRotation); AnchorShape targetAnchorShape = this.getTargetAnchorShape(); targetAnchorShape.paint(gr, false); gr.setTransform(previousTransform); // paint ControlPoints if enabled if (isPaintControlPoints()) { int last = listSize - 1; for (int index = 0; index <= last; index++) { Point point = contrPoints.get(index); previousTransform = gr.getTransform(); gr.translate(point.x, point.y); if (index == 0 || index == last) getEndPointShape().paint(gr); else getControlPointShape().paint(gr); gr.setTransform(previousTransform); } } gr.setColor(previousColor); }
/** * Appends path gp2 to gp1. Taken from pre-redesign code. * * @param reversed is true if the segments are added in reverse order */ public static void appendPath(GeneralPath gp1, GeneralPath gp2, boolean reversed) { ArrayList<Number[]> points = new ArrayList< Number[]>(); // Each element is an array consisting of one Integer and six Floats PathIterator i = gp2.getPathIterator(new AffineTransform()); float[] segment = new float[] {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; float leftmost = Float.POSITIVE_INFINITY; while (!i.isDone()) { int type = i.currentSegment(segment); i.next(); points.add( new Number[] { new Integer(type), new Float(segment[0]), new Float(segment[1]), new Float(segment[2]), new Float(segment[3]), new Float(segment[4]), new Float(segment[5]) }); } if (reversed) { float deltaX = (float) gp1.getCurrentPoint().getX(); float deltaY = (float) gp1.getCurrentPoint().getY(); Object[] typeAndPoints = points.get(points.size() - 1); int type = ((Integer) typeAndPoints[0]).intValue(); if (type == PathIterator.SEG_LINETO) { deltaX -= ((Float) typeAndPoints[1]).floatValue(); deltaY -= ((Float) typeAndPoints[2]).floatValue(); } else if (type == PathIterator.SEG_QUADTO) { deltaX -= ((Float) typeAndPoints[3]).floatValue(); deltaY -= ((Float) typeAndPoints[4]).floatValue(); } else if (type == PathIterator.SEG_CUBICTO) { deltaX -= ((Float) typeAndPoints[5]).floatValue(); deltaY -= ((Float) typeAndPoints[6]).floatValue(); } else { assert false : type; } for (int j = points.size() - 1; j >= 1; j--) { typeAndPoints = points.get(j); type = ((Integer) typeAndPoints[0]).intValue(); float x1 = ((Float) typeAndPoints[1]).floatValue(); float y1 = ((Float) typeAndPoints[2]).floatValue(); float x2 = ((Float) typeAndPoints[3]).floatValue(); float y2 = ((Float) typeAndPoints[4]).floatValue(); float prevX = 0.0f, prevY = 0.0f; int prevType = ((Integer) points.get(j - 1)[0]).intValue(); if ((prevType == PathIterator.SEG_MOVETO) || (prevType == PathIterator.SEG_LINETO)) { prevX = ((Float) points.get(j - 1)[1]).floatValue(); prevY = ((Float) points.get(j - 1)[2]).floatValue(); } else if (prevType == PathIterator.SEG_QUADTO) { prevX = ((Float) points.get(j - 1)[3]).floatValue(); prevY = ((Float) points.get(j - 1)[4]).floatValue(); } else if (prevType == PathIterator.SEG_CUBICTO) { prevX = ((Float) points.get(j - 1)[5]).floatValue(); prevY = ((Float) points.get(j - 1)[6]).floatValue(); } else { assert false : prevType; } leftmost = Math.min(leftmost, prevX + deltaX); if ((type == PathIterator.SEG_MOVETO) || (type == PathIterator.SEG_LINETO)) { gp1.lineTo(prevX + deltaX, prevY + deltaY); } else if (type == PathIterator.SEG_QUADTO) { gp1.quadTo(x1 + deltaX, y1 + deltaY, prevX + deltaX, prevY + deltaY); } else if (type == PathIterator.SEG_CUBICTO) { gp1.curveTo( x2 + deltaX, y2 + deltaY, x1 + deltaX, y1 + deltaY, prevX + deltaX, prevY + deltaY); } else { assert false : type; } } } else // Not reversed { float deltaX = (float) gp1.getCurrentPoint().getX() - ((Float) points.get(0)[1]).floatValue(); float deltaY = (float) gp1.getCurrentPoint().getY() - ((Float) points.get(0)[2]).floatValue(); for (int j = 1; j < points.size(); j++) { Object[] typeAndPoints = points.get(j); int type = ((Integer) typeAndPoints[0]).intValue(); float x1 = ((Float) typeAndPoints[1]).floatValue(); float y1 = ((Float) typeAndPoints[2]).floatValue(); float x2 = ((Float) typeAndPoints[3]).floatValue(); float y2 = ((Float) typeAndPoints[4]).floatValue(); float x3 = ((Float) typeAndPoints[5]).floatValue(); float y3 = ((Float) typeAndPoints[6]).floatValue(); if (type == PathIterator.SEG_MOVETO) { } else if (type == PathIterator.SEG_LINETO) { gp1.lineTo(x1 + deltaX, y1 + deltaY); leftmost = Math.min(leftmost, x1 + deltaX); } else if (type == PathIterator.SEG_QUADTO) { gp1.quadTo(x1 + deltaX, y1 + deltaY, x2 + deltaX, y2 + deltaY); leftmost = Math.min(leftmost, x2 + deltaX); } else if (type == PathIterator.SEG_CUBICTO) { gp1.curveTo(x1 + deltaX, y1 + deltaY, x2 + deltaX, y2 + deltaY, x3 + deltaX, y3 + deltaY); leftmost = Math.min(leftmost, x3 + deltaX); } else { assert false : type; } } } }
/** Draws a line segment relative to the current point of the GeneralPath. */ public static void lineToRelative(GeneralPath gp, float x, float y) { Point2D currentPoint = gp.getCurrentPoint(); gp.lineTo((float) currentPoint.getX() + x, (float) currentPoint.getY() + y); }