X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=blobdiff_plain;f=src2%2Ffr%2Forsay%2Flri%2Fvarna%2Fmodels%2Fgeom%2FCubicBezierCurve.java;fp=src2%2Ffr%2Forsay%2Flri%2Fvarna%2Fmodels%2Fgeom%2FCubicBezierCurve.java;h=7ff9aafba1317b94b9744deeeaeb3b32453d652a;hp=0000000000000000000000000000000000000000;hb=665d2c2f4c1310e6985b93b7c2c8a8eec2fa9086;hpb=0e684f72690bd6532272a39ab6c188a27559fd09 diff --git a/src2/fr/orsay/lri/varna/models/geom/CubicBezierCurve.java b/src2/fr/orsay/lri/varna/models/geom/CubicBezierCurve.java new file mode 100644 index 0000000..7ff9aaf --- /dev/null +++ b/src2/fr/orsay/lri/varna/models/geom/CubicBezierCurve.java @@ -0,0 +1,205 @@ +package fr.orsay.lri.varna.models.geom; + + +import java.awt.geom.Point2D; + +/** + * This class implements a cubic Bezier curve + * with a constant speed parametrization. + * The Bezier curve is approximated by a sequence of n straight lines, + * where the n+1 points between the lines are + * { B(k/n), k=0,1,...,n } where B is the standard + * parametrization given here: + * http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + * You can then use the constant speed parametrization over this sequence + * of straight lines. + * + * @author Raphael Champeimont + */ +public class CubicBezierCurve { + + /** + * The four points defining the curve. + */ + private Point2D.Double P0, P1, P2, P3; + + + + private int n; + /** + * The number of lines approximating the Bezier curve. + */ + public int getN() { + return n; + } + + + /** + * Get the (exact) length of the approximation curve. + */ + public double getApproxCurveLength() { + return lengths[n-1]; + } + + + + /** + * The n+1 points between the n lines. + */ + private Point2D.Double[] points; + + + + /** + * Array of length n. + * lengths[i] is the sum of lengths of lines up to and including the + * line starting at point points[i]. + */ + private double[] lengths; + + + /** + * Array of length n. + * The vectors along each line, with a norm of 1. + */ + private Point2D.Double[] unitVectors; + + + + /** + * The standard exact cubic Bezier curve parametrization. + * Argument t must be in [0,1]. + */ + public Point2D.Double standardParam(double t) { + double x = Math.pow(1-t,3) * P0.x + + 3 * Math.pow(1-t,2) * t * P1.x + + 3 * (1-t) * t * t * P2.x + + t * t * t * P3.x; + double y = Math.pow(1-t,3) * P0.y + + 3 * Math.pow(1-t,2) * t * P1.y + + 3 * (1-t) * t * t * P2.y + + t * t * t * P3.y; + return new Point2D.Double(x, y); + } + + + + + + /** + * Uniform approximated parameterization. + * A value in t must be in [0, getApproxCurveLength()]. + * We have built a function f such that f(t) is the position of + * the point on the approximation curve (n straight lines). + * The interesting property is that the length of the curve + * { f(t), t in [0,l] } is exactly l. + * The java function is simply the application of f over each element + * of a sorted array, ie. uniformParam(t)[k] = f(t[k]). + * Computation time is O(n+m) where n is the number of lines in which + * the curve is divided and m is the length of the array given as an + * argument. The use of a sorted array instead of m calls to the + * function enables us to have a complexity of O(n+m) instead of O(n*m) + * because we don't need to search in all the n possible lines for + * each value in t (as we know their are in increasing order). + */ + public Point2D.Double[] uniformParam(double[] t) { + int m = t.length; + Point2D.Double[] result = new Point2D.Double[m]; + int line = 0; + for (int i=0; i= n) { + // In theory should not happen, but float computation != math. + line = n-1; + } + if (t[i] < 0) { + throw (new IllegalArgumentException("t[" + i + "] < 0")); + } + // So now we know on which line we are + double lengthOnLine = t[i] - (line != 0 ? lengths[line-1] : 0); + double x = points[line].x + unitVectors[line].x * lengthOnLine; + double y = points[line].y + unitVectors[line].y * lengthOnLine; + result[i] = new Point2D.Double(x, y); + } + return result; + } + + + + /** + * A Bezier curve can be defined by four points, + * see http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + * Here we give this four points and a integer to say in how many + * line segments we want to cut the Bezier curve (if n is bigger + * the computation takes longer but the precision is better). + * The number of lines must be at least 1. + */ + public CubicBezierCurve( + Point2D.Double P0, + Point2D.Double P1, + Point2D.Double P2, + Point2D.Double P3, + int n) { + this.P0 = P0; + this.P1 = P1; + this.P2 = P2; + this.P3 = P3; + this.n = n; + if (n < 1) { + throw (new IllegalArgumentException("n must be at least 1")); + } + computeData(); + } + + + private void computeData() { + points = new Point2D.Double[n+1]; + for (int k=0; k<=n; k++) { + points[k] = standardParam(((double) k) / n); + } + + lengths = new double[n]; + unitVectors = new Point2D.Double[n]; + double sum = 0; + for (int i=0; i