• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.jme3.math;
2 
3 import com.jme3.math.Spline.SplineType;
4 import java.util.List;
5 
6 /**
7  * This class offers methods to help with curves and surfaces calculations.
8  * @author Marcin Roguski (Kealthas)
9  */
10 public class CurveAndSurfaceMath {
11 	private static final float KNOTS_MINIMUM_DELTA = 0.0001f;
12 
13 	/**
14 	 * A private constructor is defined to avoid instatiation of this class.
15 	 */
CurveAndSurfaceMath()16 	private CurveAndSurfaceMath() {}
17 
18 	/**
19 	 * This method interpolates tha data for the nurbs curve.
20 	 * @param u
21 	 *            the u value
22 	 * @param nurbSpline
23 	 *            the nurbs spline definition
24 	 * @param store
25 	 *            the resulting point in 3D space
26 	 */
interpolateNurbs(float u, Spline nurbSpline, Vector3f store)27 	public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) {
28 		if (nurbSpline.getType() != SplineType.Nurb) {
29 			throw new IllegalArgumentException("Given spline is not of a NURB type!");
30 		}
31 		List<Vector3f> controlPoints = nurbSpline.getControlPoints();
32 		float[] weights = nurbSpline.getWeights();
33 		List<Float> knots = nurbSpline.getKnots();
34 		int controlPointAmount = controlPoints.size();
35 
36 		store.set(Vector3f.ZERO);
37 		float delimeter = 0;
38 		for (int i = 0; i < controlPointAmount; ++i) {
39 			float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots);
40 			store.addLocal(nurbSpline.getControlPoints().get(i)
41 					.mult(val));
42 			delimeter += val;
43 		}
44 		store.divideLocal(delimeter);
45 	}
46 
47 	/**
48 	 * This method interpolates tha data for the nurbs surface.
49 	 *
50 	 * @param u
51 	 *            the u value
52 	 * @param v
53 	 *            the v value
54 	 * @param controlPoints
55 	 *            the nurbs' control points
56 	 * @param knots
57 	 *            the nurbs' knots
58 	 * @param basisUFunctionDegree
59 	 *            the degree of basis U function
60 	 * @param basisVFunctionDegree
61 	 *            the degree of basis V function
62 	 * @param store
63 	 *            the resulting point in 3D space
64 	 */
interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots, int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store)65 	public static void interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots,
66 			int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store) {
67 		store.set(Vector3f.ZERO);
68 		float delimeter = 0;
69 		int vControlPointsAmount = controlPoints.size();
70 		int uControlPointsAmount = controlPoints.get(0).size();
71 		for (int i = 0; i < vControlPointsAmount; ++i) {
72 			for (int j = 0; j < uControlPointsAmount; ++j) {
73 				Vector4f controlPoint = controlPoints.get(i).get(j);
74 				float val = controlPoint.w
75 								* CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1])
76 								* CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]);
77 				store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val);
78 				delimeter += val;
79 			}
80 		}
81 		store.divideLocal(delimeter);
82 	}
83 
84 	/**
85 	 * This method prepares the knots to be used. If the knots represent non-uniform B-splines (first and last knot values are being
86 	 * repeated) it leads to NaN results during calculations. This method adds a small number to each of such knots to avoid NaN's.
87 	 * @param knots
88 	 *            the knots to be prepared to use
89 	 * @param basisFunctionDegree
90 	 *            the degree of basis function
91 	 */
92 	// TODO: improve this; constant delta may lead to errors if the difference between tha last repeated
93 	// point and the following one is lower than it
prepareNurbsKnots(List<Float> knots, int basisFunctionDegree)94 	public static void prepareNurbsKnots(List<Float> knots, int basisFunctionDegree) {
95 		float delta = KNOTS_MINIMUM_DELTA;
96 		float prevValue = knots.get(0).floatValue();
97 		for(int i=1;i<knots.size();++i) {
98 			float value = knots.get(i).floatValue();
99 			if(value<=prevValue) {
100 				value += delta;
101 				knots.set(i, Float.valueOf(value));
102 				delta += KNOTS_MINIMUM_DELTA;
103 			} else {
104 				delta = KNOTS_MINIMUM_DELTA;//reset the delta's value
105 			}
106 
107 			prevValue = value;
108 		}
109 	}
110 
111 	/**
112 	 * This method computes the base function value for the NURB curve.
113 	 * @param i
114 	 *            the knot index
115 	 * @param k
116 	 *            the base function degree
117 	 * @param t
118 	 *            the knot value
119 	 * @param knots
120 	 *            the knots' values
121 	 * @return the base function value
122 	 */
computeBaseFunctionValue(int i, int k, float t, List<Float> knots)123 	private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) {
124 		if (k == 1) {
125 			return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f;
126 		} else {
127 			return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) *
128 					CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots)
129 					+ (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) *
130 					CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots);
131 		}
132 	}
133 }
134