2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package com.jme.scene.shape;
35 import static com.jme.util.geom.BufferUtils.*;
37 import java.io.IOException;
38 import java.nio.IntBuffer;
40 import com.jme.math.FastMath;
41 import com.jme.math.Vector3f;
42 import com.jme.scene.TexCoords;
43 import com.jme.scene.TriMesh;
44 import com.jme.util.export.InputCapsule;
45 import com.jme.util.export.JMEExporter;
46 import com.jme.util.export.JMEImporter;
47 import com.jme.util.export.OutputCapsule;
50 * A parameterized torus, also known as a <em>pq</em> torus.
52 * @author Joshua Slack, Eric Woroshow
53 * @version $Revision$, $Date$
55 public class PQTorus extends TriMesh {
57 private static final long serialVersionUID = 1L;
61 private float radius, width;
63 private int steps, radialSamples;
69 * Creates a parameterized torus.
71 * Steps and radialSamples are both degree of accuracy values.
73 * @param name the name of the torus.
74 * @param p the x/z oscillation.
75 * @param q the y oscillation.
76 * @param radius the radius of the PQTorus.
77 * @param width the width of the torus.
78 * @param steps the steps along the torus.
79 * @param radialSamples radial samples for the torus.
81 public PQTorus(String name, float p, float q, float radius, float width,
82 int steps, int radialSamples) {
84 updateGeometry(p, q, radius, width, steps, radialSamples);
95 public int getRadialSamples() {
99 public float getRadius() {
103 public int getSteps() {
107 public float getWidth() {
111 public void read(JMEImporter e) throws IOException {
113 InputCapsule capsule = e.getCapsule(this);
114 p = capsule.readFloat("p", 0);
115 q = capsule.readFloat("q", 0);
116 radius = capsule.readFloat("radius", 0);
117 width = capsule.readFloat("width", 0);
118 steps = capsule.readInt("steps", 0);
119 radialSamples = capsule.readInt("radialSamples", 0);
123 * Rebuilds this torus based on a new set of parameters.
125 * @param p the x/z oscillation.
126 * @param q the y oscillation.
127 * @param radius the radius of the PQTorus.
128 * @param width the width of the torus.
129 * @param steps the steps along the torus.
130 * @param radialSamples radial samples for the torus.
132 public void updateGeometry(float p, float q, float radius, float width, int steps, int radialSamples) {
135 this.radius = radius;
138 this.radialSamples = radialSamples;
140 final float thetaStep = (FastMath.TWO_PI / steps);
141 final float betaStep = (FastMath.TWO_PI / radialSamples);
142 Vector3f[] torusPoints = new Vector3f[steps];
144 // Allocate all of the required buffers
145 setVertexCount(radialSamples * steps);
146 setVertexBuffer(createVector3Buffer(getVertexCount()));
147 setNormalBuffer(createVector3Buffer(getVertexCount()));
148 getTextureCoords().set(0, new TexCoords(createVector2Buffer(getVertexCount())));
150 Vector3f pointB = new Vector3f(), T = new Vector3f(), N = new Vector3f(), B = new Vector3f();
151 Vector3f tempNorm = new Vector3f();
152 float r, x, y, z, theta = 0.0f, beta = 0.0f;
155 // Move along the length of the pq torus
156 for (int i = 0; i < steps; i++) {
158 float circleFraction = ((float) i) / (float) steps;
160 // Find the point on the torus
161 r = (0.5f * (2.0f + FastMath.sin(q * theta)) * radius);
162 x = (r * FastMath.cos(p * theta) * radius);
163 y = (r * FastMath.sin(p * theta) * radius);
164 z = (r * FastMath.cos(q * theta) * radius);
165 torusPoints[i] = new Vector3f(x, y, z);
167 // Now find a point slightly farther along the torus
168 r = (0.5f * (2.0f + FastMath.sin(q * (theta + 0.01f))) * radius);
169 x = (r * FastMath.cos(p * (theta + 0.01f)) * radius);
170 y = (r * FastMath.sin(p * (theta + 0.01f)) * radius);
171 z = (r * FastMath.cos(q * (theta + 0.01f)) * radius);
172 pointB = new Vector3f(x, y, z);
174 // Approximate the Frenet Frame
175 T = pointB.subtract(torusPoints[i]);
176 N = torusPoints[i].add(pointB);
180 // Normalise the two vectors and then use them to create an oriented circle
184 for (int j = 0; j < radialSamples; j++, nvertex++) {
186 float cx = FastMath.cos(beta) * width;
187 float cy = FastMath.sin(beta) * width;
188 float radialFraction = ((float) j) / radialSamples;
189 tempNorm.x = (cx * N.x + cy * B.x);
190 tempNorm.y = (cx * N.y + cy * B.y);
191 tempNorm.z = (cx * N.z + cy * B.z);
192 getNormalBuffer().put(tempNorm.x).put(tempNorm.y).put(tempNorm.z);
193 tempNorm.addLocal(torusPoints[i]);
194 getVertexBuffer().put(tempNorm.x).put(tempNorm.y).put(tempNorm.z);
195 getTextureCoords().get(0).coords.put(radialFraction).put(circleFraction);
199 // Update the indices data
200 IntBuffer indices = createIntBuffer(6 * getVertexCount());
201 for (int i = 0; i < getVertexCount(); i++) {
202 indices.put(new int[] {
203 i, i - radialSamples, i + 1, i + 1, i - radialSamples, i - radialSamples + 1
206 for (int i = 0, len = indices.capacity(); i < len; i++) {
207 int ind = indices.get(i);
209 ind += getVertexCount();
211 } else if (ind >= getVertexCount()) {
212 ind -= getVertexCount();
217 setIndexBuffer(indices);
220 public void write(JMEExporter e) throws IOException {
222 OutputCapsule capsule = e.getCapsule(this);
223 capsule.write(p, "p", 0);
224 capsule.write(q, "q", 0);
225 capsule.write(radius, "radius", 0);
226 capsule.write(width, "width", 0);
227 capsule.write(steps, "steps", 0);
228 capsule.write(radialSamples, "radialSamples", 0);