Skip to content

Commit 9be35f8

Browse files
authored
Update Torus.java
1 parent c110698 commit 9be35f8

File tree

1 file changed

+141
-122
lines changed
  • jme3-core/src/main/java/com/jme3/scene/shape

1 file changed

+141
-122
lines changed
Lines changed: 141 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2021 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -47,78 +47,61 @@
4747
/**
4848
* An ordinary (single holed) torus.
4949
* <p>
50-
* The center is by default the origin.
50+
* The torus is centered at the origin by default, but its position and
51+
* orientation can be transformed.
5152
*
5253
* @author Mark Powell
5354
* @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $
5455
*/
5556
public class Torus extends Mesh {
5657

58+
/**
59+
* The number of samples around the circular cross-section of the torus.
60+
*/
5761
private int circleSamples;
58-
62+
/**
63+
* The number of samples along the major radius of the torus.
64+
*/
5965
private int radialSamples;
6066
/**
61-
* minor radius of the torus
67+
* The minor radius of the torus.
6268
*/
6369
private float innerRadius;
6470
/**
65-
* major radius of the torus
71+
* The major radius of the torus.
6672
*/
6773
private float outerRadius;
6874

75+
/**
76+
* Serialization-only constructor. Do not use.
77+
*/
6978
public Torus() {
7079
}
7180

7281
/**
73-
* Constructs a new Torus. Center is the origin, but the Torus may be
74-
* transformed.
75-
*
76-
* @param circleSamples
77-
* The number of samples along the circles.
78-
* @param radialSamples
79-
* The number of samples along the radial.
80-
* @param innerRadius minor radius of the torus
81-
* @param outerRadius major radius of the torus
82+
* Constructs a new `Torus` mesh centered at the origin.
83+
*
84+
* @param circleSamples The number of samples around the circular cross-section.
85+
* Higher values result in a smoother tube.
86+
* @param radialSamples The number of samples along the major radius (around the hole).
87+
* Higher values result in a smoother overall torus shape.
88+
* @param innerRadius The minor radius of the torus (radius of the circular cross-section).
89+
* @param outerRadius The major radius of the torus (distance from the center of the hole to the center of the tube).
90+
* @throws IllegalArgumentException if `circleSamples` or `radialSamples` are less than 3,
91+
* or if `innerRadius` or `outerRadius` are negative.
8292
*/
83-
public Torus(int circleSamples, int radialSamples,
84-
float innerRadius, float outerRadius) {
93+
public Torus(int circleSamples, int radialSamples, float innerRadius, float outerRadius) {
8594
super();
8695
updateGeometry(circleSamples, radialSamples, innerRadius, outerRadius);
8796
}
8897

89-
public int getCircleSamples() {
90-
return circleSamples;
91-
}
92-
93-
public float getInnerRadius() {
94-
return innerRadius;
95-
}
96-
97-
public float getOuterRadius() {
98-
return outerRadius;
99-
}
100-
101-
public int getRadialSamples() {
102-
return radialSamples;
103-
}
104-
105-
@Override
106-
public void read(JmeImporter importer) throws IOException {
107-
super.read(importer);
108-
InputCapsule capsule = importer.getCapsule(this);
109-
circleSamples = capsule.readInt("circleSamples", 0);
110-
radialSamples = capsule.readInt("radialSamples", 0);
111-
innerRadius = capsule.readFloat("innerRadius", 0);
112-
outerRadius = capsule.readFloat("outerRadius", 0);
113-
}
114-
11598
private void setGeometryData() {
11699
// allocate vertices
117100
int vertCount = (circleSamples + 1) * (radialSamples + 1);
118101
FloatBuffer fpb = BufferUtils.createVector3Buffer(vertCount);
119102
setBuffer(Type.Position, 3, fpb);
120103

121-
// allocate normals if requested
104+
// allocate normals
122105
FloatBuffer fnb = BufferUtils.createVector3Buffer(vertCount);
123106
setBuffer(Type.Normal, 3, fnb);
124107

@@ -129,109 +112,99 @@ private void setGeometryData() {
129112
// generate geometry
130113
float inverseCircleSamples = 1.0f / circleSamples;
131114
float inverseRadialSamples = 1.0f / radialSamples;
132-
int i = 0;
133115
// generate the cylinder itself
134-
Vector3f radialAxis = new Vector3f(), torusMiddle = new Vector3f(), tempNormal = new Vector3f();
135-
for (int circleCount = 0; circleCount < circleSamples; circleCount++) {
116+
Vector3f radialAxis = new Vector3f();
117+
Vector3f torusMiddle = new Vector3f();
118+
Vector3f tempNormal = new Vector3f();
119+
120+
for (int circleCount = 0; circleCount <= circleSamples; circleCount++) {
136121
// compute center point on torus circle at specified angle
137122
float circleFraction = circleCount * inverseCircleSamples;
138123
float theta = FastMath.TWO_PI * circleFraction;
139124
float cosTheta = FastMath.cos(theta);
140125
float sinTheta = FastMath.sin(theta);
126+
127+
// Calculate the center point of the current circular cross-section on the major radius
141128
radialAxis.set(cosTheta, sinTheta, 0);
142129
radialAxis.mult(outerRadius, torusMiddle);
143130

144131
// compute slice vertices with duplication at end point
145-
int iSave = i;
146-
for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
132+
for (int radialCount = 0; radialCount <= radialSamples; radialCount++) {
147133
float radialFraction = radialCount * inverseRadialSamples;
148134
// in [0,1)
149135
float phi = FastMath.TWO_PI * radialFraction;
150136
float cosPhi = FastMath.cos(phi);
151137
float sinPhi = FastMath.sin(phi);
138+
139+
// Calculate normal vector
152140
tempNormal.set(radialAxis).multLocal(cosPhi);
153141
tempNormal.z += sinPhi;
154-
fnb.put(tempNormal.x).put(tempNormal.y).put(
155-
tempNormal.z);
156-
142+
fnb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);
143+
144+
// Calculate vertex position
157145
tempNormal.multLocal(innerRadius).addLocal(torusMiddle);
158-
fpb.put(tempNormal.x).put(tempNormal.y).put(
159-
tempNormal.z);
146+
fpb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);
160147

148+
// Calculate texture coordinates
161149
ftb.put(radialFraction).put(circleFraction);
162-
i++;
163150
}
164-
165-
BufferUtils.copyInternalVector3(fpb, iSave, i);
166-
BufferUtils.copyInternalVector3(fnb, iSave, i);
167-
168-
ftb.put(1.0f).put(circleFraction);
169-
170-
i++;
171-
}
172-
173-
// duplicate the cylinder ends to form a torus
174-
for (int iR = 0; iR <= radialSamples; iR++, i++) {
175-
BufferUtils.copyInternalVector3(fpb, iR, i);
176-
BufferUtils.copyInternalVector3(fnb, iR, i);
177-
BufferUtils.copyInternalVector2(ftb, iR, i);
178-
ftb.put(i * 2 + 1, 1.0f);
179151
}
180152
}
181153

182154
private void setIndexData() {
183-
// allocate connectivity
184-
int triCount = 2 * circleSamples * radialSamples;
185-
186-
ShortBuffer sib = BufferUtils.createShortBuffer(3 * triCount);
187-
setBuffer(Type.Index, 3, sib);
188-
189-
int i;
190-
// generate connectivity
191-
int connectionStart = 0;
192-
int index = 0;
193-
for (int circleCount = 0; circleCount < circleSamples; circleCount++) {
194-
int i0 = connectionStart;
195-
int i1 = i0 + 1;
196-
connectionStart += radialSamples + 1;
197-
int i2 = connectionStart;
198-
int i3 = i2 + 1;
199-
for (i = 0; i < radialSamples; i++, index += 6) {
200-
// if (true) {
201-
sib.put((short)i0++);
202-
sib.put((short)i2);
203-
sib.put((short)i1);
204-
sib.put((short)i1++);
205-
sib.put((short)i2++);
206-
sib.put((short)i3++);
207-
208-
// getIndexBuffer().put(i0++);
209-
// getIndexBuffer().put(i2);
210-
// getIndexBuffer().put(i1);
211-
// getIndexBuffer().put(i1++);
212-
// getIndexBuffer().put(i2++);
213-
// getIndexBuffer().put(i3++);
214-
// } else {
215-
// getIndexBuffer().put(i0++);
216-
// getIndexBuffer().put(i1);
217-
// getIndexBuffer().put(i2);
218-
// getIndexBuffer().put(i1++);
219-
// getIndexBuffer().put(i3++);
220-
// getIndexBuffer().put(i2++);
221-
// }
155+
// Each quad forms two triangles, and there are radialSamples * circleSamples quads.
156+
int totalTriangles = 2 * circleSamples * radialSamples;
157+
ShortBuffer indexBuffer = BufferUtils.createShortBuffer(3 * totalTriangles);
158+
setBuffer(Type.Index, 3, indexBuffer);
159+
160+
int currentQuadStartIndex = 0;
161+
for (int circleIter = 0; circleIter < circleSamples; circleIter++) {
162+
for (int radialIter = 0; radialIter < radialSamples; radialIter++) {
163+
int i0 = currentQuadStartIndex + radialIter;
164+
int i1 = i0 + 1;
165+
int i2 = i0 + (radialSamples + 1);
166+
int i3 = i2 + 1;
167+
168+
// First triangle of the quad
169+
indexBuffer.put((short) i0);
170+
indexBuffer.put((short) i2);
171+
indexBuffer.put((short) i1);
172+
173+
// Second triangle of the quad
174+
indexBuffer.put((short) i1);
175+
indexBuffer.put((short) i2);
176+
indexBuffer.put((short) i3);
222177
}
178+
currentQuadStartIndex += (radialSamples + 1);
223179
}
224180
}
225181

226182
/**
227-
* Rebuilds this torus based on a new set of parameters.
228-
*
229-
* @param circleSamples the number of samples along the circles.
230-
* @param radialSamples the number of samples along the radial.
231-
* @param innerRadius minor radius of the torus
232-
* @param outerRadius major radius of the torus
183+
* Rebuilds the torus mesh based on a new set of parameters.
184+
* This method updates the internal parameters and then regenerates
185+
* the vertex data, index data, updates the bounding volume, and counts.
186+
*
187+
* @param circleSamples The number of samples around the circular cross-section.
188+
* @param radialSamples The number of samples along the major radius.
189+
* @param innerRadius The minor radius of the torus.
190+
* @param outerRadius The major radius of the torus.
191+
* @throws IllegalArgumentException if `circleSamples` or `radialSamples` are less than 3,
192+
* or if `innerRadius` or `outerRadius` are negative.
233193
*/
234194
public void updateGeometry(int circleSamples, int radialSamples, float innerRadius, float outerRadius) {
195+
if (circleSamples < 3) {
196+
throw new IllegalArgumentException("circleSamples must be at least 3.");
197+
}
198+
if (radialSamples < 3) {
199+
throw new IllegalArgumentException("radialSamples must be at least 3.");
200+
}
201+
if (innerRadius < 0) {
202+
throw new IllegalArgumentException("innerRadius cannot be negative.");
203+
}
204+
if (outerRadius < 0) {
205+
throw new IllegalArgumentException("outerRadius cannot be negative.");
206+
}
207+
235208
this.circleSamples = circleSamples;
236209
this.radialSamples = radialSamples;
237210
this.innerRadius = innerRadius;
@@ -242,14 +215,60 @@ public void updateGeometry(int circleSamples, int radialSamples, float innerRadi
242215
updateCounts();
243216
}
244217

218+
/**
219+
* Returns the number of samples around the circular cross-section of the torus.
220+
*
221+
* @return The number of circle samples.
222+
*/
223+
public int getCircleSamples() {
224+
return circleSamples;
225+
}
226+
227+
/**
228+
* Returns the minor radius of the torus.
229+
*
230+
* @return The inner radius.
231+
*/
232+
public float getInnerRadius() {
233+
return innerRadius;
234+
}
235+
236+
/**
237+
* Returns the major radius of the torus.
238+
*
239+
* @return The outer radius.
240+
*/
241+
public float getOuterRadius() {
242+
return outerRadius;
243+
}
244+
245+
/**
246+
* Returns the number of samples along the major radius of the torus.
247+
*
248+
* @return The number of radial samples.
249+
*/
250+
public int getRadialSamples() {
251+
return radialSamples;
252+
}
253+
254+
@Override
255+
public void write(JmeExporter ex) throws IOException {
256+
super.write(ex);
257+
OutputCapsule oc = ex.getCapsule(this);
258+
oc.write(circleSamples, "circleSamples", 0);
259+
oc.write(radialSamples, "radialSamples", 0);
260+
oc.write(innerRadius, "innerRadius", 0);
261+
oc.write(outerRadius, "outerRadius", 0);
262+
}
263+
245264
@Override
246-
public void write(JmeExporter e) throws IOException {
247-
super.write(e);
248-
OutputCapsule capsule = e.getCapsule(this);
249-
capsule.write(circleSamples, "circleSamples", 0);
250-
capsule.write(radialSamples, "radialSamples", 0);
251-
capsule.write(innerRadius, "innerRadius", 0);
252-
capsule.write(outerRadius, "outerRadius", 0);
265+
public void read(JmeImporter im) throws IOException {
266+
super.read(im);
267+
InputCapsule ic = im.getCapsule(this);
268+
circleSamples = ic.readInt("circleSamples", 0);
269+
radialSamples = ic.readInt("radialSamples", 0);
270+
innerRadius = ic.readFloat("innerRadius", 0);
271+
outerRadius = ic.readFloat("outerRadius", 0);
253272
}
254273

255-
}
274+
}

0 commit comments

Comments
 (0)