org.freehep.graphicsio.CubicToQuadPathConstructor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of freehep-graphicsio Show documentation
Show all versions of freehep-graphicsio Show documentation
FreeHEP GraphicsIO Base Library
// Copyright 2001-2004 FreeHEP
package org.freehep.graphicsio;
import java.awt.geom.Point2D;
import java.io.IOException;
/**
* Implements the Cubic Bezier Curve PathConstructor functionality in terms of
* Quadratic Bezier Curves
*
* Uses the same algorithm published as ActionScript (SWF) by Robert Penner:
*
* ========================== Cubic Bezier Drawing v1.1
* ========================== recursive quadratic approximation with adjustable
* tolerance
*
* March 4, 2004
*
* Robert Penner www.robertpenner.com/tools/bezier_cubic.zip file:
* bezier_draw_cubic.as ==========================
*
* @author Mark Donszelmann
* @version $Id: freehep-graphicsio/src/main/java/org/freehep/graphicsio/CubicToQuadPathConstructor.java efe5341792e9 2006/11/13 22:08:58 duns $
*/
public abstract class CubicToQuadPathConstructor extends
AbstractPathConstructor {
private double resolutionSq;
protected CubicToQuadPathConstructor(double resolution) {
super();
resolutionSq = resolution * resolution;
}
public void move(double x, double y) throws IOException {
currentX = x;
currentY = y;
}
public void line(double x, double y) throws IOException {
currentX = x;
currentY = y;
}
public void cubic(double x1, double y1, double x2, double y2, double x3,
double y3) throws IOException {
quadratify(new Point2D.Double(currentX, currentY), new Point2D.Double(
x1, y1), new Point2D.Double(x2, y2), new Point2D.Double(x3, y3));
currentX = x3;
currentY = y3;
}
public void closePath(double x0, double y0) throws IOException {
currentX = 0;
currentY = 0;
}
public static Point2D intersect(Point2D p1, Point2D p2, Point2D p3,
Point2D p4) {
double dx1 = p2.getX() - p1.getX();
double dx2 = p3.getX() - p4.getX();
// line are vertical
if ((dx1 == 0) && (dx2 == 0)) return null;
double dy1 = p2.getY() - p1.getY();
double dy2 = p3.getY() - p4.getY();
// line are horizontal
if ((dy1 == 0) && (dy2 == 0)) return null;
double m1 = (p2.getY() - p1.getY()) / dx1;
double m2 = (p3.getY() - p4.getY()) / dx2;
if (dx1 == 0) {
// infinity
return new Point2D.Double(p1.getX(), m2 * (p1.getX() - p4.getX())
+ p4.getY());
} else if (dx2 == 0) {
// infinity
return new Point2D.Double(p4.getX(), m1 * (p4.getX() - p1.getX())
+ p1.getY());
}
// lines are parallel
if (m1 == m2) return null;
double x = (-m2 * p4.getX() + p4.getY() + m1 * p1.getX() - p1.getY())
/ (m1 - m2);
double y = m1 * (x - p1.getX()) + p1.getY();
return new Point2D.Double(x, y);
}
public static Point2D midPoint(Point2D a, Point2D b) {
return new Point2D.Double((a.getX() + b.getX()) / 2.0, (a.getY() + b
.getY()) / 2.0);
}
public void quadratify(Point2D a, Point2D b, Point2D c, Point2D d)
throws IOException {
// find intersection between bezier arms
Point2D s = intersect(a, b, c, d);
if (s == null) return;
// find distance between the midpoints
double dx = (a.getX() + d.getX() + s.getX() * 4 - (b.getX() + c.getX()) * 3) * .125;
double dy = (a.getY() + d.getY() + s.getY() * 4 - (b.getY() + c.getY()) * 3) * .125;
// split curve if the quadratic isn't close enough
if (dx * dx + dy * dy > resolutionSq) {
Point2D p01 = midPoint(a, b);
Point2D p12 = midPoint(b, c);
Point2D p23 = midPoint(c, d);
Point2D p02 = midPoint(p01, p12);
Point2D p13 = midPoint(p12, p23);
Point2D p03 = midPoint(p02, p13);
// recursive call to subdivide curve
quadratify(a, p01, p02, p03);
quadratify(p03, p13, p23, d);
} else {
// end recursion by drawing quadratic bezier
quad(s.getX(), s.getY(), d.getX(), d.getY());
}
}
static class Test extends CubicToQuadPathConstructor {
public Test(double resolution) {
super(resolution);
}
public void quad(double x1, double y1, double x2, double y2) {
System.out.println("Quad: (" + currentX + ", " + currentY + ") ("
+ x1 + ", " + y1 + ") (" + x2 + ", " + y2 + ")");
currentX = x2;
currentY = y2;
}
}
public static void main(String[] args) throws Exception {
PathConstructor pc = new Test(0.5);
// A, B, C, D
pc.move(20, 20);
pc.cubic(20, 40, 40, 60, 60, 60);
// A, B, D, C
pc.move(20, 20);
pc.cubic(20, 40, 60, 60, 40, 60);
// Intersecting Curve
pc.move(183, 149);
pc.cubic(189, 291, 256, 347, 295, 244);
pc.cubic(334, 141, 286, 216, 214, 228);
pc.cubic(142, 240, 142, 256, 176, 284);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy