// Copyright 2001 FreeHEP. package org.freehep.graphicsio; import java.awt.geom.Point2D; import java.io.IOException; import java.util.Stack; /** * Implements cubics by approximating them using a polyline. Useful class for * output formats that do NOT implement bezier curves at all, or if you need * only straight lines. * * @author Mark Donszelmann * @version $Id: CubicToLinePathConstructor.java,v 1.5 2009-08-17 21:44:45 * murkle Exp $ */ public abstract class CubicToLinePathConstructor extends QuadToCubicPathConstructor { private double resolution; protected CubicToLinePathConstructor() { this(0.025); } protected CubicToLinePathConstructor(double resolution) { this.resolution = Math.abs(resolution); } @Override public void cubic(double x1, double y1, double x2, double y2, double x3, double y3) throws IOException { // ControlSets are written at the end Stack/* <ControlSet> */ controls = new Stack/* <ControlSet> */(); // System.out.println("Cubic "+x1+" "+y1+" "+x2+" "+y2+" "+x3+" "+y3); Point2D p0 = new Point2D.Double(currentX, currentY); Point2D p1 = new Point2D.Double(x1, y1); Point2D p2 = new Point2D.Double(x2, y2); Point2D p3 = new Point2D.Double(x3, y3); // ControlSets to create the controls Stack/* <ControlSet> */ temps = new Stack/* <ControlSet> */(); temps.push(new ControlSet(p0, p1, p2, p3)); while (!temps.empty()) { ControlSet control = (ControlSet) temps.pop(); if (control.breadth() > resolution) { temps.push(control); temps.push(control.bisect()); } else { controls.push(control); } } /* * tempSet[l++] = new ControlSet(p0, p1, p2, p3); while (l > 0) { * ControlSet control1 = tempSet[--l]; double b = control1.breadth(); if * (b > resolution) { ControlSet control3 = control1.bisect(); * tempSet[l++] = control1; tempSet[l++] = control3; } else { * controls.push(control1); } } */ // write out control sets // System.out.println(k); while (!controls.empty()) { Point2D p = ((ControlSet) controls.pop()).getPoint(); line(p.getX(), p.getY()); // System.out.println(control2.getPoint()); } // store currentX and currentY super.cubic(x1, y1, x2, y2, x3, y3); } class ControlSet { private Point2D point0; private Point2D point1; private Point2D point2; private Point2D point3; public ControlSet(Point2D p0, Point2D p1, Point2D p2, Point2D p3) { point0 = p0; point1 = p1; point2 = p2; point3 = p3; } public double breadth() { double f0 = point0.getX(); double f4 = point0.getY(); double f1 = point1.getX(); double f5 = point1.getY(); double f2 = point2.getX(); double f6 = point2.getY(); double f3 = point3.getX(); double f7 = point3.getY(); if ((Math.abs(f0 - f3) < resolution) && (Math.abs(f4 - f7) < resolution)) { double f8 = Math.abs(f1 - f0) + Math.abs(f5 - f4); double f10 = Math.abs(f2 - f0) + Math.abs(f6 - f4); return Math.max(f10, f8); } double d0 = f4 - f7; double d1 = f3 - f0; double f12 = Math.sqrt(d0 * d0 + d1 * d1); double d2 = f3 * f4 - f0 * f7; double f9 = Math.abs((d0 * f2 + d1 * f6) - d2) / f12; double f11 = Math.abs((d0 * f1 + d1 * f5) - d2) / f12; return Math.max(f9, f11); } public ControlSet bisect() { Point2D p0 = average(point0, point1); Point2D p1 = average(point1, point2); Point2D p2 = average(point2, point3); Point2D p3 = average(p0, p1); Point2D p4 = average(p1, p2); Point2D p5 = average(p3, p4); ControlSet controlset = new ControlSet(p5, p4, p2, point3); point1 = p0; point2 = p3; point3 = p5; return controlset; } public Point2D average(Point2D p1, Point2D p2) { return new Point2D.Double((p1.getX() + p2.getX()) / 2.0, (p1.getY() + p2.getY()) / 2.0); } public Point2D getPoint() { return point3; } } }