Package com.ardor3d.scenegraph.shape

Source Code of com.ardor3d.scenegraph.shape.Extrusion

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.scenegraph.shape;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import com.ardor3d.math.Quaternion;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.IndexMode;
import com.ardor3d.scenegraph.IndexBufferData;
import com.ardor3d.scenegraph.Line;
import com.ardor3d.scenegraph.Mesh;
import com.ardor3d.util.geom.BufferUtils;

/**
* An extrusion of a 2D object ({@link Line}) along a path (List of Vector3). Either a convenience constructor can be
* used or the {@link #updateGeometry} method. It is also capable of doing a cubic spline interpolation for a list of
* supporting points
*/
public class Extrusion extends Mesh {

    /**
     * Default Constructor. Creates an empty Extrusion.
     *
     * @see #updateGeometry(Line, List, Vector3)
     * @see #updateGeometry(Line, List, boolean, Vector3)
     * @see #updateGeometry(Line, List, int, Vector3)
     * @see #updateGeometry(Line, List, int, boolean, Vector3)
     */
    public Extrusion() {}

    /**
     * Creates an empty named Extrusion.
     *
     * @param name
     *            name
     * @see #updateGeometry(Line, List, Vector3)
     * @see #updateGeometry(Line, List, boolean, Vector3)
     * @see #updateGeometry(Line, List, int, Vector3)
     * @see #updateGeometry(Line, List, int, boolean, Vector3)
     */
    public Extrusion(final String name) {
        super(name);
    }

    /**
     * Convenience constructor. Calls {@link #updateGeometry(Line, List, Vector3)}.
     *
     * @param shape
     *            see {@link #updateGeometry(Line, List, Vector3)}
     * @param path
     *            see {@link #updateGeometry(Line, List, Vector3)}
     * @param up
     *            up vector
     */
    public Extrusion(final Line shape, final List<ReadOnlyVector3> path, final ReadOnlyVector3 up) {
        updateGeometry(shape, path, up);
    }

    /**
     * Convenience constructor. Sets the name and calls {@link #updateGeometry(Line, List, Vector3)}.
     *
     * @param name
     *            name
     * @param shape
     *            see {@link #updateGeometry(Line, List, Vector3)}
     * @param path
     *            see {@link #updateGeometry(Line, List, Vector3)}
     * @param up
     *            up vector
     */
    public Extrusion(final String name, final Line shape, final List<ReadOnlyVector3> path, final ReadOnlyVector3 up) {
        super(name);
        updateGeometry(shape, path, up);
    }

    /**
     * Update vertex, color, index and texture buffers (0) to contain an extrusion of shape along path.
     *
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param path
     *            a list of vectors that describe the path the shape should be extruded
     * @param up
     *            up vector
     */
    public void updateGeometry(final Line shape, final List<ReadOnlyVector3> path, final ReadOnlyVector3 up) {
        updateGeometry(shape, path, false, up);
    }

    /**
     * Update vertex, color, index and texture buffers (0) to contain an extrusion of shape along path.
     *
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param path
     *            a list of vectors that describe the path the shape should be extruded
     * @param closed
     *            true to connect first and last point
     * @param up
     *            up vector
     */
    public void updateGeometry(final Line shape, final List<ReadOnlyVector3> path, final boolean closed,
            final ReadOnlyVector3 up) {
        final FloatBuffer shapeBuffer = shape.getMeshData().getVertexBuffer();
        final FloatBuffer shapeNormalBuffer = shape.getMeshData().getNormalBuffer();

        final int numVertices = path.size() * shapeBuffer.limit();

        FloatBuffer vertices;
        if (_meshData.getVertexBuffer() != null && _meshData.getVertexBuffer().limit() == numVertices) {
            vertices = _meshData.getVertexBuffer();
            vertices.rewind();
        } else {
            vertices = BufferUtils.createFloatBuffer(numVertices);
        }

        FloatBuffer normals = null;
        if (shapeNormalBuffer != null) {
            if (_meshData.getNormalBuffer() != null && _meshData.getNormalBuffer().limit() == numVertices) {
                normals = _meshData.getNormalBuffer();
                normals.rewind();
            } else {
                normals = BufferUtils.createFloatBuffer(numVertices);
            }
        }

        final int numIndices = (path.size() - 1) * 2 * shapeBuffer.limit();
        IndexBufferData<?> indices;
        if (_meshData.getIndices() != null && _meshData.getIndices().limit() == numIndices) {
            indices = _meshData.getIndices();
            indices.rewind();
        } else {
            indices = BufferUtils.createIndexBufferData(numIndices, numVertices - 1);
        }

        final IndexMode indexMode = shape.getMeshData().getIndexMode(0);

        final int shapeVertices = shapeBuffer.limit() / 3;
        final Vector3 vector = new Vector3();
        final Vector3 direction = new Vector3();
        final Quaternion rotation = new Quaternion();

        for (int i = 0; i < path.size(); i++) {
            final ReadOnlyVector3 point = path.get(i);
            shapeBuffer.rewind();
            if (shapeNormalBuffer != null) {
                shapeNormalBuffer.rewind();
            }
            int shapeVertice = 0;
            do {
                final ReadOnlyVector3 nextPoint = i < path.size() - 1 ? path.get(i + 1) : closed ? path.get(0) : null;
                final ReadOnlyVector3 lastPoint = i > 0 ? path.get(i - 1) : null;
                if (nextPoint != null) {
                    direction.set(nextPoint).subtractLocal(point);
                } else {
                    direction.set(point).subtractLocal(lastPoint);
                }
                rotation.lookAt(direction, up);

                if (shapeNormalBuffer != null && normals != null) {
                    vector.set(shapeNormalBuffer.get(), shapeNormalBuffer.get(), shapeNormalBuffer.get());
                    rotation.apply(vector, vector);
                    normals.put(vector.getXf());
                    normals.put(vector.getYf());
                    normals.put(vector.getZf());
                }

                vector.set(shapeBuffer.get(), shapeBuffer.get(), shapeBuffer.get());
                rotation.apply(vector, vector);
                vector.addLocal(point);
                vertices.put(vector.getXf());
                vertices.put(vector.getYf());
                vertices.put(vector.getZf());

                if (indexMode != IndexMode.Lines || (shapeVertice & 1) == 0) {
                    if (i < path.size() - 1) {
                        if (shapeBuffer.hasRemaining()) {
                            indices.put(i * shapeVertices + shapeVertice);
                            indices.put(i * shapeVertices + shapeVertice + 1);
                            indices.put((i + 1) * shapeVertices + shapeVertice);

                            indices.put((i + 1) * shapeVertices + shapeVertice + 1);
                            indices.put((i + 1) * shapeVertices + shapeVertice);
                            indices.put(i * shapeVertices + shapeVertice + 1);
                        } else if (indexMode == IndexMode.LineLoop) {
                            indices.put(i * shapeVertices + shapeVertice);
                            indices.put(i * shapeVertices + shapeVertice + 1);
                            indices.put((i + 1) * shapeVertices + shapeVertice);

                            indices.put(i * shapeVertices + shapeVertice);
                            indices.put((i - 1) * shapeVertices + shapeVertice + 1);
                            indices.put(i * shapeVertices + shapeVertice + 1);
                        }
                    } else if (closed) {
                        indices.put(i * shapeVertices + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                        indices.put(0 + shapeVertice);

                        indices.put(0 + shapeVertice + 1);
                        indices.put(0 + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                    }
                }
                shapeVertice++;
            } while (shapeBuffer.hasRemaining());
        }

        _meshData.setVertexBuffer(vertices);
        if (normals != null) {
            _meshData.setNormalBuffer(normals);
        }
        _meshData.setIndices(indices);
    }

    /**
     * Performs cubic spline interpolation to find a path through the supporting points where the second derivative is
     * zero. Then calls {@link #updateGeometry(Line, List, Vector3)} with this path.
     *
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param points
     *            a list of supporting points for the spline interpolation
     * @param segments
     *            number of resulting path segments per supporting point
     * @param up
     *            up vector
     */
    public void updateGeometry(final Line shape, final List<ReadOnlyVector3> points, final int segments,
            final ReadOnlyVector3 up) {
        updateGeometry(shape, points, segments, false, up);
    }

    /**
     * Performs cubic spline interpolation to find a path through the supporting points where the second derivative is
     * zero. Then calls {@link #updateGeometry(Line, List, boolean, Vector3)} with this path.
     *
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param points
     *            a list of supporting points for the spline interpolation
     * @param segments
     *            number of resulting path segments per supporting point
     * @param closed
     *            true to close the shape (connect last and first point)
     * @param up
     *            up vector
     */
    public void updateGeometry(final Line shape, final List<ReadOnlyVector3> points, final int segments,
            final boolean closed, final ReadOnlyVector3 up) {
        int np = points.size(); // number of points
        if (closed) {
            np = np + 3;
        }
        final double d[][] = new double[3][np]; // Newton form coefficients
        final double x[] = new double[np]; // x-coordinates of nodes

        final List<ReadOnlyVector3> path = new ArrayList<ReadOnlyVector3>();

        for (int i = 0; i < np; i++) {
            ReadOnlyVector3 p;
            if (!closed) {
                p = points.get(i);
            } else {
                if (i == 0) {
                    p = points.get(points.size() - 1);
                } else if (i >= np - 2) {
                    p = points.get(i - np + 2);
                } else {
                    p = points.get(i - 1);
                }
            }
            x[i] = i;
            d[0][i] = p.getX();
            d[1][i] = p.getY();
            d[2][i] = p.getZ();
        }

        if (np > 1) {
            final double[][] a = new double[3][np];
            final double h[] = new double[np];
            for (int i = 1; i <= np - 1; i++) {
                h[i] = x[i] - x[i - 1];
            }
            if (np > 2) {
                final double sub[] = new double[np - 1];
                final double diag[] = new double[np - 1];
                final double sup[] = new double[np - 1];

                for (int i = 1; i <= np - 2; i++) {
                    diag[i] = (h[i] + h[i + 1]) / 3;
                    sup[i] = h[i + 1] / 6;
                    sub[i] = h[i] / 6;
                    for (int dim = 0; dim < 3; dim++) {
                        a[dim][i] = (d[dim][i + 1] - d[dim][i]) / h[i + 1] - (d[dim][i] - d[dim][i - 1]) / h[i];
                    }
                }
                for (int dim = 0; dim < 3; dim++) {
                    solveTridiag(sub.clone(), diag.clone(), sup.clone(), a[dim], np - 2);
                }
            }
            // note that a[0]=a[np-1]=0
            // draw
            if (!closed) {
                path.add(new Vector3(d[0][0], d[1][0], d[2][0]));
            }
            final double[] point = new double[3];
            for (int i = closed ? 2 : 1; i <= np - 2; i++) { // loop over
                // intervals
                // between nodes
                for (int j = 1; j <= segments; j++) {
                    for (int dim = 0; dim < 3; dim++) {
                        final double t1 = (h[i] * j) / segments;
                        final double t2 = h[i] - t1;
                        final double v = ((-a[dim][i - 1] / 6 * (t2 + h[i]) * t1 + d[dim][i - 1]) * t2 + (-a[dim][i]
                                / 6 * (t1 + h[i]) * t2 + d[dim][i])
                                * t1)
                                / h[i];
                        // float t = x[i - 1] + t1;
                        point[dim] = v;
                    }
                    path.add(new Vector3(point[0], point[1], point[2]));
                }
            }
        }

        this.updateGeometry(shape, path, closed, up);
    }

    /*
     * solve linear system with tridiagonal n by n matrix a using Gaussian elimination without pivoting where a(i,i-1) =
     * sub[i] for 2<=i<=n a(i,i) = diag[i] for 1<=i<=n a(i,i+1) = sup[i] for 1<=i<=n-1 (the values sub[1], sup[n] are
     * ignored) right hand side vector b[1:n] is overwritten with solution NOTE: 1...n is used in all arrays, 0 is
     * unused
     */
    private static void solveTridiag(final double sub[], final double diag[], final double sup[], final double b[],
            final int n) {
        // factorization and forward substitution
        for (int i = 2; i <= n; i++) {
            sub[i] = sub[i] / diag[i - 1];
            diag[i] = diag[i] - sub[i] * sup[i - 1];
            b[i] = b[i] - sub[i] * b[i - 1];
        }
        b[n] = b[n] / diag[n];
        for (int i = n - 1; i >= 1; i--) {
            b[i] = (b[i] - sup[i] * b[i + 1]) / diag[i];
        }
    }
}
TOP

Related Classes of com.ardor3d.scenegraph.shape.Extrusion

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.