Home | History | Annotate | Download | only in curves
      1 package com.jme3.scene.plugins.blender.curves;
      2 
      3 import com.jme3.math.Vector3f;
      4 import com.jme3.scene.plugins.blender.file.DynamicArray;
      5 import com.jme3.scene.plugins.blender.file.Structure;
      6 import java.util.ArrayList;
      7 import java.util.List;
      8 
      9 /**
     10  * A class that helps to calculate the bezier curves calues. It uses doubles for performing calculations to minimize
     11  * floating point operations errors.
     12  * @author Marcin Roguski
     13  */
     14 public class BezierCurve {
     15 
     16     public static final int X_VALUE = 0;
     17     public static final int Y_VALUE = 1;
     18     public static final int Z_VALUE = 2;
     19     /**
     20      * The type of the curve. Describes the data it modifies.
     21      * Used in ipos calculations.
     22      */
     23     private int type;
     24     /** The dimension of the curve. */
     25     private int dimension;
     26     /** A table of the bezier points. */
     27     private float[][][] bezierPoints;
     28 
     29     @SuppressWarnings("unchecked")
     30     public BezierCurve(final int type, final List<Structure> bezTriples, final int dimension) {
     31         if (dimension != 2 && dimension != 3) {
     32             throw new IllegalArgumentException("The dimension of the curve should be 2 or 3!");
     33         }
     34         this.type = type;
     35         this.dimension = dimension;
     36         //first index of the bezierPoints table has the length of triples amount
     37         //the second index points to a table od three points of a bezier triple (handle, point, handle)
     38         //the third index specifies the coordinates of the specific point in a bezier triple
     39         bezierPoints = new float[bezTriples.size()][3][dimension];
     40         int i = 0, j, k;
     41         for (Structure bezTriple : bezTriples) {
     42             DynamicArray<Number> vec = (DynamicArray<Number>) bezTriple.getFieldValue("vec");
     43             for (j = 0; j < 3; ++j) {
     44                 for (k = 0; k < dimension; ++k) {
     45                     bezierPoints[i][j][k] = vec.get(j, k).floatValue();
     46                 }
     47             }
     48             ++i;
     49         }
     50     }
     51 
     52     /**
     53      * This method evaluates the data for the specified frame. The Y value is returned.
     54      * @param frame
     55      *        the frame for which the value is being calculated
     56      * @param valuePart
     57      *        this param specifies wheather we should return the X, Y or Z part of the result value; it should have
     58      *        one of the following values: X_VALUE - the X factor of the result Y_VALUE - the Y factor of the result
     59      *        Z_VALUE - the Z factor of the result
     60      * @return the value of the curve
     61      */
     62     public float evaluate(int frame, int valuePart) {
     63         for (int i = 0; i < bezierPoints.length - 1; ++i) {
     64             if (frame >= bezierPoints[i][1][0] && frame <= bezierPoints[i + 1][1][0]) {
     65                 float t = (frame - bezierPoints[i][1][0]) / (bezierPoints[i + 1][1][0] - bezierPoints[i][1][0]);
     66                 float oneMinusT = 1.0f - t;
     67                 float oneMinusT2 = oneMinusT * oneMinusT;
     68                 float t2 = t * t;
     69                 return bezierPoints[i][1][valuePart] * oneMinusT2 * oneMinusT + 3.0f * bezierPoints[i][2][valuePart] * t * oneMinusT2 + 3.0f * bezierPoints[i + 1][0][valuePart] * t2 * oneMinusT + bezierPoints[i + 1][1][valuePart] * t2 * t;
     70             }
     71         }
     72         if (frame < bezierPoints[0][1][0]) {
     73             return bezierPoints[0][1][1];
     74         } else { //frame>bezierPoints[bezierPoints.length-1][1][0]
     75             return bezierPoints[bezierPoints.length - 1][1][1];
     76         }
     77     }
     78 
     79     /**
     80      * This method returns the frame where last bezier triple center point of the bezier curve is located.
     81      * @return the frame number of the last defined bezier triple point for the curve
     82      */
     83     public int getLastFrame() {
     84         return (int) bezierPoints[bezierPoints.length - 1][1][0];
     85     }
     86 
     87     /**
     88      * This method returns the type of the bezier curve. The type describes the parameter that this curve modifies
     89      * (ie. LocationX or rotationW of the feature).
     90      * @return the type of the bezier curve
     91      */
     92     public int getType() {
     93         return type;
     94     }
     95 
     96     /**
     97      * This method returns a list of control points for this curve.
     98      * @return a list of control points for this curve.
     99      */
    100     public List<Vector3f> getControlPoints() {
    101         List<Vector3f> controlPoints = new ArrayList<Vector3f>(bezierPoints.length * 3);
    102         for (int i = 0; i < bezierPoints.length; ++i) {
    103             controlPoints.add(new Vector3f(bezierPoints[i][0][0], bezierPoints[i][0][1], bezierPoints[i][0][2]));
    104             controlPoints.add(new Vector3f(bezierPoints[i][1][0], bezierPoints[i][1][1], bezierPoints[i][1][2]));
    105             controlPoints.add(new Vector3f(bezierPoints[i][2][0], bezierPoints[i][2][1], bezierPoints[i][2][2]));
    106         }
    107         return controlPoints;
    108     }
    109 
    110     @Override
    111     public String toString() {
    112         StringBuilder sb = new StringBuilder("Bezier curve: ").append(type).append('\n');
    113         for (int i = 0; i < bezierPoints.length; ++i) {
    114             sb.append(this.toStringBezTriple(i)).append('\n');
    115         }
    116         return sb.toString();
    117     }
    118 
    119     /**
    120      * This method converts the bezier triple of a specified index into text.
    121      * @param tripleIndex
    122      *        index of the triple
    123      * @return text representation of the triple
    124      */
    125     private String toStringBezTriple(int tripleIndex) {
    126         if (this.dimension == 2) {
    127             return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ") ("
    128                     + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ") ("
    129                     + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ")]";
    130         } else {
    131             return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ", " + bezierPoints[tripleIndex][0][2] + ") ("
    132                     + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ", " + bezierPoints[tripleIndex][1][2] + ") ("
    133                     + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ", " + bezierPoints[tripleIndex][2][2] + ")]";
    134         }
    135     }
    136 }