/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.video.util;
/**
* Utility class for calculating various types of curves.
*
* @author Ewout Prangsma
* @author peda
*/
public class Curves {
private static final int steps = 19;
private static final int steps2 = steps * 2;
private static final double subdiv_step = 1.0 / (steps + 1);
private static final double subdiv_step2 = subdiv_step * subdiv_step;
private static final double subdiv_step3 = subdiv_step2 * subdiv_step;
private static final double subdiv_mul3 = 3.0 * subdiv_step;
private static final double subdiv2_mul3 = 3.0 * subdiv_step2;
private static final double subdiv2_mul6 = 6.0 * subdiv_step2;
private static final double subdiv3_mul6 = 6.0 * subdiv_step3;
private static final double subdiv_mul2 = subdiv_step * 2;
private static final double subdiv2_mul2 = subdiv_step2 * 2;
/**
* Calculate the line points that make up the cubic curve described by
* (x0,y0)-(x3,y3)
*
* @param x0
* @param y0
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
* @param points The resulting points
* @return the number of points updated in points array
*/
public static int calculateCubicCurve(double x0, double y0, double x1, double y1, double x2,
double y2, double x3, double y3, double points[]) {
final int length = 42;
final int steps = (length / 2) - 1;
final double incr = 1.0 / steps;
int i = 0;
double t = 0.0;
for (int step = 0; step < steps; step++) {
double f0 = (1 - t) * (1 - t) * (1 - t);
double f1 = 3 * t * (1 - t) * (1 - t);
double f2 = 3 * t * t * (1 - t);
double f3 = t * t * t;
double new_x = f0 * x0 + f1 * x1 + f2 * x2 + f3 * x3;
double new_y = f0 * y0 + f1 * y1 + f2 * y2 + f3 * y3;
points[i++] = new_x;
points[i++] = new_y;
t += incr;
}
points[i++] = x3;
points[i++] = y3;
return length;
}
/**
* tried to eliminate the need of mult within the loop
*
* @param x0
* @param y0
* @param x1
* @param y1
* @param x2
* @param y2
* @param x3
* @param y3
* @param points The resulting points
* @return the number of points updated in points array
*/
public static int calculateCubicCurveOpt2(double x0, double y0, double x1, double y1,
double x2, double y2, double x3, double y3, double[] points) {
/*
* first derivative of the curve at point 0
*/
final double dpx = x1 - x0;
final double dpy = y1 - y0;
/*
* second derivative of the curve at point 0
*/
final double ddpx = x0 - x1 * 2.0 + x2;
final double ddpy = y0 - y1 * 2.0 + y2;
/*
* third derivative of the curve at point 0
*/
final double dddpx = (x1 - x2) * 3.0 - x0 + x3;
final double dddpy = (y1 - y2) * 3.0 - y0 + y3;
double fx = x0;
double fy = y0;
double dfx = dpx * subdiv_mul3 + ddpx * subdiv2_mul3 + dddpx * subdiv_step3;
double dfy = dpy * subdiv_mul3 + ddpy * subdiv2_mul3 + dddpy * subdiv_step3;
double ddfx = ddpx * subdiv2_mul6 + dddpx * subdiv3_mul6;
double ddfy = ddpy * subdiv2_mul6 + dddpy * subdiv3_mul6;
final double dddfx = dddpx * subdiv3_mul6;
final double dddfy = dddpy * subdiv3_mul6;
points[0] = x0;
points[1] = y0;
for (int i = 1; i <= steps; i++) {
fx += dfx;
fy += dfy;
dfx += ddfx;
dfy += ddfy;
ddfx += dddfx;
ddfy += dddfy;
points[i << 1] = fx;
points[(i << 1) + 1] = fy;
}
points[steps2 + 2] = x3;
points[steps2 + 3] = y3;
return 42;
}
/**
* Calculate the line points that make up the quadratic parametric curve
* described by (x0,y0)-(x2,y2)
*
* @param x0
* @param y0
* @param x1
* @param y1
* @param x2
* @param y2
* @param points The resulting points
* @return the number of points updated in points array
*/
public static int calculateQuadCurve(double x0, double y0, double x1, double y1, double x2,
double y2, double points[]) {
final int length = 42;
final int steps = (length / 2) - 1;
final double incr = 1.0 / steps;
int i = 0;
double t = 0.0;
for (int step = 0; step < steps; step++) {
double f0 = (1 - t) * (1 - t);
double f1 = 2 * t * (1 - t);
double f2 = t * t;
double new_x = f0 * x0 + f1 * x1 + f2 * x2;
double new_y = f0 * y0 + f1 * y1 + f2 * y2;
points[i++] = new_x;
points[i++] = new_y;
t += incr;
}
points[i++] = x2;
points[i++] = y2;
return length;
}
/**
* try to not do any mul within the loop
*
* @param x0
* @param y0
* @param x1
* @param y1
* @param x2
* @param y2
* @param points The resulting points
* @return the number of points updated in points array
*/
public static int calculateQuadCurveOpt2(double x0, double y0, double x1, double y1, double x2,
double y2, double points[]) {
/*
* first derivatives of the Curve at point 0
*/
final double dpx = x1 - x0;
final double dpy = y1 - y0;
/*
* second derivatives of the Curve at point 0
*/
final double ddpx = x2 + x0 - 2 * x1;
final double ddpy = y2 + y0 - 2 * y1;
/*
* the endpoints of the line
*/
double fx = x0;
double fy = y0;
double dfx = subdiv_mul2 * dpx + subdiv_step2 * ddpx;
double dfy = subdiv_mul2 * dpy + subdiv_step2 * ddpy;
final double ddfx = ddpx * subdiv2_mul2;
final double ddfy = ddpy * subdiv2_mul2;
points[0] = x0;
points[1] = y0;
for (int i = 1; i <= steps; i++) {
fx += dfx;
fy += dfy;
dfx += ddfx;
dfy += ddfy;
points[i << 1] = fx;
points[(i << 1) + 1] = fy;
}
points[steps2 + 2] = x2;
points[steps2 + 3] = y2;
return 42;
}
/**
* Subdivision by de'casteljau
*
* This implementation may look nicer but it is much slower, so forget it
* also I haven't been able to find a good estimation how many subdiv steps
* we need
*
* @param x0
* @param y0
* @param x1
* @param y1
* @param x2
* @param y2
* @param points The resulting points
*
* public static GeneralPath calculateQuadCurveOpt1(double x0, double y0,
* double x1, double y1, double x2, double y2) {
*
* GeneralPath result = new GeneralPath(); result.moveTo((float) x0, (float)
* y0); calculateQuadCurveRecursive(x0, y0, x1, y1, x2, y2, result);
*
* return result; }
*
* private static void calculateQuadCurveRecursive(double x0, double y0,
* double x1, double y1, double x2, double y2, GeneralPath result) {
* // try to estimate if we have to do a further subdivision double dx =
* x2-x0; double dy = y2-y0;
* /* double dist = Math.abs(((x1 - x2) * dy - (y1 - y2) * dx)); // if the
* distance from point 1 to the line (0 to 2) is less then one pixel //
* TODO: dist is not the distance as expected! if (dist < 2.0) {
* result.addDoubles(x1, y1); result.addDoubles(x2, y2); return; }
* // this is an alternativ to the first aproximation, don't know which one
* is faster or better yet :/ if ( ((dx*dx) + (dy*dy)) < 4 ) {
* result.lineTo((float) x2, (float) y2); return; }
* // calculate mid-points // this is only fast if l1a compiler uses fscale
* instead of fdiv!! double x01 = (x0 + x1) / 2; double y01 = (y0 + y1) / 2;
* double x12 = (x1 + x2) / 2; double y12 = (y1 + y2) / 2;
*
* double x012 = (x01 + x12) / 2; double y012 = (y01 + y12) / 2;
*
* calculateQuadCurveRecursive(x0, y0, x01, y01, x012, y012, result);
* calculateQuadCurveRecursive(x012, y012, x12, y12, x2, y2, result); }
*/
}