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