X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Futils%2FPathUtils2.java;h=6a418a39c403cf191618632287a5ca0707ceeb9b;hb=452670c58399d8054872655841ebb6e66d9c6b6e;hp=2dfd0707c0666330d7cc5f00a1c3c951948991ef;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/PathUtils2.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/PathUtils2.java index 2dfd0707c..6a418a39c 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/PathUtils2.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/utils/PathUtils2.java @@ -1,586 +1,586 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.g2d.utils; - -import java.awt.Shape; -import java.awt.geom.CubicCurve2D; -import java.awt.geom.Line2D; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.QuadCurve2D; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -/** - * Path Utils. - *

- * A line segment (linear, quadratic or cubic bezier) is described - * with a double array. The length of the array describes its degree (4,6,8). - * The first 2 elements define start point and last 2 the end point. - * Points in the middle are bezier control points. - * - * @See {@link GeometryUtils} for more geometry related utilities - * @author Toni Kalajainen - */ -public class PathUtils2 { - - /** - * Get tangent of an bezier - * @param lineSegment bezier of n degrees - * @param degree 1..3 - * @param t 0..1 - * @return unit vector - */ - public static Point2D getLineTangent(Shape line, double t, Point2D pt) - { - double x=0, y=0; - if (line instanceof Line2D) - { - Line2D l = (Line2D) line; - x = l.getX1() - l.getX2(); - y = l.getY1() - l.getY2(); - } else if (line instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX(); - double p1y = l.getCtrlY(); - double p2x = l.getX2(); - double p2y = l.getY2(); - x = 2*t*(p0x - 2*p1x + p2x) + 2*(-p0x + p1x); - y = 2*t*(p0y - 2*p1y + p2y) + 2*(-p0y + p1y); - - } else if (line instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX1(); - double p1y = l.getCtrlY1(); - double p2x = l.getCtrlX2(); - double p2y = l.getCtrlY2(); - double p3x = l.getX2(); - double p3y = l.getY2(); - x = 3*(1-t)*(1-t)*(p1x-p2x) + 3*(p2x-p1x)*2*t*(1-t) + 3*(p3x-p0x)*t*t; - y = 3*(1-t)*(1-t)*(p1y-p0y) + 3*(p2y-p1y)*2*t*(1-t) + 3*(p3y-p2y)*t*t; - } else throw new IllegalArgumentException(); - - return new Point2D.Double(x, y); - } - - /** - * - * @param lineSegment - * @param t 0..1 - * @return - */ - public static Point2D getLinePos(Shape line, double t, Point2D pt) - { - assert(line!=null); - double x=0, y=0; - if (pt==null) pt = new Point2D.Double(); - - if (line instanceof Line2D) { - Line2D l = (Line2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getX2(); - double p1y = l.getY2(); - - x = p0x*(1-t) + t*p1x; - y = p0y*(1-t) + t*p1y; - } else - if (line instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX(); - double p1y = l.getCtrlY(); - double p2x = l.getX2(); - double p2y = l.getY2(); - - double c2x = p0x-2*p1x+p2x; - double c2y = p0y-2*p1y+p2y; - - double c1x = -2*p0x+2*p1x; - double c1y = -2*p0y+2*p1y; - - double c0x = p0x; - double c0y = p0y; - - x = t*t*c2x+t*c1x+c0x; - y = t*t*c2y+t*c1y+c0y; - } else if (line instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX1(); - double p1y = l.getCtrlY1(); - double p2x = l.getCtrlX2(); - double p2y = l.getCtrlY2(); - double p3x = l.getX2(); - double p3y = l.getY2(); - - x = (1-t)*(1-t)*(1-t)*p0x + 3*t*(1-t)*(1-t)*p1x + 3*t*t*(1-t)*p2x + t*t*t*p3x; - y = (1-t)*(1-t)*(1-t)*p0y + 3*t*(1-t)*(1-t)*p1y + 3*t*t*(1-t)*p2y + t*t*t*p3y; - } else throw new IllegalArgumentException(); - pt.setLocation(x, y); - - return pt; - } - - public static double getLineLength(Shape line) - { - if (line instanceof Line2D) { - Line2D l = (Line2D) line; - double dx = l.getX2() - l.getX1(); - double dy = l.getY2() - l.getY1(); - return Math.sqrt(dx*dx+dy*dy); - } - - // Quick'n'dirty approximation - // TODO Replace with accurate value - double result = 0; - Point2D prevPos = getLinePos(line, 0.0, null); - for (int i=0; i<10; i++) - { - double t = (double)(i+1)/10; - Point2D pos = getLinePos(line, t, null); - result += pos.distance(prevPos); - prevPos.setLocation(pos); - } - return result; - } - - public static int getLineDegree(Shape line) - { - if (line instanceof Line2D) return 1; - if (line instanceof QuadCurve2D) return 2; - if (line instanceof CubicCurve2D) return 3; - throw new IllegalArgumentException(line+" is not a shape"); - } - - - public static double[] toArray(Shape line) - { - if (line instanceof Line2D) { - Line2D l = (Line2D) line; - return new double[] {l.getX1(), l.getY1(), l.getX2(), l.getY2()}; - } - if (line instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) line; - return new double[] {l.getX1(), l.getY1(), l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()}; - } - if (line instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) line; - return new double[] {l.getX1(), l.getY1(), l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()}; - } - throw new IllegalArgumentException(line+" is not a shape"); - } - - public static Shape toShape(double dada[]) - { - if (dada.length==4) - return new Line2D.Double(dada[0], dada[1], dada[2], dada[3]); - if (dada.length==6) - return new QuadCurve2D.Double(dada[0], dada[1], dada[2], dada[3], dada[4], dada[5]); - if (dada.length==8) - return new CubicCurve2D.Double(dada[0], dada[1], dada[2], dada[3], dada[4], dada[5], dada[6], dada[7]); - throw new IllegalArgumentException(); - } - - public static void interpolatePaths(List l1, List l2, double t, Collection result) - { - if (l1.size()>l2.size()) { - List l_ = l1; - l1 = l2; - l2 = l_; - t = 1-t; - } - - int div = l2.size() / l1.size(); - int mod = l2.size() % l1.size(); - - int rightIndex = 0; - for (int i=0; i l1 = new ArrayList(); - ArrayList l2 = new ArrayList(); - toShapes(path1, l1); - toShapes(path2, l2); - ArrayList result = new ArrayList(); - interpolatePaths(l1, l2, t, result); - Path2D p = new Path2D.Double(); - appedToPath(p, result); - return p; - } - - public static Path2D interpolatePaths(Path2D path1, Path2D path2, double t) - { - return interpolatePaths(path1.getPathIterator(null), path2.getPathIterator(null), t); - } - - public static Shape interpolateLine(Shape l1, Shape l2, double t) - { - assert(t>=0 && t<=1); - if (t==0) return l1; - if (t==1) return l2; - - double[] a1 = toArray(l1); - double[] a2 = toArray(l2); - double[] res = PathUtils.interpolateLineSegment(a1, a2, t); - return toShape(res); - } - - public static void toShapes(PathIterator pi, Collection result) - { - Iterator i = toShapeIterator(pi); - while (i.hasNext()) { - Shape segment = i.next(); - result.add(segment); - } - } - - /** - * Returns an iterator that splits path into line shapes - * @param pi path iterator - * @return line segment iterator - */ - public static Iterator toShapeIterator(final PathIterator pi) - { - return new PathIteratorToShapeIterator(pi); - } - - private static class PathIteratorToShapeIterator implements Iterator - { - final PathIterator pi; - double lineTo[] = new double[6]; - double startPos[] = new double[2]; - double from[] = new double[2]; - int degree = 0; - PathIteratorToShapeIterator(PathIterator pi) { - this.pi = pi; - while(!pi.isDone()) { - int type = pi.currentSegment(lineTo); - pi.next(); - if (type == PathIterator.SEG_MOVETO) { - startPos[0] = from[0] = lineTo[0]; - startPos[1] = from[1] = lineTo[1]; - } - if (type == PathIterator.SEG_CLOSE) { - type = PathIterator.SEG_LINETO; - lineTo[0] = startPos[0]; - lineTo[1] = startPos[1]; - } - if (type>=PathIterator.SEG_LINETO && type<=PathIterator.SEG_CUBICTO) - { - degree = type; - // from == xx - break; - } - } - } - @Override - public boolean hasNext() { - return degree>0; - } - @Override - public Shape next() { - if (degree==0) return null; - Shape res = null; - if (degree==1) - res = new Line2D.Double(from[0], from[1], lineTo[0], lineTo[1]); - else if (degree==2) - res = new QuadCurve2D.Double(from[0], from[1], lineTo[0], lineTo[1], lineTo[2], lineTo[3]); - else if (degree==3) - res = new CubicCurve2D.Double(from[0], from[1], lineTo[0], lineTo[1], lineTo[2], lineTo[3], lineTo[4], lineTo[5]); - else throw new IllegalArgumentException(); - // traverse path iterator until end or until next segment is known - degree = 0; - from[0] = lineTo[0]; - from[1] = lineTo[1]; - while(!pi.isDone()) { - int type = pi.currentSegment(lineTo); - pi.next(); - if (type == PathIterator.SEG_MOVETO) { - startPos[0] = from[0] = lineTo[0]; - startPos[1] = from[1] = lineTo[1]; - } - if (type == PathIterator.SEG_CLOSE) { - type = PathIterator.SEG_LINETO; - lineTo[0] = startPos[0]; - lineTo[1] = startPos[1]; - } - if (type>=PathIterator.SEG_LINETO && type<=PathIterator.SEG_CUBICTO) - { - degree = type; - break; - } - } - return res; - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - - - - public static Shape subdiv_takeLeft(Shape line, double t) - { - if (t==1) return line; - if (line instanceof Line2D) { - Line2D l = (Line2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getX2(); - double p1y = l.getY2(); - double p1x_ = p0x*(1-t) + p1x*t; - double p1y_ = p0y*(1-t) + p1y*t; - - return new Line2D.Double( p0x, p0y, p1x_, p1y_ ); - } - - if (line instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX(); - double p1y = l.getCtrlY(); - double p2x = l.getX2(); - double p2y = l.getY2(); - double p1x_ = p0x*(1-t) + p1x*t; - double p1y_ = p0y*(1-t) + p1y*t; - - double q0x = p0x*(1-t) + p1x*t; - double q0y = p0y*(1-t) + p1y*t; - - double q1x = p1x*(1-t) + p2x*t; - double q1y = p1y*(1-t) + p2y*t; - - double p2x_ = q0x*(1-t) + q1x*t; - double p2y_ = q0y*(1-t) + q1y*t; - - return new QuadCurve2D.Double( p0x, p0y, p1x_, p1y_, p2x_, p2y_ ); - } - - if (line instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX1(); - double p1y = l.getCtrlY1(); - double p2x = l.getCtrlX2(); - double p2y = l.getCtrlY2(); - double p3x = l.getX2(); - double p3y = l.getY2(); - double p1x_ = p0x*(1-t) + p1x*t; - double p1y_ = p0y*(1-t) + p1y*t; - - double q0x = p0x*(1-t) + p1x*t; - double q0y = p0y*(1-t) + p1y*t; - - double q1x = p1x*(1-t) + p2x*t; - double q1y = p1y*(1-t) + p2y*t; - - double p2x_ = q0x*(1-t) + q1x*t; - double p2y_ = q0y*(1-t) + q1y*t; - - double q2x = p2x*(1-t) + p3x*t; - double q2y = p2y*(1-t) + p3y*t; - - double r0x = q0x*(1-t) + q1x*t; - double r0y = q0y*(1-t) + q1y*t; - - double r1x = q1x*(1-t) + q2x*t; - double r1y = q1y*(1-t) + q2y*t; - - double p3x_ = r0x*(1-t) + r1x*t; - double p3y_ = r0y*(1-t) + r1y*t; - - return new CubicCurve2D.Double(p0x, p0y, p1x_, p1y_, p2x_, p2y_, p3x_, p3y_); - } - - throw new IllegalArgumentException(); - } - - public static Shape subdiv_takeRight(Shape line, double t) - { - if (t==0) return line; - if (line instanceof Line2D) { - Line2D l = (Line2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getX2(); - double p1y = l.getY2(); - double p0x_ = p0x*(1-t) + p1x*t; - double p0y_ = p0y*(1-t) + p1y*t; - - return new Line2D.Double( p0x_, p0y_, p1x, p1y ); - } - - if (line instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) line; - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX(); - double p1y = l.getCtrlY(); - double p2x = l.getX2(); - double p2y = l.getY2(); - - double q0x = p0x*(1-t) + p1x*t; - double q0y = p0y*(1-t) + p1y*t; - - double q1x = p1x*(1-t) + p2x*t; - double q1y = p1y*(1-t) + p2y*t; - - double p2x_ = q0x*(1-t) + q1x*t; - double p2y_ = q0y*(1-t) + q1y*t; - - return new QuadCurve2D.Double( p2x_, p2y_, q1x, q1y, p2x, p2y ); - } - - - if (line instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) line; - - double p0x = l.getX1(); - double p0y = l.getY1(); - double p1x = l.getCtrlX1(); - double p1y = l.getCtrlY1(); - double p2x = l.getCtrlX2(); - double p2y = l.getCtrlY2(); - double p3x = l.getX2(); - double p3y = l.getY2(); - - double q0x = p0x*(1-t) + p1x*t; - double q0y = p0y*(1-t) + p1y*t; - - double q1x = p1x*(1-t) + p2x*t; - double q1y = p1y*(1-t) + p2y*t; - - double q2x = p2x*(1-t) + p3x*t; - double q2y = p2y*(1-t) + p3y*t; - - double r0x = q0x*(1-t) + q1x*t; - double r0y = q0y*(1-t) + q1y*t; - - double r1x = q1x*(1-t) + q2x*t; - double r1y = q1y*(1-t) + q2y*t; - - double p3x_ = r0x*(1-t) + r1x*t; - double p3y_ = r0y*(1-t) + r1y*t; - - return new CubicCurve2D.Double( p3x_, p3y_, r1x, r1y, q2x, q2y, p3x, p3y ); - } - - return null; - } - - - - /** - * Crops line segment into a smaller line segment - * @param line line segment - * @param t0 begin t - * @param t1 end t - * @return cropped line segment - */ - public static Shape subdiv(Shape line, double t0, double t1) - { - if (t0==0 && t1==1) return line; - Shape temp = subdiv_takeLeft(line, t1); - return subdiv_takeRight(temp, t0/t1); - } - - public static void appedToPath(Path2D p, Shape ... shapes) - { - for (Shape s : shapes) - { - Point2D cur = p.getCurrentPoint(); - if (s instanceof Line2D) { - Line2D l = (Line2D) s; - if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.lineTo(l.getX2(), l.getY2()); - } else if (s instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) s; - if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.quadTo(l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()); - } else if (s instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) s; - if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.curveTo(l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()); - } throw new IllegalArgumentException(); - } - } - public static void appedToPath(Path2D p, Collection shapes) - { - for (Shape s : shapes) - { - Point2D cur = p.getCurrentPoint(); - if (s instanceof Line2D) { - Line2D l = (Line2D) s; - if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.lineTo(l.getX2(), l.getY2()); - } else if (s instanceof QuadCurve2D) { - QuadCurve2D l = (QuadCurve2D) s; - if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.quadTo(l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()); - } else if (s instanceof CubicCurve2D) { - CubicCurve2D l = (CubicCurve2D) s; - if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) - p.moveTo(l.getX1(), l.getY1()); - p.curveTo(l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()); - } else throw new IllegalArgumentException(); - } - } - - - public static void main(String[] args) { - - } - - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g2d.utils; + +import java.awt.Shape; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.QuadCurve2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * Path Utils. + *

+ * A line segment (linear, quadratic or cubic bezier) is described + * with a double array. The length of the array describes its degree (4,6,8). + * The first 2 elements define start point and last 2 the end point. + * Points in the middle are bezier control points. + * + * @See {@link GeometryUtils} for more geometry related utilities + * @author Toni Kalajainen + */ +public class PathUtils2 { + + /** + * Get tangent of an bezier + * @param lineSegment bezier of n degrees + * @param degree 1..3 + * @param t 0..1 + * @return unit vector + */ + public static Point2D getLineTangent(Shape line, double t, Point2D pt) + { + double x=0, y=0; + if (line instanceof Line2D) + { + Line2D l = (Line2D) line; + x = l.getX1() - l.getX2(); + y = l.getY1() - l.getY2(); + } else if (line instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX(); + double p1y = l.getCtrlY(); + double p2x = l.getX2(); + double p2y = l.getY2(); + x = 2*t*(p0x - 2*p1x + p2x) + 2*(-p0x + p1x); + y = 2*t*(p0y - 2*p1y + p2y) + 2*(-p0y + p1y); + + } else if (line instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX1(); + double p1y = l.getCtrlY1(); + double p2x = l.getCtrlX2(); + double p2y = l.getCtrlY2(); + double p3x = l.getX2(); + double p3y = l.getY2(); + x = 3*(1-t)*(1-t)*(p1x-p2x) + 3*(p2x-p1x)*2*t*(1-t) + 3*(p3x-p0x)*t*t; + y = 3*(1-t)*(1-t)*(p1y-p0y) + 3*(p2y-p1y)*2*t*(1-t) + 3*(p3y-p2y)*t*t; + } else throw new IllegalArgumentException(); + + return new Point2D.Double(x, y); + } + + /** + * + * @param lineSegment + * @param t 0..1 + * @return + */ + public static Point2D getLinePos(Shape line, double t, Point2D pt) + { + assert(line!=null); + double x=0, y=0; + if (pt==null) pt = new Point2D.Double(); + + if (line instanceof Line2D) { + Line2D l = (Line2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getX2(); + double p1y = l.getY2(); + + x = p0x*(1-t) + t*p1x; + y = p0y*(1-t) + t*p1y; + } else + if (line instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX(); + double p1y = l.getCtrlY(); + double p2x = l.getX2(); + double p2y = l.getY2(); + + double c2x = p0x-2*p1x+p2x; + double c2y = p0y-2*p1y+p2y; + + double c1x = -2*p0x+2*p1x; + double c1y = -2*p0y+2*p1y; + + double c0x = p0x; + double c0y = p0y; + + x = t*t*c2x+t*c1x+c0x; + y = t*t*c2y+t*c1y+c0y; + } else if (line instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX1(); + double p1y = l.getCtrlY1(); + double p2x = l.getCtrlX2(); + double p2y = l.getCtrlY2(); + double p3x = l.getX2(); + double p3y = l.getY2(); + + x = (1-t)*(1-t)*(1-t)*p0x + 3*t*(1-t)*(1-t)*p1x + 3*t*t*(1-t)*p2x + t*t*t*p3x; + y = (1-t)*(1-t)*(1-t)*p0y + 3*t*(1-t)*(1-t)*p1y + 3*t*t*(1-t)*p2y + t*t*t*p3y; + } else throw new IllegalArgumentException(); + pt.setLocation(x, y); + + return pt; + } + + public static double getLineLength(Shape line) + { + if (line instanceof Line2D) { + Line2D l = (Line2D) line; + double dx = l.getX2() - l.getX1(); + double dy = l.getY2() - l.getY1(); + return Math.sqrt(dx*dx+dy*dy); + } + + // Quick'n'dirty approximation + // TODO Replace with accurate value + double result = 0; + Point2D prevPos = getLinePos(line, 0.0, null); + for (int i=0; i<10; i++) + { + double t = (double)(i+1)/10; + Point2D pos = getLinePos(line, t, null); + result += pos.distance(prevPos); + prevPos.setLocation(pos); + } + return result; + } + + public static int getLineDegree(Shape line) + { + if (line instanceof Line2D) return 1; + if (line instanceof QuadCurve2D) return 2; + if (line instanceof CubicCurve2D) return 3; + throw new IllegalArgumentException(line+" is not a shape"); + } + + + public static double[] toArray(Shape line) + { + if (line instanceof Line2D) { + Line2D l = (Line2D) line; + return new double[] {l.getX1(), l.getY1(), l.getX2(), l.getY2()}; + } + if (line instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) line; + return new double[] {l.getX1(), l.getY1(), l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()}; + } + if (line instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) line; + return new double[] {l.getX1(), l.getY1(), l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()}; + } + throw new IllegalArgumentException(line+" is not a shape"); + } + + public static Shape toShape(double dada[]) + { + if (dada.length==4) + return new Line2D.Double(dada[0], dada[1], dada[2], dada[3]); + if (dada.length==6) + return new QuadCurve2D.Double(dada[0], dada[1], dada[2], dada[3], dada[4], dada[5]); + if (dada.length==8) + return new CubicCurve2D.Double(dada[0], dada[1], dada[2], dada[3], dada[4], dada[5], dada[6], dada[7]); + throw new IllegalArgumentException(); + } + + public static void interpolatePaths(List l1, List l2, double t, Collection result) + { + if (l1.size()>l2.size()) { + List l_ = l1; + l1 = l2; + l2 = l_; + t = 1-t; + } + + int div = l2.size() / l1.size(); + int mod = l2.size() % l1.size(); + + int rightIndex = 0; + for (int i=0; i l1 = new ArrayList(); + ArrayList l2 = new ArrayList(); + toShapes(path1, l1); + toShapes(path2, l2); + ArrayList result = new ArrayList(); + interpolatePaths(l1, l2, t, result); + Path2D p = new Path2D.Double(); + appedToPath(p, result); + return p; + } + + public static Path2D interpolatePaths(Path2D path1, Path2D path2, double t) + { + return interpolatePaths(path1.getPathIterator(null), path2.getPathIterator(null), t); + } + + public static Shape interpolateLine(Shape l1, Shape l2, double t) + { + assert(t>=0 && t<=1); + if (t==0) return l1; + if (t==1) return l2; + + double[] a1 = toArray(l1); + double[] a2 = toArray(l2); + double[] res = PathUtils.interpolateLineSegment(a1, a2, t); + return toShape(res); + } + + public static void toShapes(PathIterator pi, Collection result) + { + Iterator i = toShapeIterator(pi); + while (i.hasNext()) { + Shape segment = i.next(); + result.add(segment); + } + } + + /** + * Returns an iterator that splits path into line shapes + * @param pi path iterator + * @return line segment iterator + */ + public static Iterator toShapeIterator(final PathIterator pi) + { + return new PathIteratorToShapeIterator(pi); + } + + private static class PathIteratorToShapeIterator implements Iterator + { + final PathIterator pi; + double lineTo[] = new double[6]; + double startPos[] = new double[2]; + double from[] = new double[2]; + int degree = 0; + PathIteratorToShapeIterator(PathIterator pi) { + this.pi = pi; + while(!pi.isDone()) { + int type = pi.currentSegment(lineTo); + pi.next(); + if (type == PathIterator.SEG_MOVETO) { + startPos[0] = from[0] = lineTo[0]; + startPos[1] = from[1] = lineTo[1]; + } + if (type == PathIterator.SEG_CLOSE) { + type = PathIterator.SEG_LINETO; + lineTo[0] = startPos[0]; + lineTo[1] = startPos[1]; + } + if (type>=PathIterator.SEG_LINETO && type<=PathIterator.SEG_CUBICTO) + { + degree = type; + // from == xx + break; + } + } + } + @Override + public boolean hasNext() { + return degree>0; + } + @Override + public Shape next() { + if (degree==0) return null; + Shape res = null; + if (degree==1) + res = new Line2D.Double(from[0], from[1], lineTo[0], lineTo[1]); + else if (degree==2) + res = new QuadCurve2D.Double(from[0], from[1], lineTo[0], lineTo[1], lineTo[2], lineTo[3]); + else if (degree==3) + res = new CubicCurve2D.Double(from[0], from[1], lineTo[0], lineTo[1], lineTo[2], lineTo[3], lineTo[4], lineTo[5]); + else throw new IllegalArgumentException(); + // traverse path iterator until end or until next segment is known + degree = 0; + from[0] = lineTo[0]; + from[1] = lineTo[1]; + while(!pi.isDone()) { + int type = pi.currentSegment(lineTo); + pi.next(); + if (type == PathIterator.SEG_MOVETO) { + startPos[0] = from[0] = lineTo[0]; + startPos[1] = from[1] = lineTo[1]; + } + if (type == PathIterator.SEG_CLOSE) { + type = PathIterator.SEG_LINETO; + lineTo[0] = startPos[0]; + lineTo[1] = startPos[1]; + } + if (type>=PathIterator.SEG_LINETO && type<=PathIterator.SEG_CUBICTO) + { + degree = type; + break; + } + } + return res; + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + + + + public static Shape subdiv_takeLeft(Shape line, double t) + { + if (t==1) return line; + if (line instanceof Line2D) { + Line2D l = (Line2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getX2(); + double p1y = l.getY2(); + double p1x_ = p0x*(1-t) + p1x*t; + double p1y_ = p0y*(1-t) + p1y*t; + + return new Line2D.Double( p0x, p0y, p1x_, p1y_ ); + } + + if (line instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX(); + double p1y = l.getCtrlY(); + double p2x = l.getX2(); + double p2y = l.getY2(); + double p1x_ = p0x*(1-t) + p1x*t; + double p1y_ = p0y*(1-t) + p1y*t; + + double q0x = p0x*(1-t) + p1x*t; + double q0y = p0y*(1-t) + p1y*t; + + double q1x = p1x*(1-t) + p2x*t; + double q1y = p1y*(1-t) + p2y*t; + + double p2x_ = q0x*(1-t) + q1x*t; + double p2y_ = q0y*(1-t) + q1y*t; + + return new QuadCurve2D.Double( p0x, p0y, p1x_, p1y_, p2x_, p2y_ ); + } + + if (line instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX1(); + double p1y = l.getCtrlY1(); + double p2x = l.getCtrlX2(); + double p2y = l.getCtrlY2(); + double p3x = l.getX2(); + double p3y = l.getY2(); + double p1x_ = p0x*(1-t) + p1x*t; + double p1y_ = p0y*(1-t) + p1y*t; + + double q0x = p0x*(1-t) + p1x*t; + double q0y = p0y*(1-t) + p1y*t; + + double q1x = p1x*(1-t) + p2x*t; + double q1y = p1y*(1-t) + p2y*t; + + double p2x_ = q0x*(1-t) + q1x*t; + double p2y_ = q0y*(1-t) + q1y*t; + + double q2x = p2x*(1-t) + p3x*t; + double q2y = p2y*(1-t) + p3y*t; + + double r0x = q0x*(1-t) + q1x*t; + double r0y = q0y*(1-t) + q1y*t; + + double r1x = q1x*(1-t) + q2x*t; + double r1y = q1y*(1-t) + q2y*t; + + double p3x_ = r0x*(1-t) + r1x*t; + double p3y_ = r0y*(1-t) + r1y*t; + + return new CubicCurve2D.Double(p0x, p0y, p1x_, p1y_, p2x_, p2y_, p3x_, p3y_); + } + + throw new IllegalArgumentException(); + } + + public static Shape subdiv_takeRight(Shape line, double t) + { + if (t==0) return line; + if (line instanceof Line2D) { + Line2D l = (Line2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getX2(); + double p1y = l.getY2(); + double p0x_ = p0x*(1-t) + p1x*t; + double p0y_ = p0y*(1-t) + p1y*t; + + return new Line2D.Double( p0x_, p0y_, p1x, p1y ); + } + + if (line instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) line; + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX(); + double p1y = l.getCtrlY(); + double p2x = l.getX2(); + double p2y = l.getY2(); + + double q0x = p0x*(1-t) + p1x*t; + double q0y = p0y*(1-t) + p1y*t; + + double q1x = p1x*(1-t) + p2x*t; + double q1y = p1y*(1-t) + p2y*t; + + double p2x_ = q0x*(1-t) + q1x*t; + double p2y_ = q0y*(1-t) + q1y*t; + + return new QuadCurve2D.Double( p2x_, p2y_, q1x, q1y, p2x, p2y ); + } + + + if (line instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) line; + + double p0x = l.getX1(); + double p0y = l.getY1(); + double p1x = l.getCtrlX1(); + double p1y = l.getCtrlY1(); + double p2x = l.getCtrlX2(); + double p2y = l.getCtrlY2(); + double p3x = l.getX2(); + double p3y = l.getY2(); + + double q0x = p0x*(1-t) + p1x*t; + double q0y = p0y*(1-t) + p1y*t; + + double q1x = p1x*(1-t) + p2x*t; + double q1y = p1y*(1-t) + p2y*t; + + double q2x = p2x*(1-t) + p3x*t; + double q2y = p2y*(1-t) + p3y*t; + + double r0x = q0x*(1-t) + q1x*t; + double r0y = q0y*(1-t) + q1y*t; + + double r1x = q1x*(1-t) + q2x*t; + double r1y = q1y*(1-t) + q2y*t; + + double p3x_ = r0x*(1-t) + r1x*t; + double p3y_ = r0y*(1-t) + r1y*t; + + return new CubicCurve2D.Double( p3x_, p3y_, r1x, r1y, q2x, q2y, p3x, p3y ); + } + + return null; + } + + + + /** + * Crops line segment into a smaller line segment + * @param line line segment + * @param t0 begin t + * @param t1 end t + * @return cropped line segment + */ + public static Shape subdiv(Shape line, double t0, double t1) + { + if (t0==0 && t1==1) return line; + Shape temp = subdiv_takeLeft(line, t1); + return subdiv_takeRight(temp, t0/t1); + } + + public static void appedToPath(Path2D p, Shape ... shapes) + { + for (Shape s : shapes) + { + Point2D cur = p.getCurrentPoint(); + if (s instanceof Line2D) { + Line2D l = (Line2D) s; + if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.lineTo(l.getX2(), l.getY2()); + } else if (s instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) s; + if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.quadTo(l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()); + } else if (s instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) s; + if (cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.curveTo(l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()); + } throw new IllegalArgumentException(); + } + } + public static void appedToPath(Path2D p, Collection shapes) + { + for (Shape s : shapes) + { + Point2D cur = p.getCurrentPoint(); + if (s instanceof Line2D) { + Line2D l = (Line2D) s; + if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.lineTo(l.getX2(), l.getY2()); + } else if (s instanceof QuadCurve2D) { + QuadCurve2D l = (QuadCurve2D) s; + if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.quadTo(l.getCtrlX(), l.getCtrlY(), l.getX2(), l.getY2()); + } else if (s instanceof CubicCurve2D) { + CubicCurve2D l = (CubicCurve2D) s; + if (cur==null || cur.getX()!=l.getX1() || cur.getY()!=l.getY1()) + p.moveTo(l.getX1(), l.getY1()); + p.curveTo(l.getCtrlX1(), l.getCtrlY1(), l.getCtrlX2(), l.getCtrlY2(), l.getX2(), l.getY2()); + } else throw new IllegalArgumentException(); + } + } + + + public static void main(String[] args) { + + } + + +}