Added a unit test and fixed indentation.
This commit is contained in:
parent
61c22d5709
commit
ebaad20f2f
@ -209,15 +209,15 @@ public class Cylinder extends Mesh {
|
|||||||
* @param inverted is the cylinder is meant to be viewed from the inside.
|
* @param inverted is the cylinder is meant to be viewed from the inside.
|
||||||
*/
|
*/
|
||||||
public void updateGeometry(int axisSamples, int radialSamples,
|
public void updateGeometry(int axisSamples, int radialSamples,
|
||||||
float topRadius, float bottomRadius, float height, boolean closed, boolean inverted)
|
float topRadius, float bottomRadius, float height, boolean closed, boolean inverted) {
|
||||||
{
|
|
||||||
// Ensure there's at least two axis samples and 3 radial samples, and positive dimensions.
|
// Ensure there's at least two axis samples and 3 radial samples, and positive dimensions.
|
||||||
if( axisSamples < 2
|
if( axisSamples < 2
|
||||||
|| radialSamples < 3
|
|| radialSamples < 3
|
||||||
|| topRadius <= 0
|
|| topRadius <= 0
|
||||||
|| bottomRadius <= 0
|
|| bottomRadius <= 0
|
||||||
|| height <= 0 )
|
|| height <= 0 ) {
|
||||||
throw new IllegalArgumentException("Cylinders must have at least 2 axis samples and 3 radial samples, and positive dimensions.");
|
throw new IllegalArgumentException("Cylinders must have at least 2 axis samples and 3 radial samples, and positive dimensions.");
|
||||||
|
}
|
||||||
|
|
||||||
this.axisSamples = axisSamples;
|
this.axisSamples = axisSamples;
|
||||||
this.radialSamples = radialSamples;
|
this.radialSamples = radialSamples;
|
||||||
@ -231,8 +231,7 @@ public class Cylinder extends Mesh {
|
|||||||
int verticesCount = axisSamples * (radialSamples +1);
|
int verticesCount = axisSamples * (radialSamples +1);
|
||||||
// Triangles: Two per side rectangle, which is the product of numbers of samples.
|
// Triangles: Two per side rectangle, which is the product of numbers of samples.
|
||||||
int trianglesCount = axisSamples * radialSamples * 2 ;
|
int trianglesCount = axisSamples * radialSamples * 2 ;
|
||||||
if( closed )
|
if( closed ) {
|
||||||
{
|
|
||||||
// If there are caps, add two additional rims and two summits.
|
// If there are caps, add two additional rims and two summits.
|
||||||
verticesCount += 2 + 2 * (radialSamples +1);
|
verticesCount += 2 + 2 * (radialSamples +1);
|
||||||
// Add one triangle per radial sample, twice, to form the caps.
|
// Add one triangle per radial sample, twice, to form the caps.
|
||||||
@ -241,8 +240,7 @@ public class Cylinder extends Mesh {
|
|||||||
|
|
||||||
// Compute the points along a unit circle:
|
// Compute the points along a unit circle:
|
||||||
float[][] circlePoints = new float[radialSamples+1][2];
|
float[][] circlePoints = new float[radialSamples+1][2];
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
|
||||||
{
|
|
||||||
float angle = FastMath.TWO_PI / radialSamples * circlePoint;
|
float angle = FastMath.TWO_PI / radialSamples * circlePoint;
|
||||||
circlePoints[circlePoint][0] = FastMath.cos(angle);
|
circlePoints[circlePoint][0] = FastMath.cos(angle);
|
||||||
circlePoints[circlePoint][1] = FastMath.sin(angle);
|
circlePoints[circlePoint][1] = FastMath.sin(angle);
|
||||||
@ -263,8 +261,7 @@ public class Cylinder extends Mesh {
|
|||||||
// The normal in A and D is simply orthogonal to AD, which means we can get it once per sample.
|
// The normal in A and D is simply orthogonal to AD, which means we can get it once per sample.
|
||||||
//
|
//
|
||||||
Vector3f[] circleNormals = new Vector3f[radialSamples+1];
|
Vector3f[] circleNormals = new Vector3f[radialSamples+1];
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples+1; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples+1; circlePoint++) {
|
||||||
{
|
|
||||||
// The normal is the orthogonal to the side, which can be got without trigonometry.
|
// The normal is the orthogonal to the side, which can be got without trigonometry.
|
||||||
// The edge direction is oriented so that it goes up by Height, and out by the radius difference; let's use
|
// The edge direction is oriented so that it goes up by Height, and out by the radius difference; let's use
|
||||||
// those values in reverse order.
|
// those values in reverse order.
|
||||||
@ -278,13 +275,11 @@ public class Cylinder extends Mesh {
|
|||||||
int currentIndex = 0;
|
int currentIndex = 0;
|
||||||
|
|
||||||
// Add a circle of points for each axis sample.
|
// Add a circle of points for each axis sample.
|
||||||
for(int axisSample = 0; axisSample < axisSamples; axisSample++ )
|
for(int axisSample = 0; axisSample < axisSamples; axisSample++ ) {
|
||||||
{
|
|
||||||
float currentHeight = -height / 2 + height * axisSample / (axisSamples-1);
|
float currentHeight = -height / 2 + height * axisSample / (axisSamples-1);
|
||||||
float currentRadius = bottomRadius + (topRadius - bottomRadius) * axisSample / (axisSamples-1);
|
float currentRadius = bottomRadius + (topRadius - bottomRadius) * axisSample / (axisSamples-1);
|
||||||
|
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
|
||||||
{
|
|
||||||
// Position, by multipliying the position on a unit circle with the current radius.
|
// Position, by multipliying the position on a unit circle with the current radius.
|
||||||
vertices[currentIndex*3] = circlePoints[circlePoint][0] * currentRadius;
|
vertices[currentIndex*3] = circlePoints[circlePoint][0] * currentRadius;
|
||||||
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * currentRadius;
|
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * currentRadius;
|
||||||
@ -311,11 +306,9 @@ public class Cylinder extends Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If closed, add duplicate rims on top and bottom, with normals facing up and down.
|
// If closed, add duplicate rims on top and bottom, with normals facing up and down.
|
||||||
if (closed)
|
if (closed) {
|
||||||
{
|
|
||||||
// Bottom
|
// Bottom
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
|
||||||
{
|
|
||||||
vertices[currentIndex*3] = circlePoints[circlePoint][0] * bottomRadius;
|
vertices[currentIndex*3] = circlePoints[circlePoint][0] * bottomRadius;
|
||||||
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * bottomRadius;
|
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * bottomRadius;
|
||||||
vertices[currentIndex*3 +2] = -height/2;
|
vertices[currentIndex*3 +2] = -height/2;
|
||||||
@ -330,8 +323,7 @@ public class Cylinder extends Mesh {
|
|||||||
currentIndex++;
|
currentIndex++;
|
||||||
}
|
}
|
||||||
// Top
|
// Top
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
|
||||||
{
|
|
||||||
vertices[currentIndex*3] = circlePoints[circlePoint][0] * topRadius;
|
vertices[currentIndex*3] = circlePoints[circlePoint][0] * topRadius;
|
||||||
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * topRadius;
|
vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * topRadius;
|
||||||
vertices[currentIndex*3 +2] = height/2;
|
vertices[currentIndex*3 +2] = height/2;
|
||||||
@ -375,10 +367,8 @@ public class Cylinder extends Mesh {
|
|||||||
// Add the triangles indexes.
|
// Add the triangles indexes.
|
||||||
short[] indices = new short[trianglesCount * 3];
|
short[] indices = new short[trianglesCount * 3];
|
||||||
currentIndex = 0;
|
currentIndex = 0;
|
||||||
for (short axisSample = 0; axisSample < axisSamples - 1; axisSample++)
|
for (short axisSample = 0; axisSample < axisSamples - 1; axisSample++) {
|
||||||
{
|
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++)
|
|
||||||
{
|
|
||||||
indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint);
|
indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint);
|
||||||
indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint + 1);
|
indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint + 1);
|
||||||
indices[currentIndex++] = (short) ((axisSample + 1) * (radialSamples + 1) + circlePoint);
|
indices[currentIndex++] = (short) ((axisSample + 1) * (radialSamples + 1) + circlePoint);
|
||||||
@ -389,16 +379,14 @@ public class Cylinder extends Mesh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add caps if needed.
|
// Add caps if needed.
|
||||||
if(closed)
|
if(closed) {
|
||||||
{
|
|
||||||
short bottomCapIndex = (short) (verticesCount - 2);
|
short bottomCapIndex = (short) (verticesCount - 2);
|
||||||
short topCapIndex = (short) (verticesCount - 1);
|
short topCapIndex = (short) (verticesCount - 1);
|
||||||
|
|
||||||
int bottomRowOffset = (axisSamples) * (radialSamples +1 );
|
int bottomRowOffset = (axisSamples) * (radialSamples +1 );
|
||||||
int topRowOffset = (axisSamples+1) * (radialSamples +1 );
|
int topRowOffset = (axisSamples+1) * (radialSamples +1 );
|
||||||
|
|
||||||
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++)
|
for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
|
||||||
{
|
|
||||||
indices[currentIndex++] = (short) (bottomRowOffset + circlePoint +1);
|
indices[currentIndex++] = (short) (bottomRowOffset + circlePoint +1);
|
||||||
indices[currentIndex++] = (short) (bottomRowOffset + circlePoint);
|
indices[currentIndex++] = (short) (bottomRowOffset + circlePoint);
|
||||||
indices[currentIndex++] = bottomCapIndex;
|
indices[currentIndex++] = bottomCapIndex;
|
||||||
@ -411,17 +399,14 @@ public class Cylinder extends Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If inverted, the triangles and normals are all reverted.
|
// If inverted, the triangles and normals are all reverted.
|
||||||
if (inverted)
|
if (inverted) {
|
||||||
{
|
for (int i = 0; i < indices.length / 2; i++) {
|
||||||
for (int i = 0; i < indices.length / 2; i++)
|
|
||||||
{
|
|
||||||
short temp = indices[i];
|
short temp = indices[i];
|
||||||
indices[i] = indices[indices.length - 1 - i];
|
indices[i] = indices[indices.length - 1 - i];
|
||||||
indices[indices.length - 1 - i] = temp;
|
indices[indices.length - 1 - i] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i< normals.length; i++)
|
for(int i = 0; i< normals.length; i++) {
|
||||||
{
|
|
||||||
normals[i] = -normals[i];
|
normals[i] = -normals[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2017 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.jme3.scene;
|
||||||
|
|
||||||
|
import com.jme3.collision.CollisionResults;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
import com.jme3.math.Ray;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.shape.Cylinder;
|
||||||
|
import java.util.Random;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that geometries behave correctly, by casting rays and ensure they don't break.
|
||||||
|
*
|
||||||
|
* @author Christophe Carpentier
|
||||||
|
*/
|
||||||
|
public class ShapeGeometryTest {
|
||||||
|
|
||||||
|
protected static final int NUMBER_OF_TRIES = 1000;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCylinders() {
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
// Create a cylinder, cast a random ray, and ensure everything goes well.
|
||||||
|
Node scene = new Node("Scene Node");
|
||||||
|
|
||||||
|
for (int i = 0; i < NUMBER_OF_TRIES; i++) {
|
||||||
|
scene.detachAllChildren();
|
||||||
|
|
||||||
|
Cylinder cylinder = new Cylinder(2, 8, 1, 1, true);
|
||||||
|
Geometry geometry = new Geometry("cylinder", cylinder);
|
||||||
|
geometry.rotate(FastMath.HALF_PI, 0, 0);
|
||||||
|
scene.attachChild(geometry);
|
||||||
|
|
||||||
|
// Cast a random ray, and count successes and IndexOutOfBoundsExceptions.
|
||||||
|
Vector3f randomPoint = new Vector3f(random.nextFloat(), random.nextFloat(), random.nextFloat());
|
||||||
|
Vector3f randomDirection = new Vector3f(random.nextFloat(), random.nextFloat(), random.nextFloat());
|
||||||
|
randomDirection.normalizeLocal();
|
||||||
|
|
||||||
|
Ray ray = new Ray(randomPoint, randomDirection);
|
||||||
|
CollisionResults collisionResults = new CollisionResults();
|
||||||
|
|
||||||
|
// If the geometry is invalid, this should throw various exceptions.
|
||||||
|
scene.collideWith(ray, collisionResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user