/* * @(#)PathWriter.java * * $Date: 2014-06-06 20:04:49 +0200 (P, 06 jún. 2014) $ * * Copyright (c) 2011 by Jeremy Wood. * All rights reserved. * * The copyright of this software is owned by Jeremy Wood. * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * Jeremy Wood. For details see accompanying license terms. * * This software is probably, but not necessarily, discussed here: * https://javagraphics.java.net/ * * That site should also contain the most recent official version * of this software. (See the SVN repository for more details.) */ package com.bric.geom; import java.awt.Shape; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; /** This object writes path data. * <P>With this abstract class you could filter shape data as it is * being written. The simplest extension of this is the * {@link GeneralPathWriter}. * * <P>This is designed to match the <code>GeneralPath</code> method * signatures. * */ public abstract class PathWriter { /** Adds a point to the path by moving to the specified coordinates. * * @param x the x-coordinate to move to * @param y the y-coordinate to move to */ public abstract void moveTo(float x,float y); /** Adds a point to the path by drawing a straight line from the current coordinates to the new specified coordinates. * * @param x the x-coordinate of the end point. * @param y the y-coordinate of the end point. */ public abstract void lineTo(float x,float y); /** Adds a curved segment, defined by two new points, to the path by drawing a Quadratic curve that intersects both the current coordinates and the coordinates (x2, y2), using the specified point (x1, y1) as a quadratic parametric control point. * * @param cx the x-coordinate of the control point. * @param cy the y-coordinate of the control point. * @param x the x-coordinate of the end point. * @param y the y-coordinate of the end point. */ public abstract void quadTo(float cx,float cy,float x,float y); /** 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. * * @param cx1 the x-coordinate of the first control point. * @param cy1 the y-coordinate of the first control point. * @param cx2 the x-coordinate of the second control point. * @param cy2 the y-coordinate of the second control point. * @param x the x-coordinate of the end point. * @param y the y-coordinate of the end point. * */ public abstract void curveTo(float cx1,float cy1,float cx2,float cy2,float x,float y); /** Closes the current subpath by drawing a straight line back to the coordinates of the last moveTo. */ public abstract void closePath(); /** This guarantees that this writer has flushed all currently written * information. * <P>For example, some writers may need to perform complex calculations * and re-organize shapes. Or some writers may simply be buffering * path instructions to better manage memory. Calling this method * guarantees that all path instructions be immediately processed. * <P>Because some writers may be manipulating path data you should * <i>not call this method</i> until all shape data has been written. * */ public abstract void flush(); /** Writes a shape. * <P>This iterates through the shape and makes the appropriate * calls to <code>moveTo()</code>, <code>curveTo()</code>, etc. * * @param s the shape to write. */ public void write(Shape s) { write(s.getPathIterator(null)); } /** Writes a path. * <P>This iterates through the path and makes the appropriate * calls to <code>moveTo()</code>, <code>curveTo()</code>, etc. * * @param i the path to write. */ public void write(PathIterator i) { float[] coords = new float[6]; int k; while(i.isDone()==false) { k = i.currentSegment(coords); if(k==PathIterator.SEG_MOVETO) { moveTo(coords[0],coords[1]); } else if(k==PathIterator.SEG_LINETO) { lineTo(coords[0],coords[1]); } else if(k==PathIterator.SEG_QUADTO) { quadTo(coords[0],coords[1],coords[2],coords[3]); } else if(k==PathIterator.SEG_CUBICTO) { curveTo(coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]); } else if(k==PathIterator.SEG_CLOSE) { closePath(); } else { throw new RuntimeException("Unexpected segment: "+k); } i.next(); } } /** This appends a cubic curve to the GeneralPath provided that ranges from t = t0 to t = t1. * This assumes that the path already ends at the point (ax*t0*t0*t0+bx*t0*t0+cx*t0+dx, ay*t0*t0*t0+by*t0*t0+cy*t0+dx). * @param path the path to append data to. * @param t0 the t-value for the beginning of this curve * @param t1 the t-value for the end of this curve * @param ax the coefficient for the (t^3) term of the x parametric equation * @param bx the coefficient for the (t^2) term of the x parametric equation * @param cx the coefficient for the t term of the x parametric equation * @param dx the constant for the x parametric equation. * @param ay the coefficient for the (t^3) term of the y parametric equation * @param by the coefficient for the (t^2) term of the y parametric equation * @param cy the coefficient for the t term of the y parametric equation * @param dy the constant for the y parametric equation. */ public static void cubicTo(GeneralPath path,double t0,double t1,double ax,double bx,double cx,double dx,double ay,double by,double cy,double dy) { cubicTo2(path,t0,t1,ax,bx,cx,dx,ay,by,cy,dy); } /** This appends a cubic curve to the PathWriter provided that ranges from t = t0 to t = t1. * This assumes that the path already ends at the point (ax*t0*t0*t0+bx*t0*t0+cx*t0+dx, ay*t0*t0*t0+by*t0*t0+cy*t0+dx). * @param path the path to append data to. * @param t0 the t-value for the beginning of this curve * @param t1 the t-value for the end of this curve * @param ax the coefficient for the (t^3) term of the x parametric equation * @param bx the coefficient for the (t^2) term of the x parametric equation * @param cx the coefficient for the t term of the x parametric equation * @param dx the constant for the x parametric equation. * @param ay the coefficient for the (t^3) term of the y parametric equation * @param by the coefficient for the (t^2) term of the y parametric equation * @param cy the coefficient for the t term of the y parametric equation * @param dy the constant for the y parametric equation. */ public static void cubicTo(PathWriter path,double t0,double t1,double ax,double bx,double cx,double dx,double ay,double by,double cy,double dy) { cubicTo2(path,t0,t1,ax,bx,cx,dx,ay,by,cy,dy); } private static void cubicTo2(Object obj,double t0,double t1,double ax,double bx,double cx,double dx,double ay,double by,double cy,double dy) { double tW = 2.0*t0/3.0+t1/3.0; double tZ = t0/3.0+2.0*t1/3.0; double f0 = ay*t0*t0*t0+by*t0*t0+cy*t0+dy; double f1 = ay*tW*tW*tW+by*tW*tW+cy*tW+dy; double f2 = ay*tZ*tZ*tZ+by*tZ*tZ+cy*tZ+dy; double f3 = ay*t1*t1*t1+by*t1*t1+cy*t1+dy; double dy2 = f0; double cy2 = (-11*f0+18*f1-9*f2+2*f3)/2.0; double by2 = (-19*f0+27*f2-8*f3-10*cy2)/4; double ay2 = f3-by2-cy2-f0; f0 = ax*t0*t0*t0+bx*t0*t0+cx*t0+dx; f1 = ax*tW*tW*tW+bx*tW*tW+cx*tW+dx; f2 = ax*tZ*tZ*tZ+bx*tZ*tZ+cx*tZ+dx; f3 = ax*t1*t1*t1+bx*t1*t1+cx*t1+dx; double dx2 = f0; double cx2 = (-11*f0+18*f1-9*f2+2*f3)/2.0; double bx2 = (-19*f0+27*f2-8*f3-10*cx2)/4; double ax2 = f3-bx2-cx2-f0; double cy0 = (3*dy2+cy2)/3; double cy1 = (by2-3*dy2+6*cy0)/3; double y1 = ay2+dy2-3*cy0+3*cy1; double cx0 = (3*dx2+cx2)/3; double cx1 = (bx2-3*dx2+6*cx0)/3; double x1 = ax2+dx2-3*cx0+3*cx1; if(obj instanceof GeneralPath) { ((GeneralPath)obj).curveTo((float)cx0, (float)cy0, (float)cx1, (float)cy1, (float)x1, (float)y1); } else if(obj instanceof PathWriter) { ((PathWriter)obj).curveTo((float)cx0, (float)cy0, (float)cx1, (float)cy1, (float)x1, (float)y1); } } /** This appends a quadratic curve to the GeneralPath provided that ranges from t = t0 to t = t1. * This assumes that the path already ends at the point (ax*t0*t0+bx*t0+cx, ay*t0*t0+by*t0+cy). * @param path the path to append data to. * @param t0 the t-value for the beginning of this curve * @param t1 the t-value for the end of this curve * @param ax the coefficient for the (t^2) term of the x parametric equation * @param bx the coefficient for the t term of the x parametric equation * @param cx the constant for the x parametric equation. * @param ay the coefficient for the (t^2) term of the y parametric equation * @param by the coefficient for the t term of the y parametric equation * @param cy the constant for the y parametric equation. */ public static void quadTo(GeneralPath path,double t0,double t1,double ax,double bx,double cx,double ay,double by,double cy) { quadTo2(path,t0,t1,ax,bx,cx,ay,by,cy); } /** This appends a quadratic curve to the PathWriter provided that ranges from t = t0 to t = t1. * This assumes that the path already ends at the point (ax*t0*t0+bx*t0+cx, ay*t0*t0+by*t0+cy). * @param path the path to append data to. * @param t0 the t-value for the beginning of this curve * @param t1 the t-value for the end of this curve * @param ax the coefficient for the (t^2) term of the x parametric equation * @param bx the coefficient for the t term of the x parametric equation * @param cx the constant for the x parametric equation. * @param ay the coefficient for the (t^2) term of the y parametric equation * @param by the coefficient for the t term of the y parametric equation * @param cy the constant for the y parametric equation. */ public static void quadTo(PathWriter path,double t0,double t1,double ax,double bx,double cx,double ay,double by,double cy) { quadTo2(path,t0,t1,ax,bx,cx,ay,by,cy); } private static void quadTo2(Object obj,double t0,double t1,double ax,double bx,double cx,double ay,double by,double cy) { double tZ = (t0+t1)/2.0; double f0 = ay*t0*t0+by*t0+cy; double f1 = ay*tZ*tZ+by*tZ+cy; double f2 = ay*t1*t1+by*t1+cy; double ay2 = 2*f2-4*f1+2*f0; double cy2 = f0; double by2 = f2-cy2-ay2; f0 = ax*t0*t0+bx*t0+cx; f1 = ax*tZ*tZ+bx*tZ+cx; f2 = ax*t1*t1+bx*t1+cx; double ax2 = 2*f2-4*f1+2*f0; double cx2 = f0; double bx2 = f2-cx2-ax2; double ctrlY = (2*cy2+by2)/2; double y1 = ay2-cy2+2*ctrlY; double ctrlX = (2*cx2+bx2)/2; double x1 = ax2-cx2+2*ctrlX; if(obj instanceof GeneralPath) { ((GeneralPath)obj).quadTo((float)ctrlX, (float)ctrlY, (float)x1, (float)y1); } else if(obj instanceof PathWriter) { ((PathWriter)obj).quadTo((float)ctrlX, (float)ctrlY, (float)x1, (float)y1); } } }