/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, Geomatys
*
* 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotoolkit.display3d.utils;
import javax.vecmath.Vector3d;
import java.util.List;
/**
*
* @author Thomas Rouby (Geomatys)
*/
public final class BezierCurve {
private BezierCurve(){}
public static double factoriel(int i){
double f = 1.0;
for (int j=2; j<=i; j++){
f *= j;
}
return f;
}
public static int[] pascalCoef(int ordre){
if (ordre < 0) return null;
final int[] tmp1 = new int[ordre+1];
final int[] tmp2 = new int[ordre+1];
tmp1[0] = tmp2[0] = 1;
for (int i=1; i <= ordre; i++){
for (int j=1; j<=i; j++){
tmp1[j] = tmp2[j];
tmp2[j] = tmp1[j-1]+tmp1[j];
}
}
return tmp2;
}
public static double bezierCoef(final int i, final int n, final double u){
return (factoriel(n)/(factoriel(i)*factoriel(n-i))) * Math.pow(u, i) * Math.pow(1-u, n-i);
}
public static Vector3d bezierCurve(final List<Vector3d> Pi, final double u){
Vector3d point = new Vector3d(0.0, 0.0, 0.0);
final int n = Pi.size()-1;
if (n >= 0){
final int[] pascalCoef = BezierCurve.pascalCoef(n);
for (int i=0; i<=n; i++){
final double coef = pascalCoef[i] * Math.pow(u, i) * Math.pow(1-u, n-i);
point.x += coef*Pi.get(i).x;
point.y += coef*Pi.get(i).y;
point.z += coef*Pi.get(i).z;
}
}
return point;
}
public static Vector3d bezierDerivativeCurve(final List<Vector3d> Pi, final double u){
Vector3d point = new Vector3d(0.0, 0.0, 0.0);
final int n = Pi.size()-1;
final int order = n-1;
if (n >= 0){
final int[] pascalCoef = BezierCurve.pascalCoef(order);
for (int i=0; i<=order; i++){
final double coef = pascalCoef[i] * Math.pow(u, i) * Math.pow(1-u, order-i);
final Vector3d Qi = new Vector3d();
Qi.sub(Pi.get(i+1), Pi.get(i));
Qi.scale(n);
point.x += coef*Qi.x;
point.y += coef*Qi.y;
point.z += coef*Qi.z;
}
}
return point;
}
public static Vector3d bezierSecondCurve(final List<Vector3d> Pi, final double u){
Vector3d point = new Vector3d(0.0, 0.0, 0.0);
final int n = Pi.size()-1;
final int order = n-2;
if (n >= 0){
final int[] pascalCoef = BezierCurve.pascalCoef(order);
for (int i=0; i<=order; i++){
final double coef = pascalCoef[i] * Math.pow(u, i) * Math.pow(1-u, order-i);
final Vector3d Qi0 = new Vector3d();
Qi0.sub(Pi.get(i+1), Pi.get(i));
Qi0.scale(n);
final Vector3d Qi1 = new Vector3d();
Qi1.sub(Pi.get(i+2), Pi.get(i+1));
Qi1.scale(n);
final Vector3d Ri = new Vector3d();
Ri.sub(Qi1, Qi0);
Ri.scale(n);
point.x += coef*Ri.x;
point.y += coef*Ri.y;
point.z += coef*Ri.z;
}
}
return point;
}
}