OSDN Git Service

Revert CatmullRomSpline
authorXoppa <contact@xoppa.nl>
Thu, 14 Feb 2013 17:22:21 +0000 (18:22 +0100)
committerXoppa <contact@xoppa.nl>
Thu, 14 Feb 2013 17:22:21 +0000 (18:22 +0100)
gdx/src/com/badlogic/gdx/math/CatmullRom.java [new file with mode: 0644]
gdx/src/com/badlogic/gdx/math/CatmullRomSpline.java

diff --git a/gdx/src/com/badlogic/gdx/math/CatmullRom.java b/gdx/src/com/badlogic/gdx/math/CatmullRom.java
new file mode 100644 (file)
index 0000000..63c25cc
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package com.badlogic.gdx.math;
+
+import com.badlogic.gdx.utils.Array;
+
+/** @author Xoppa */
+public class CatmullRom<T extends Vector<T>> implements Path<T> {
+       /** Calculates the catmullrom value for the given position (t).
+        * @param out The Vector to set to the result.
+        * @param t The position (0<=t<=1) on the spline
+        * @param points The control points
+        * @param continuous If true the b-spline restarts at 0 when reaching 1
+        * @param tmp A temporary vector used for the calculation
+        * @return The value of out */
+       public static <T extends Vector<T>> T calculate(final T out, final float t, final T[] points, final boolean continuous, final T tmp) {
+               final int n = continuous ? points.length : points.length - 3;
+               float u = t * n;
+               int i = (t >= 1f) ? (n - 1) : (int)u;
+               u -= (float)i;
+               return calculate(out, i, u, points, continuous, tmp);
+       }
+       
+       /** Calculates the catmullrom value for the given span (i) at the given position (u).
+        * @param out The Vector to set to the result.
+        * @param i The span (0<=i<spanCount) spanCount = continuous ? points.length : points.length - degree
+        * @param u The position (0<=u<=1) on the span
+        * @param points The control points
+        * @param continuous If true the b-spline restarts at 0 when reaching 1
+        * @param tmp A temporary vector used for the calculation
+        * @return The value of out */
+       public static <T extends Vector<T>> T calculate(final T out, final int i, final float u, final T[] points, final boolean continuous, final T tmp) {
+               final int n = points.length;
+               final float u2 = u * u;
+               final float u3 = u2 * u;
+               out.set(points[i]).mul(1.5f * u3 - 2.5f * u2 + 1.0f);
+               if (continuous || i > 0) out.add(tmp.set(points[(n+i-1)%n]).mul(-0.5f * u3 + u2 - 0.5f * u));
+               if (continuous || i < (n - 1)) out.add(tmp.set(points[(i + 1)%n]).mul(-1.5f * u3 + 2f * u2 + 0.5f * u));
+               if (continuous || i < (n - 2)) out.add(tmp.set(points[(i + 2)%n]).mul(0.5f * u3 - 0.5f * u2));
+               return out;
+       }
+       
+       public T[] controlPoints;
+       public boolean continuous;
+       public int spanCount;
+       private T tmp;
+       
+       public CatmullRom() { }
+       public CatmullRom(final T[] controlPoints, final boolean continuous) {
+               set(controlPoints, continuous);
+       }
+       
+       public CatmullRom set(final T[] controlPoints, final boolean continuous) {
+               if (tmp == null)
+                       tmp = controlPoints[0].cpy();
+               this.controlPoints = controlPoints;
+               this.continuous = continuous;
+               this.spanCount = continuous ? controlPoints.length : controlPoints.length - 3;
+               return this;
+       }
+
+       @Override
+       public T valueAt (T out, float t) {
+               final int n = spanCount;
+               float u = t * n;
+               int i = (t >= 1f) ? (n - 1) : (int)u;
+               u -= (float)i;
+               return valueAt(out, i, u);
+       }
+       
+       /** @return The value of the spline at position u of the specified span */ 
+       public T valueAt(final T out, final int span, final float u) {
+               return calculate(out, continuous ? span : (span + 1), u, controlPoints, continuous, tmp);
+       }
+       
+       /** @return The span closest to the specified value */ 
+       public int nearest(final T in) {
+               return nearest(in, 0, spanCount);
+       }
+       
+       /** @return The span closest to the specified value, restricting to the specified spans. */
+       public int nearest(final T in, int start, final int count) {
+               while (start < 0) start += spanCount;
+               int result = start % spanCount;
+               float dst = in.dst2(controlPoints[result]);
+               for (int i = 1; i < count; i++) {
+                       final int idx = (start + i) % spanCount;
+                       final float d = in.dst2(controlPoints[idx]);
+                       if (d < dst) {
+                               dst = d;
+                               result = idx;
+                       }
+               }
+               return result;
+       }
+       
+       @Override
+       public float approximate (T v) {
+               return approximate(v, nearest(v));
+       }
+       
+       public float approximate(final T in, int start, final int count) {
+               return approximate(in, nearest(in, start, count));
+       }
+       
+       public float approximate(final T in, final int near) {
+               int n = near;
+               final T nearest = controlPoints[n];
+               final T previous = controlPoints[n>0?n-1:spanCount-1];
+               final T next = controlPoints[(n+1)%spanCount];
+               final float dstPrev2 = in.dst2(previous);
+               final float dstNext2 = in.dst2(next);
+               T P1, P2, P3;
+               if (dstNext2 < dstPrev2) {
+                       P1 = nearest;
+                       P2 = next;
+                       P3 = in;
+               } else {
+                       P1 = previous;
+                       P2 = nearest;
+                       P3 = in;
+                       n = n>0?n-1:spanCount-1;
+               }
+               float L1 = P1.dst(P2);
+               float L2 = P3.dst(P2);
+               float L3 = P3.dst(P1);
+               float s = (L2*L2 + L1*L1 - L3*L3) / (2*L1);
+               float u = MathUtils.clamp((L1-s)/L1, 0f, 1f);
+               return ((float)n + u) / spanCount;
+       }
+}
index 1537ad1..0f660c8 100644 (file)
 \r
 package com.badlogic.gdx.math;\r
 \r
-import com.badlogic.gdx.utils.Array;\r
-\r
-/** @author Xoppa */\r
-public class CatmullRomSpline<T extends Vector<T>> implements Path<T> {\r
-       /** Calculates the catmullrom value for the given position (t).\r
-        * @param out The Vector to set to the result.\r
-        * @param t The position (0<=t<=1) on the spline\r
-        * @param points The control points\r
-        * @param continuous If true the b-spline restarts at 0 when reaching 1\r
-        * @param tmp A temporary vector used for the calculation\r
-        * @return The value of out */\r
-       public static <T extends Vector<T>> T calculate(final T out, final float t, final T[] points, final boolean continuous, final T tmp) {\r
-               final int n = continuous ? points.length : points.length - 3;\r
-               float u = t * n;\r
-               int i = (t >= 1f) ? (n - 1) : (int)u;\r
-               u -= (float)i;\r
-               return calculate(out, i, u, points, continuous, tmp);\r
-       }\r
-       \r
-       /** Calculates the catmullrom value for the given span (i) at the given position (u).\r
-        * @param out The Vector to set to the result.\r
-        * @param i The span (0<=i<spanCount) spanCount = continuous ? points.length : points.length - degree\r
-        * @param u The position (0<=u<=1) on the span\r
-        * @param points The control points\r
-        * @param continuous If true the b-spline restarts at 0 when reaching 1\r
-        * @param tmp A temporary vector used for the calculation\r
-        * @return The value of out */\r
-       public static <T extends Vector<T>> T calculate(final T out, final int i, final float u, final T[] points, final boolean continuous, final T tmp) {\r
-               final int n = points.length;\r
-               final float u2 = u * u;\r
-               final float u3 = u2 * u;\r
-               out.set(points[i]).mul(1.5f * u3 - 2.5f * u2 + 1.0f);\r
-               if (continuous || i > 0) out.add(tmp.set(points[(n+i-1)%n]).mul(-0.5f * u3 + u2 - 0.5f * u));\r
-               if (continuous || i < (n - 1)) out.add(tmp.set(points[(i + 1)%n]).mul(-1.5f * u3 + 2f * u2 + 0.5f * u));\r
-               if (continuous || i < (n - 2)) out.add(tmp.set(points[(i + 2)%n]).mul(0.5f * u3 - 0.5f * u2));\r
-               return out;\r
-       }\r
-       \r
-       public T[] controlPoints;\r
-       public boolean continuous;\r
-       public int spanCount;\r
-       private T tmp;\r
-       \r
-       public CatmullRomSpline() { }\r
-       public CatmullRomSpline(final T[] controlPoints, final boolean continuous) {\r
-               set(controlPoints, continuous);\r
-       }\r
-       \r
-       public CatmullRomSpline set(final T[] controlPoints, final boolean continuous) {\r
-               if (tmp == null)\r
-                       tmp = controlPoints[0].cpy();\r
-               this.controlPoints = controlPoints;\r
-               this.continuous = continuous;\r
-               this.spanCount = continuous ? controlPoints.length : controlPoints.length - 3;\r
-               return this;\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/** Encapsulates a catmull rom spline with n control points, n >= 4. For more information on this type of spline see\r
+ * http://www.mvps.org/directx/articles/catmull/.\r
+ * \r
+ * @author badlogicgames@gmail.com */\r
+public class CatmullRomSpline implements Serializable {\r
+       private static final long serialVersionUID = -3290464799289771451L;\r
+       private List<Vector3> controlPoints = new ArrayList<Vector3>();\r
+       Vector3 T1 = new Vector3();\r
+       Vector3 T2 = new Vector3();\r
+\r
+       /** Adds a new control point\r
+        * \r
+        * @param point the point */\r
+       public void add (Vector3 point) {\r
+               controlPoints.add(point);\r
        }\r
 \r
-       @Override\r
-       public T valueAt (T out, float t) {\r
-               final int n = spanCount;\r
-               float u = t * n;\r
-               int i = (t >= 1f) ? (n - 1) : (int)u;\r
-               u -= (float)i;\r
-               return valueAt(out, i, u);\r
+       /** @return all control points */\r
+       public List<Vector3> getControlPoints () {\r
+               return controlPoints;\r
        }\r
-       \r
-       /** @return The value of the spline at position u of the specified span */ \r
-       public T valueAt(final T out, final int span, final float u) {\r
-               return calculate(out, continuous ? span : (span + 1), u, controlPoints, continuous, tmp);\r
+\r
+       /** Returns a path, between every two control points numPoints are generated and the control points themselves are added too.\r
+        * The first and the last controlpoint are omitted. if there's less than 4 controlpoints an empty path is returned.\r
+        * \r
+        * @param numPoints number of points returned for a segment\r
+        * @return the path */\r
+       public List<Vector3> getPath (int numPoints) {\r
+               ArrayList<Vector3> points = new ArrayList<Vector3>();\r
+\r
+               if (controlPoints.size() < 4) return points;\r
+\r
+               Vector3 T1 = new Vector3();\r
+               Vector3 T2 = new Vector3();\r
+\r
+               for (int i = 1; i <= controlPoints.size() - 3; i++) {\r
+                       points.add(controlPoints.get(i));\r
+                       float increment = 1.0f / (numPoints + 1);\r
+                       float t = increment;\r
+\r
+                       T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i - 1)).mul(0.5f);\r
+                       T2.set(controlPoints.get(i + 2)).sub(controlPoints.get(i)).mul(0.5f);\r
+\r
+                       for (int j = 0; j < numPoints; j++) {\r
+                               float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis\r
+                               // function 1\r
+                               float h2 = -2 * t * t * t + 3 * t * t; // calculate basis\r
+                               // function 2\r
+                               float h3 = t * t * t - 2 * t * t + t; // calculate basis\r
+                               // function 3\r
+                               float h4 = t * t * t - t * t; // calculate basis function 4\r
+\r
+                               Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);\r
+                               point.add(controlPoints.get(i + 1).tmp().mul(h2));\r
+                               point.add(T1.tmp().mul(h3));\r
+                               point.add(T2.tmp().mul(h4));\r
+                               points.add(point);\r
+                               t += increment;\r
+                       }\r
+               }\r
+\r
+               if (controlPoints.size() >= 4) points.add(controlPoints.get(controlPoints.size() - 2));\r
+\r
+               return points;\r
        }\r
-       \r
-       /** @return The span closest to the specified value */ \r
-       public int nearest(final T in) {\r
-               return nearest(in, 0, spanCount);\r
+\r
+       /** Returns a path, between every two control points numPoints are generated and the control points themselves are added too.\r
+        * The first and the last controlpoint are omitted. if there's less than 4 controlpoints an empty path is returned.\r
+        * \r
+        * @param points the array of Vector3 instances to store the path in\r
+        * @param numPoints number of points returned for a segment */\r
+       public void getPath (Vector3[] points, int numPoints) {\r
+               int idx = 0;\r
+               if (controlPoints.size() < 4) return;\r
+\r
+               for (int i = 1; i <= controlPoints.size() - 3; i++) {\r
+                       points[idx++].set(controlPoints.get(i));\r
+                       float increment = 1.0f / (numPoints + 1);\r
+                       float t = increment;\r
+\r
+                       T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i - 1)).mul(0.5f);\r
+                       T2.set(controlPoints.get(i + 2)).sub(controlPoints.get(i)).mul(0.5f);\r
+\r
+                       for (int j = 0; j < numPoints; j++) {\r
+                               float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis\r
+                               // function 1\r
+                               float h2 = -2 * t * t * t + 3 * t * t; // calculate basis\r
+                               // function 2\r
+                               float h3 = t * t * t - 2 * t * t + t; // calculate basis\r
+                               // function 3\r
+                               float h4 = t * t * t - t * t; // calculate basis function 4\r
+\r
+                               Vector3 point = points[idx++].set(controlPoints.get(i)).mul(h1);\r
+                               point.add(controlPoints.get(i + 1).tmp().mul(h2));\r
+                               point.add(T1.tmp().mul(h3));\r
+                               point.add(T2.tmp().mul(h4));\r
+                               t += increment;\r
+                       }\r
+               }\r
+\r
+               points[idx].set(controlPoints.get(controlPoints.size() - 2));\r
        }\r
-       \r
-       /** @return The span closest to the specified value, restricting to the specified spans. */\r
-       public int nearest(final T in, int start, final int count) {\r
-               while (start < 0) start += spanCount;\r
-               int result = start % spanCount;\r
-               float dst = in.dst2(controlPoints[result]);\r
-               for (int i = 1; i < count; i++) {\r
-                       final int idx = (start + i) % spanCount;\r
-                       final float d = in.dst2(controlPoints[idx]);\r
-                       if (d < dst) {\r
-                               dst = d;\r
-                               result = idx;\r
+\r
+       /** Returns all tangents for the points in a path. Same semantics as getPath.\r
+        * \r
+        * @param numPoints number of points returned for a segment\r
+        * @return the tangents of the points in the path */\r
+       public List<Vector3> getTangents (int numPoints) {\r
+               ArrayList<Vector3> tangents = new ArrayList<Vector3>();\r
+\r
+               if (controlPoints.size() < 4) return tangents;\r
+\r
+               Vector3 T1 = new Vector3();\r
+               Vector3 T2 = new Vector3();\r
+\r
+               for (int i = 1; i <= controlPoints.size() - 3; i++) {\r
+                       float increment = 1.0f / (numPoints + 1);\r
+                       float t = increment;\r
+\r
+                       T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i - 1)).mul(0.5f);\r
+                       T2.set(controlPoints.get(i + 2)).sub(controlPoints.get(i)).mul(0.5f);\r
+\r
+                       tangents.add(new Vector3(T1).nor());\r
+\r
+                       for (int j = 0; j < numPoints; j++) {\r
+                               float h1 = 6 * t * t - 6 * t; // calculate basis function 1\r
+                               float h2 = -6 * t * t + 6 * t; // calculate basis function 2\r
+                               float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3\r
+                               float h4 = 3 * t * t - 2 * t; // calculate basis function 4\r
+\r
+                               Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);\r
+                               point.add(controlPoints.get(i + 1).tmp().mul(h2));\r
+                               point.add(T1.tmp().mul(h3));\r
+                               point.add(T2.tmp().mul(h4));\r
+                               tangents.add(point.nor());\r
+                               t += increment;\r
                        }\r
                }\r
-               return result;\r
+\r
+               if (controlPoints.size() >= 4)\r
+                       tangents.add(T1.set(controlPoints.get(controlPoints.size() - 1)).sub(controlPoints.get(controlPoints.size() - 3))\r
+                               .mul(0.5f).cpy().nor());\r
+\r
+               return tangents;\r
        }\r
-       \r
-       @Override\r
-       public float approximate (T v) {\r
-               return approximate(v, nearest(v));\r
+\r
+       /** Returns all tangent's normals in 2D space for the points in a path. The controlpoints have to lie in the x/y plane for this\r
+        * to work. Same semantics as getPath.\r
+        * \r
+        * @param numPoints number of points returned for a segment\r
+        * @return the tangents of the points in the path */\r
+       public List<Vector3> getTangentNormals2D (int numPoints) {\r
+               ArrayList<Vector3> tangents = new ArrayList<Vector3>();\r
+\r
+               if (controlPoints.size() < 4) return tangents;\r
+\r
+               Vector3 T1 = new Vector3();\r
+               Vector3 T2 = new Vector3();\r
+\r
+               for (int i = 1; i <= controlPoints.size() - 3; i++) {\r
+                       float increment = 1.0f / (numPoints + 1);\r
+                       float t = increment;\r
+\r
+                       T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i - 1)).mul(0.5f);\r
+                       T2.set(controlPoints.get(i + 2)).sub(controlPoints.get(i)).mul(0.5f);\r
+\r
+                       Vector3 normal = new Vector3(T1).nor();\r
+                       float x = normal.x;\r
+                       normal.x = normal.y;\r
+                       normal.y = -x;\r
+                       tangents.add(normal);\r
+\r
+                       for (int j = 0; j < numPoints; j++) {\r
+                               float h1 = 6 * t * t - 6 * t; // calculate basis function 1\r
+                               float h2 = -6 * t * t + 6 * t; // calculate basis function 2\r
+                               float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3\r
+                               float h4 = 3 * t * t - 2 * t; // calculate basis function 4\r
+\r
+                               Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);\r
+                               point.add(controlPoints.get(i + 1).tmp().mul(h2));\r
+                               point.add(T1.tmp().mul(h3));\r
+                               point.add(T2.tmp().mul(h4));\r
+                               point.nor();\r
+                               x = point.x;\r
+                               point.x = point.y;\r
+                               point.y = -x;\r
+                               tangents.add(point);\r
+                               t += increment;\r
+                       }\r
+               }\r
+\r
+               return tangents;\r
        }\r
-       \r
-       public float approximate(final T in, int start, final int count) {\r
-               return approximate(in, nearest(in, start, count));\r
+\r
+       /** Returns the tangent's normals using the tangent and provided up vector doing a cross product.\r
+        * \r
+        * @param numPoints number of points per segment\r
+        * @param up up vector\r
+        * @return a list of tangent normals */\r
+       public List<Vector3> getTangentNormals (int numPoints, Vector3 up) {\r
+               List<Vector3> tangents = getTangents(numPoints);\r
+               ArrayList<Vector3> normals = new ArrayList<Vector3>();\r
+\r
+               for (Vector3 tangent : tangents)\r
+                       normals.add(new Vector3(tangent).crs(up).nor());\r
+\r
+               return normals;\r
        }\r
-       \r
-       public float approximate(final T in, final int near) {\r
-               int n = near;\r
-               final T nearest = controlPoints[n];\r
-               final T previous = controlPoints[n>0?n-1:spanCount-1];\r
-               final T next = controlPoints[(n+1)%spanCount];\r
-               final float dstPrev2 = in.dst2(previous);\r
-               final float dstNext2 = in.dst2(next);\r
-               T P1, P2, P3;\r
-               if (dstNext2 < dstPrev2) {\r
-                       P1 = nearest;\r
-                       P2 = next;\r
-                       P3 = in;\r
-               } else {\r
-                       P1 = previous;\r
-                       P2 = nearest;\r
-                       P3 = in;\r
-                       n = n>0?n-1:spanCount-1;\r
-               }\r
-               float L1 = P1.dst(P2);\r
-               float L2 = P3.dst(P2);\r
-               float L3 = P3.dst(P1);\r
-               float s = (L2*L2 + L1*L1 - L3*L3) / (2*L1);\r
-               float u = MathUtils.clamp((L1-s)/L1, 0f, 1f);\r
-               return ((float)n + u) / spanCount;\r
+\r
+       public List<Vector3> getTangentNormals (int numPoints, List<Vector3> up) {\r
+               List<Vector3> tangents = getTangents(numPoints);\r
+               ArrayList<Vector3> normals = new ArrayList<Vector3>();\r
+\r
+               int i = 0;\r
+               for (Vector3 tangent : tangents)\r
+                       normals.add(new Vector3(tangent).crs(up.get(i++)).nor());\r
+\r
+               return normals;\r
        }\r
 }\r