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 }