[committed] PolylineCurve

Hey guys,



I needed another Curve, so i implemented the PolylineCurve, which is a polyline (a chain of N lines) and can be used like a Curve (CurveController, …)



I also created a suiting testcase.



Here's the patch:



Index: src/com/jme/curve/PolylineCurve.java
===================================================================
--- src/com/jme/curve/PolylineCurve.java   (revision 0)
+++ src/com/jme/curve/PolylineCurve.java   (revision 0)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2003-2009 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme.curve;
+
+import com.jme.intersection.CollisionResults;
+import com.jme.intersection.PickResults;
+import com.jme.math.Matrix3f;
+import com.jme.math.Ray;
+import com.jme.math.Vector3f;
+import com.jme.scene.Spatial;
+import com.jme.util.geom.BufferUtils;
+
+
+public class PolylineCurve extends Curve {
+
+  private Vector3f prev = new Vector3f();
+
+  private Vector3f next = new Vector3f();
+
+  private Vector3f temp = new Vector3f();
+
+  private static final long serialVersionUID = -1650585082935112089L;
+
+  private float[] percents;
+
+  private final Vector3f[] controlPoints;
+
+  private float totalLength;
+
+
+  /**
+   * Constructor instantiates a new <code>PolylineCurve</code> object. The control points that define the curve are
+   * supplied.
+   *
+   * @param name the name of the scene element. This is required for identification and comparision purposes.
+   * @param controlPoints the points that define the curve.
+   */
+  public PolylineCurve(String name, Vector3f[] controlPoints) {
+    super(name, controlPoints);
+    this.controlPoints = controlPoints;
+
+    float[] cummLengths = new float[controlPoints.length];
+    percents = new float[controlPoints.length];
+
+    // calculate length of curve up to control points
+    for (int i = 1; i < controlPoints.length; i++) {
+      cummLengths[i] = cummLengths[i - 1] + controlPoints[i].subtract(controlPoints[i - 1]).length();
+    } // for
+
+    // calculate place in percent on curve of all control points
+    totalLength = cummLengths[cummLengths.length - 1];
+    for (int i = 1; i < controlPoints.length; i++) {
+      percents[i] = (1f / totalLength) * cummLengths[i];
+    } // for
+  } // PolylineCurve
+
+
+  /**
+   * <code>getOrientation</code> calculates the rotation matrix for any given point along to the line to still be facing
+   * in the direction of the line.
+   *
+   * @param time the current time (between 0 and 1)
+   * @param precision how accurate to (i.e. the next time) to check against.
+   * @return the rotation matrix.
+   * @see com.jme.curve.Curve#getOrientation(float, float)
+   */
+  public Matrix3f getOrientation(float time, float precision) {
+    Matrix3f rotation = new Matrix3f();
+
+    // calculate tangent
+    Vector3f point = getPoint(time);
+    Vector3f tangent = point.subtract(getPoint(time + precision)).normalizeLocal();
+    // calculate normal
+    Vector3f tangent2 = getPoint(time - precision).subtract(point);
+    Vector3f normal = tangent.cross(tangent2).normalizeLocal();
+    // calculate binormal
+    Vector3f binormal = tangent.cross(normal).normalizeLocal();
+    // set columns
+    rotation.setColumn(0, tangent);
+    rotation.setColumn(1, normal);
+    rotation.setColumn(2, binormal);
+    return rotation;
+  }
+
+
+  /**
+   * <code>getOrientation</code> calculates the rotation matrix for any given point along to the line to still be facing
+   * in the direction of the line. A up vector is supplied, this keep the rotation matrix following the line, but
+   * insures the object's up vector is not drastically changed.
+   *
+   * @param time the current time (between 0 and 1)
+   * @param precision how accurate to (i.e. the next time) to check against.
+   * @return the rotation matrix.
+   * @see com.jme.curve.Curve#getOrientation(float, float)
+   */
+  public Matrix3f getOrientation(float time, float precision, Vector3f up) {
+    if (up == null) {
+      return getOrientation(time, precision);
+    }
+    Matrix3f rotation = new Matrix3f();
+    // calculate tangent
+    Vector3f tangent = getPoint(time).subtract(getPoint(time + precision)).normalizeLocal();
+    // calculate binormal
+    Vector3f binormal = tangent.cross(up).normalizeLocal();
+    // calculate normal
+    Vector3f normal = binormal.cross(tangent).normalizeLocal();
+    // set columns
+    rotation.setColumn(0, tangent);
+    rotation.setColumn(1, normal);
+    rotation.setColumn(2, binormal);
+    return rotation;
+  }
+
+
+  /*
+   * (non-Javadoc)
+   *
+   * @see com.jme.curve.Curve#getPoint(float)
+   */
+  @Override
+  public Vector3f getPoint(float time) {
+    return getPoint(time, new Vector3f());
+  }
+
+
+  @Override
+  public Vector3f getPoint(float time, Vector3f store) {
+    // first point
+    if (time <= 0 || controlPoints.length <= 1) {
+      BufferUtils.populateFromBuffer(store, getVertexBuffer(), 0);
+      return store;
+    } // if
+    // last point.
+    if (time >= 1) {
+      BufferUtils.populateFromBuffer(store, getVertexBuffer(), getVertexCount() - 1);
+      return store;
+    } // if
+
+    int i = 0;
+    while (time > percents[i]) {
+      i++;
+    } // while
+
+    // get the next and previous control point on the curve
+    BufferUtils.populateFromBuffer(next, getVertexBuffer(), i);
+    BufferUtils.populateFromBuffer(prev, getVertexBuffer(), i - 1);
+
+    temp.set(next);
+    temp.subtractLocal(prev);
+    store.set(prev);
+    store.addLocal(temp.normalizeLocal().multLocal(totalLength * (time - percents[i - 1])));
+
+    return store;
+  }
+
+
+  @Override
+  public void findCollisions(Spatial scene, CollisionResults results) {
+    // TODO Auto-generated method stub
+  }
+
+
+  @Override
+  public boolean hasCollision(Spatial scene, boolean checkTriangles) {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+
+  /*
+   * (non-Javadoc)
+   *
+   * @see com.jme.scene.Spatial#doPick(com.jme.math.Ray, com.jme.intersection.PickResults)
+   */
+  public void findPick(Ray toTest, PickResults results) {
+    // TODO Auto-generated method stub
+
+  }
+
+}
Index: src/jmetest/curve/TestPolylineCurve.java
===================================================================
--- src/jmetest/curve/TestPolylineCurve.java   (revision 0)
+++ src/jmetest/curve/TestPolylineCurve.java   (revision 0)
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2003-2009 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jmetest.curve;
+
+import com.jme.app.SimpleGame;
+import com.jme.bounding.BoundingSphere;
+import com.jme.curve.CurveController;
+import com.jme.curve.PolylineCurve;
+import com.jme.image.Texture;
+import com.jme.input.MouseInput;
+import com.jme.math.Vector3f;
+import com.jme.renderer.ColorRGBA;
+import com.jme.scene.Controller;
+import com.jme.scene.TriMesh;
+import com.jme.scene.shape.Box;
+import com.jme.scene.state.TextureState;
+import com.jme.scene.state.ZBufferState;
+import com.jme.util.TextureManager;
+import com.jme.util.geom.BufferUtils;
+
+/**
+ * <code>TestPolyCurve</code>
+ * @author Mark Powell
+ * @version $Id: TestBezierCurve.java 4130 2009-03-19 20:04:51Z blaine.dev $
+ */
+public class TestPolylineCurve extends SimpleGame {
+
+  private Vector3f up = new Vector3f(0, 1, 0);
+
+  public static void main(String[] args) {
+    TestPolylineCurve app = new TestPolylineCurve();
+    app.setConfigShowMode(ConfigShowMode.AlwaysShow);
+    app.start();
+  }
+
+  /* (non-Javadoc)
+   * @see com.jme.app.SimpleGame#initGame()
+   */
+  protected void simpleInitGame() {
+    MouseInput.get().setCursorVisible(true);
+    lightState.setEnabled(false); // by default for this demo
+    display.setTitle("Polyline Curve Test");
+
+    //create control Points
+    Vector3f[] points = new Vector3f[4];
+    points[0] = new Vector3f( -4, 0, 0);
+    points[1] = new Vector3f( -2, 3, 2);
+    points[2] = new Vector3f(2, -3, -2);
+    points[3] = new Vector3f(4, 0, 0);
+
+    PolylineCurve curve = new PolylineCurve("Curve", points);
+    curve.setSteps(256);
+    ColorRGBA[] colors = new ColorRGBA[4];
+    colors[0] = new ColorRGBA(0, 1, 0, 1);
+    colors[1] = new ColorRGBA(1, 0, 0, 1);
+    colors[2] = new ColorRGBA(1, 1, 0, 1);
+    colors[3] = new ColorRGBA(0, 0, 1, 1);
+    curve.setColorBuffer(BufferUtils.createFloatBuffer(colors));
+
+    Vector3f min = new Vector3f( -0.1f, -0.1f, -0.1f);
+    Vector3f max = new Vector3f(0.1f, 0.1f, 0.1f);
+
+    ZBufferState buf = display.getRenderer().createZBufferState();
+    buf.setEnabled(true);
+    buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
+
+    TriMesh t = new Box("Control 1", min, max);
+    t.setModelBound(new BoundingSphere());
+    t.updateModelBound();
+
+    t.setLocalTranslation(new Vector3f(points[0]));
+
+    TriMesh t2 = new Box("Control 2", min, max);
+    t2.setModelBound(new BoundingSphere());
+    t2.updateModelBound();
+
+    t2.setLocalTranslation(new Vector3f(points[1]));
+
+    TriMesh t3 = new Box("Control 3", min, max);
+    t3.setModelBound(new BoundingSphere());
+    t3.updateModelBound();
+
+    t3.setLocalTranslation(new Vector3f(points[2]));
+
+    TriMesh t4 = new Box("Control 4", min, max);
+    t4.setModelBound(new BoundingSphere());
+    t4.updateModelBound();
+
+    t4.setLocalTranslation(new Vector3f(points[3]));
+
+    TriMesh box = new Box("Controlled Box", min.mult(5), max.mult(5));
+    box.setModelBound(new BoundingSphere());
+    box.updateModelBound();
+
+    box.setLocalTranslation(new Vector3f(points[0]));
+
+    CurveController cc = new CurveController(curve, box);
+    box.addController(cc);
+    cc.setRepeatType(Controller.RT_CYCLE);
+    cc.setUpVector(up);
+    cc.setSpeed(0.5f);
+
+    TextureState ts = display.getRenderer().createTextureState();
+    ts.setEnabled(true);
+    ts.setTexture(
+        TextureManager.loadTexture(
+        TestPolylineCurve.class.getClassLoader().getResource(
+        "jmetest/data/images/Monkey.jpg"),
+        Texture.MinificationFilter.BilinearNearestMipMap,
+        Texture.MagnificationFilter.Bilinear));
+    box.setRenderState(ts);
+
+    rootNode.setRenderState(buf);
+    rootNode.attachChild(t);
+    rootNode.attachChild(t2);
+    rootNode.attachChild(t3);
+    rootNode.attachChild(t4);
+    rootNode.attachChild(box);
+    rootNode.attachChild(curve);
+
+  }
+}

good job!  :slight_smile:

Committed revision 4359