Refactor tube exporter to use cylinder exporter

This commit is contained in:
SiboVG 2023-08-14 02:20:16 +02:00
parent 87c4cbec97
commit 7ebed840b6
8 changed files with 113 additions and 211 deletions

View File

@ -29,20 +29,10 @@ public class BodyTubeExporter extends RocketComponentExporter<BodyTube> {
} }
} }
private void generateMesh(float outerRadius, float innerRadius, float length, boolean isFilled, private void generateMesh(float outerRadius, float innerRadius, float length, boolean isFilled, InstanceContext context) {
InstanceContext context) { // Generate the mesh
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, isFilled ? 0 : innerRadius, length, LOD);
if (isFilled || Float.compare(innerRadius, 0) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, true, LOD);
} else {
if (Float.compare(innerRadius, outerRadius) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, false, LOD);
} else {
TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD);
}
}
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Translate the mesh to the position in the rocket // Translate the mesh to the position in the rocket

View File

@ -30,19 +30,9 @@ public class LaunchLugExporter extends RocketComponentExporter<LaunchLug> {
} }
private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) { private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) {
// Generate the mesh
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
// Generate the instance mesh
if (Float.compare(innerRadius, 0) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, true, LOD);
} else {
if (Float.compare(innerRadius, outerRadius) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, false, LOD);
} else {
TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD); TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD);
}
}
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Translate the mesh to the position in the rocket // Translate the mesh to the position in the rocket

View File

@ -53,45 +53,45 @@ public class RailButtonExporter extends RocketComponentExporter<RailButton> {
final int normalStartIdx = obj.getNumNormals(); final int normalStartIdx = obj.getNumNormals();
// Generate base cylinder // Generate base cylinder
List<Integer> baseCylinderBottomVertices = new ArrayList<>(); List<Integer> baseCylinderForeVertices = new ArrayList<>();
List<Integer> baseCylinderTopVertices = new ArrayList<>(); List<Integer> baseCylinderAftVertices = new ArrayList<>();
CylinderExporter.addCylinderMesh(obj, transformer, null, outerRadius, baseHeight, false, LOD, CylinderExporter.addCylinderMesh(obj, transformer, null, outerRadius, baseHeight, false, LOD,
baseCylinderBottomVertices, baseCylinderTopVertices); baseCylinderForeVertices, baseCylinderAftVertices);
// Generate inner cylinder // Generate inner cylinder
int tmpStartIdx = obj.getNumVertices(); int tmpStartIdx = obj.getNumVertices();
List<Integer> innerCylinderBottomVertices = new ArrayList<>(); List<Integer> innerCylinderForeVertices = new ArrayList<>();
List<Integer> innerCylinderTopVertices = new ArrayList<>(); List<Integer> innerCylinderAftVertices = new ArrayList<>();
CylinderExporter.addCylinderMesh(obj, transformer, null, innerRadius, innerHeight, false, LOD, CylinderExporter.addCylinderMesh(obj, transformer, null, innerRadius, innerHeight, false, LOD,
innerCylinderBottomVertices, innerCylinderTopVertices); innerCylinderForeVertices, innerCylinderAftVertices);
int tmpEndIdx = Math.max(obj.getNumVertices() - 1, tmpStartIdx); int tmpEndIdx = Math.max(obj.getNumVertices() - 1, tmpStartIdx);
FloatTuple locOffs = transformer.convertLocWithoutOriginOffs(baseHeight, 0, 0); FloatTuple locOffs = transformer.convertLocWithoutOriginOffs(baseHeight, 0, 0);
ObjUtils.translateVertices(obj, tmpStartIdx, tmpEndIdx, locOffs.getX(), locOffs.getY(), locOffs.getZ()); ObjUtils.translateVertices(obj, tmpStartIdx, tmpEndIdx, locOffs.getX(), locOffs.getY(), locOffs.getZ());
// Generate flange cylinder // Generate flange cylinder
tmpStartIdx = obj.getNumVertices(); tmpStartIdx = obj.getNumVertices();
List<Integer> flangeCylinderBottomVertices = new ArrayList<>(); List<Integer> flangeCylinderForeVertices = new ArrayList<>();
List<Integer> flangeCylinderTopVertices = new ArrayList<>(); List<Integer> flangeCylinderAftVertices = new ArrayList<>();
CylinderExporter.addCylinderMesh(obj, transformer, null, outerRadius, flangeHeight, false, LOD, CylinderExporter.addCylinderMesh(obj, transformer, null, outerRadius, flangeHeight, false, LOD,
flangeCylinderBottomVertices, flangeCylinderTopVertices); flangeCylinderForeVertices, flangeCylinderAftVertices);
tmpEndIdx = Math.max(obj.getNumVertices() - 1, tmpStartIdx); tmpEndIdx = Math.max(obj.getNumVertices() - 1, tmpStartIdx);
locOffs = transformer.convertLocWithoutOriginOffs(baseHeight + innerHeight, 0, 0); locOffs = transformer.convertLocWithoutOriginOffs(baseHeight + innerHeight, 0, 0);
ObjUtils.translateVertices(obj, tmpStartIdx, tmpEndIdx, locOffs.getX(), locOffs.getY(), locOffs.getZ()); ObjUtils.translateVertices(obj, tmpStartIdx, tmpEndIdx, locOffs.getX(), locOffs.getY(), locOffs.getZ());
// Generate base disk // Generate base disk
DiskExporter.closeDiskMesh(obj, transformer, null, baseCylinderTopVertices, false, true); DiskExporter.closeDiskMesh(obj, transformer, null, baseCylinderForeVertices, false, true);
// Generate base inner disk // Generate base inner disk
DiskExporter.closeDiskMesh(obj, transformer, null, baseCylinderBottomVertices, innerCylinderTopVertices, false, false); DiskExporter.closeDiskMesh(obj, transformer, null, baseCylinderAftVertices, innerCylinderForeVertices, false, false);
// Generate flange inner disk // Generate flange inner disk
DiskExporter.closeDiskMesh(obj, transformer, null, innerCylinderBottomVertices, flangeCylinderTopVertices, true, true); DiskExporter.closeDiskMesh(obj, transformer, null, innerCylinderAftVertices, flangeCylinderForeVertices, true, true);
// Generate flange disk/screw // Generate flange disk/screw
if (Float.compare(screwHeight, 0) == 0) { if (Float.compare(screwHeight, 0) == 0) {
DiskExporter.closeDiskMesh(obj, transformer, null, flangeCylinderBottomVertices, false, false); DiskExporter.closeDiskMesh(obj, transformer, null, flangeCylinderAftVertices, false, false);
} else { } else {
addScrew(obj, baseHeight, innerHeight, flangeHeight, outerRadius, screwHeight, LOD, flangeCylinderBottomVertices); addScrew(obj, baseHeight, innerHeight, flangeHeight, outerRadius, screwHeight, LOD, flangeCylinderAftVertices);
} }

View File

@ -30,18 +30,9 @@ public class RingComponentExporter extends RocketComponentExporter<RingComponent
} }
private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) { private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) {
// Generate the mesh
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
if (Float.compare(innerRadius, 0) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, true, LOD);
} else {
if (Float.compare(innerRadius, outerRadius) == 0) {
CylinderExporter.addCylinderMesh(obj, transformer, groupName, outerRadius, length, false, LOD);
} else {
TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD); TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD);
}
}
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Translate the mesh to the position in the rocket // Translate the mesh to the position in the rocket

View File

@ -64,9 +64,9 @@ public class TransitionExporter extends RocketComponentExporter<Transition> {
float outerFore = (float) component.getForeRadius(); float outerFore = (float) component.getForeRadius();
float innerFore = (float) (component.getForeRadius() - component.getThickness()); float innerFore = (float) (component.getForeRadius() - component.getThickness());
TubeExporter.addTubeMesh(obj, transformer, null, outerAft, outerFore, innerAft, innerFore, TubeExporter.addTubeMesh(obj, transformer, null, outerFore, outerAft, innerFore, innerAft,
(float) component.getLength(), this.nrOfSides, (float) component.getLength(), this.nrOfSides,
outsideAftRingVertices, outsideForeRingVertices, insideAftRingVertices, insideForeRingVertices); outsideForeRingVertices, outsideAftRingVertices, insideForeRingVertices, insideAftRingVertices);
} }
// Otherwise, use complex geometry // Otherwise, use complex geometry
else { else {
@ -370,10 +370,10 @@ public class TransitionExporter extends RocketComponentExporter<Transition> {
private void addShoulder(float shoulderRadius, float shoulderLength, float shoulderThickness, boolean isCapped, private void addShoulder(float shoulderRadius, float shoulderLength, float shoulderThickness, boolean isCapped,
boolean isForeSide, int nrOfSides, List<Integer> outerRingVertices, List<Integer> innerRingVertices) { boolean isForeSide, int nrOfSides, List<Integer> outerRingVertices, List<Integer> innerRingVertices) {
final float innerCylinderRadius = isCapped ? 0 : shoulderRadius - shoulderThickness; final float innerCylinderRadius = isCapped ? 0 : shoulderRadius - shoulderThickness;
final List<Integer> outerCylinderBottomVertices = new ArrayList<>(); final List<Integer> outerCylinderForeVertices = new ArrayList<>();
final List<Integer> outerCylinderTopVertices = new ArrayList<>(); final List<Integer> outerCylinderAftVertices = new ArrayList<>();
final List<Integer> innerCylinderBottomVertices = isCapped ? null : new ArrayList<>(); final List<Integer> innerCylinderForeVertices = isCapped ? null : new ArrayList<>();
final List<Integer> innerCylinderTopVertices = isCapped ? null : new ArrayList<>(); final List<Integer> innerCylinderAftVertices = isCapped ? null : new ArrayList<>();
int startIdx; int startIdx;
int endIdx; int endIdx;
@ -403,7 +403,7 @@ public class TransitionExporter extends RocketComponentExporter<Transition> {
// Generate outer cylinder (no. 3) // Generate outer cylinder (no. 3)
startIdx = obj.getNumVertices(); startIdx = obj.getNumVertices();
CylinderExporter.addCylinderMesh(obj, transformer, null, shoulderRadius, shoulderLength, CylinderExporter.addCylinderMesh(obj, transformer, null, shoulderRadius, shoulderLength,
false, nrOfSides, outerCylinderBottomVertices, outerCylinderTopVertices); false, nrOfSides, outerCylinderForeVertices, outerCylinderAftVertices);
endIdx = Math.max(obj.getNumVertices() - 1, startIdx); endIdx = Math.max(obj.getNumVertices() - 1, startIdx);
// Translate the outer cylinder to the correct position // Translate the outer cylinder to the correct position
@ -415,7 +415,7 @@ public class TransitionExporter extends RocketComponentExporter<Transition> {
if (!isCapped) { if (!isCapped) {
startIdx = obj.getNumVertices(); startIdx = obj.getNumVertices();
CylinderExporter.addCylinderMesh(obj, transformer, null, innerCylinderRadius, shoulderLength + shoulderThickness, CylinderExporter.addCylinderMesh(obj, transformer, null, innerCylinderRadius, shoulderLength + shoulderThickness,
false, false, nrOfSides, innerCylinderBottomVertices, innerCylinderTopVertices); false, false, nrOfSides, innerCylinderForeVertices, innerCylinderAftVertices);
endIdx = Math.max(obj.getNumVertices() - 1, startIdx); endIdx = Math.max(obj.getNumVertices() - 1, startIdx);
// Translate the outer cylinder to the correct position // Translate the outer cylinder to the correct position
@ -426,23 +426,23 @@ public class TransitionExporter extends RocketComponentExporter<Transition> {
// Generate shoulder top disk (no. 4) // Generate shoulder top disk (no. 4)
if (isForeSide) { if (isForeSide) {
DiskExporter.closeDiskMesh(obj, transformer, null, outerCylinderTopVertices, innerCylinderTopVertices, false, true); DiskExporter.closeDiskMesh(obj, transformer, null, outerCylinderForeVertices, innerCylinderForeVertices, false, true);
} else { } else {
DiskExporter.closeDiskMesh(obj, transformer, null, outerCylinderBottomVertices, innerCylinderBottomVertices, false, false); DiskExporter.closeDiskMesh(obj, transformer, null, outerCylinderAftVertices, innerCylinderAftVertices, false, false);
} }
// Generate transition outer disk (no. 5) // Generate transition outer disk (no. 5)
if (isForeSide) { if (isForeSide) {
DiskExporter.closeDiskMesh(obj, transformer, null, outerRingVertices, outerCylinderBottomVertices, false, true); DiskExporter.closeDiskMesh(obj, transformer, null, outerRingVertices, outerCylinderAftVertices, false, true);
} else { } else {
DiskExporter.closeDiskMesh(obj, transformer, null, outerRingVertices, outerCylinderTopVertices, false, false); DiskExporter.closeDiskMesh(obj, transformer, null, outerRingVertices, outerCylinderForeVertices, false, false);
} }
// Generate transition inner disk (no. 6) // Generate transition inner disk (no. 6)
if (isForeSide) { if (isForeSide) {
DiskExporter.closeDiskMesh(obj, transformer, null, innerRingVertices, innerCylinderBottomVertices, false, false); DiskExporter.closeDiskMesh(obj, transformer, null, innerRingVertices, innerCylinderAftVertices, false, false);
} else { } else {
DiskExporter.closeDiskMesh(obj, transformer, null, innerRingVertices, innerCylinderTopVertices, false, true); DiskExporter.closeDiskMesh(obj, transformer, null, innerRingVertices, innerCylinderForeVertices, false, true);
} }
} }

View File

@ -14,19 +14,20 @@ public class CylinderExporter {
* @param obj The obj to add the mesh to * @param obj The obj to add the mesh to
* @param transformer The coordinate system transformer to use to switch from the OpenRocket coordinate system to a custom OBJ coordinate system * @param transformer The coordinate system transformer to use to switch from the OpenRocket coordinate system to a custom OBJ coordinate system
* @param groupName The name of the group to add the mesh to, or null if no group should be added (use the active group) * @param groupName The name of the group to add the mesh to, or null if no group should be added (use the active group)
* @param radius The radius of the cylinder * @param foreRadius The fore (top) radius of the cylinder
* @param aftRadius The aft (bottom) radius of the cylinder
* @param length The length of the cylinder * @param length The length of the cylinder
* @param numSides The number of sides of the cylinder * @param numSides The number of sides of the cylinder
* @param solid Whether the cylinder should be solid (true) or hollow (false) * @param solid Whether the cylinder should be solid (true) or hollow (false)
* NOTE: Culling is not really thought of for the hollow cylinder; this mode is really meant to be * NOTE: Culling is not really thought of for the hollow cylinder; this mode is really meant to be
* combined with other objects * combined with other objects
* @param isOutside Whether the cylinder is an outside face (true) or inside face (false) * @param isOutside Whether the cylinder is an outside face (true) or inside face (false)
* @param bottomRingVertices A list to add the bottom ring vertex indices to * @param foreRingVertices A list to add the fore (top) ring vertex indices to
* @param topRingVertices A list to add the top ring vertex indices to * @param aftRingVertices A list to add the aft (bottom) ring vertex indices to
*/ */
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float length, int numSides, boolean solid, boolean isOutside, float foreRadius, float aftRadius, float length, int numSides, boolean solid, boolean isOutside,
List<Integer> bottomRingVertices, List<Integer> topRingVertices) { List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
// Set the new group // Set the new group
if (groupName != null) { if (groupName != null) {
obj.setActiveGroupNames(groupName); obj.setActiveGroupNames(groupName);
@ -47,10 +48,10 @@ public class CylinderExporter {
} }
// Generate side top vertices // Generate side top vertices
generateRingVertices(obj, transformer, startIdx, numSides, 0, radius, isOutside, topRingVertices); generateRingVertices(obj, transformer, startIdx, numSides, 0, foreRadius, isOutside, foreRingVertices);
// Generate side bottom vertices // Generate side bottom vertices
generateRingVertices(obj, transformer, startIdx + numSides, numSides, length, radius, isOutside, bottomRingVertices); generateRingVertices(obj, transformer, startIdx + numSides, numSides, length, aftRadius, isOutside, aftRingVertices);
// Create faces for the bottom and top // Create faces for the bottom and top
if (solid) { if (solid) {
@ -111,28 +112,34 @@ public class CylinderExporter {
} }
} }
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float length, int numSides, boolean solid, boolean isOutside,
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, radius, length, numSides, solid, isOutside, foreRingVertices, aftRingVertices);
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float height, int numSides, boolean solid, float radius, float height, int numSides, boolean solid,
List<Integer> bottomRingVertices, List<Integer> topRingVertices) { List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, height, numSides, solid, true, bottomRingVertices, topRingVertices); addCylinderMesh(obj, transformer, groupName, radius, height, numSides, solid, true, foreRingVertices, aftRingVertices);
} }
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float height, boolean solid, ObjUtils.LevelOfDetail LOD, float radius, float height, boolean solid, ObjUtils.LevelOfDetail LOD,
List<Integer> bottomRingVertices, List<Integer> topRingVertices) { List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, height, LOD.getNrOfSides(radius), solid, bottomRingVertices, topRingVertices); addCylinderMesh(obj, transformer, groupName, radius, height, LOD.getNrOfSides(radius), solid, foreRingVertices, aftRingVertices);
} }
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float height, boolean solid, boolean isOutside, int nrOfSlices, float radius, float height, boolean solid, boolean isOutside, int nrOfSlices,
List<Integer> bottomRingVertices, List<Integer> topRingVertices) { List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, isOutside, bottomRingVertices, topRingVertices); addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, isOutside, foreRingVertices, aftRingVertices);
} }
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float height, boolean solid, int nrOfSlices, float radius, float height, boolean solid, int nrOfSlices,
List<Integer> bottomRingVertices, List<Integer> topRingVertices) { List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, bottomRingVertices, topRingVertices); addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, foreRingVertices, aftRingVertices);
} }
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,

View File

@ -6,6 +6,7 @@ import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.file.wavefrontobj.DefaultObjFace; import net.sf.openrocket.file.wavefrontobj.DefaultObjFace;
import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter.generateRingVertices; import static net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter.generateRingVertices;
@ -16,23 +17,25 @@ public class TubeExporter {
* It is drawn in the origin of the OBJ coordinate system. The longitudinal axis is positive, converted OpenRocket x-axis. * It is drawn in the origin of the OBJ coordinate system. The longitudinal axis is positive, converted OpenRocket x-axis.
* @param obj The obj to add the mesh to * @param obj The obj to add the mesh to
* @param groupName The name of the group to add the mesh to, or null if no group should be added (use the active group) * @param groupName The name of the group to add the mesh to, or null if no group should be added (use the active group)
* @param aftOuterRadius The outer radius of the aft (bottom) of the tube
* @param foreOuterRadius The outer radius of the fore (top) of the tube * @param foreOuterRadius The outer radius of the fore (top) of the tube
* @param aftInnerRadius The inner radius of the aft (bottom) of the tube * @param aftOuterRadius The outer radius of the aft (bottom) of the tube
* @param foreInnerRadius The inner radius of the fore (top) of the tube * @param foreInnerRadius The inner radius of the fore (top) of the tube
* Set to 0, together with aftInnerRadius, to create a solid tube
* @param aftInnerRadius The inner radius of the aft (bottom) of the tube
* Set to 0, together with foreInnerRadius, to create a solid tube
* @param length The length of the tube * @param length The length of the tube
* @param numSides The number of sides of the tube * @param numSides The number of sides of the tube
* @param bottomOuterVertices A list to add the indices of the bottom outer vertices to, or null if the indices are not needed * @param foreOuterVertices A list to add the indices of the fore (top) outer vertices to, or null if the indices are not needed
* @param topOuterVertices A list to add the indices of the top outer vertices to, or null if the indices are not needed * @param aftOuterVertices A list to add the indices of the aft (bottom) outer vertices to, or null if the indices are not needed
* @param bottomInnerVertices A list to add the indices of the bottom inner vertices to, or null if the indices are not needed * @param foreInnerVertices A list to add the indices of the fore (top) inner vertices to, or null if the indices are not needed
* @param topInnerVertices A list to add the indices of the top inner vertices to, or null if the indices are not needed * @param aftInnerVertices A list to add the indices of the aft (bottom) inner vertices to, or null if the indices are not needed
*/ */
public static void addTubeMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName, public static void addTubeMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float aftOuterRadius, float foreOuterRadius, float foreOuterRadius, float aftOuterRadius,
float aftInnerRadius, float foreInnerRadius, float length, int numSides, float foreInnerRadius, float aftInnerRadius, float length, int numSides,
List<Integer> bottomOuterVertices, List<Integer> topOuterVertices, List<Integer> foreOuterVertices, List<Integer> aftOuterVertices,
List<Integer> bottomInnerVertices, List<Integer> topInnerVertices) { List<Integer> foreInnerVertices, List<Integer> aftInnerVertices) {
if (aftInnerRadius > aftOuterRadius || foreInnerRadius > foreOuterRadius) { if (Float.compare(aftInnerRadius, aftOuterRadius) > 0 || Float.compare(foreInnerRadius, foreOuterRadius) > 0) {
throw new IllegalArgumentException("Inner radius must be less than outer radius"); throw new IllegalArgumentException("Inner radius must be less than outer radius");
} }
@ -41,102 +44,38 @@ public class TubeExporter {
obj.setActiveGroupNames(groupName); obj.setActiveGroupNames(groupName);
} }
// Other meshes may have been added to the obj, so we need to keep track of the starting indices // We need to store the vertices to create the closing disks, so we'll create lists if they do not exist
int startIdx = obj.getNumVertices(); if (foreOuterVertices == null) {
int normalsStartIdx = obj.getNumNormals(); foreOuterVertices = new ArrayList<>();
}
obj.addNormal(transformer.convertLocWithoutOriginOffs(-1, 0, 0)); // Top faces normal if (aftOuterVertices == null) {
obj.addNormal(transformer.convertLocWithoutOriginOffs(1, 0, 0)); // Bottom faces normal aftOuterVertices = new ArrayList<>();
}
// Generate top outside vertices if (foreInnerVertices == null) {
generateRingVertices(obj, transformer, startIdx, numSides, 0, foreOuterRadius, true, topOuterVertices); foreInnerVertices = new ArrayList<>();
}
// Generate top inside vertices if (aftInnerVertices == null) {
generateRingVertices(obj, transformer, startIdx + numSides, numSides, 0, foreInnerRadius, false, topInnerVertices); aftInnerVertices = new ArrayList<>();
// Generate bottom outside vertices
generateRingVertices(obj, transformer, startIdx + 2*numSides, numSides, length, aftOuterRadius, true, bottomOuterVertices);
// Generate bottom inside vertices
generateRingVertices(obj, transformer, startIdx + 3*numSides, numSides, length, aftInnerRadius, false, bottomInnerVertices);
// Create top faces
for (int i = 0; i < numSides; i++) {
int[] vertexIndices = new int[] {
i, // Bottom-left of quad outside vertex
((i + 1) % numSides), // Bottom-right of quad outside vertex
numSides + ((i + 1) % numSides), // Top-right of quad inside vertex
numSides + i, // Top-left of quad inside vertex
};
ObjUtils.offsetIndex(vertexIndices, startIdx);
int[] normalIndices = new int[] {0, 0, 0, 0};
ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face);
} }
// Create bottom faces // Generate inside mesh
for (int i = 0; i < numSides; i++) { boolean hasForeThickness = Float.compare(foreOuterRadius, foreInnerRadius) > 0 && Float.compare(foreInnerRadius, 0) > 0;
int[] vertexIndices = new int[] { boolean hasAftThickness = Float.compare(aftOuterRadius, aftInnerRadius) > 0 && Float.compare(aftInnerRadius, 0) > 0;
2*numSides + i, // Bottom-left of quad outside vertex if (hasForeThickness || hasAftThickness) {
3*numSides + i, // Top-left of quad inside vertex CylinderExporter.addCylinderMesh(obj, transformer, null, foreInnerRadius, aftInnerRadius, length, numSides,
3*numSides + ((i + 1) % numSides), // Top-right of quad inside vertex false, false, foreInnerVertices, aftInnerVertices);
2*numSides + ((i + 1) % numSides), // Bottom-right of quad outside vertex
};
ObjUtils.offsetIndex(vertexIndices, startIdx);
int[] normalIndices = new int[] {1, 1, 1, 1};
ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face);
} }
// Create outside side faces // Generate outside mesh
for (int i = 0; i < numSides; i++) { CylinderExporter.addCylinderMesh(obj, transformer, null, foreOuterRadius, aftOuterRadius, length, numSides,
final int nextIdx = (i + 1) % numSides; !hasForeThickness && !hasAftThickness, true, foreOuterVertices, aftOuterVertices);
int[] vertexIndices = new int[]{
i, // Bottom-left of quad outside vertex
2*numSides + i, // Top-left of quad outside vertex
2*numSides + nextIdx, // Top-right of quad outside vertex
nextIdx, // Bottom-right of quad outside vertex
};
ObjUtils.offsetIndex(vertexIndices, startIdx);
int[] normalIndices = new int[]{ // Close the mesh
i, // Bottom-left of quad outside vertex if (hasForeThickness) {
2*numSides + i, // Top-left of quad outside vertex DiskExporter.closeDiskMesh(obj, transformer, null, foreOuterVertices, foreInnerVertices, false, true);
2*numSides + nextIdx, // Top-right of quad outside vertex
nextIdx, // Bottom-right of quad outside vertex
};
ObjUtils.offsetIndex(normalIndices, normalsStartIdx + 2); // Extra 2 offset for bottom and top normals
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face);
} }
if (hasAftThickness) {
// Create inside side faces DiskExporter.closeDiskMesh(obj, transformer, null, aftOuterVertices, aftInnerVertices, false, false);
for (int i = 0; i < numSides; i++) {
final int nextIdx = (i + 1) % numSides;
int[] vertexIndices = new int[]{
numSides + i, // Bottom-left of quad inside vertex
numSides + nextIdx, // Bottom-right of quad inside vertex
3*numSides + nextIdx, // Top-right of quad inside vertex
3*numSides + i, // Top-left of quad inside vertex
};
ObjUtils.offsetIndex(vertexIndices, startIdx);
int[] normalIndices = new int[]{
numSides + i, // Bottom-left of quad inside vertex
numSides + nextIdx, // Bottom-right of quad inside vertex
3*numSides + nextIdx, // Top-right of quad inside vertex
3*numSides + i, // Top-left of quad inside vertex
};
ObjUtils.offsetIndex(normalIndices, normalsStartIdx + 2); // Extra 2 offset for bottom and top normals
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face);
} }
} }

View File

@ -12,7 +12,6 @@ import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.OpenRocketDocumentFactory; import net.sf.openrocket.document.OpenRocketDocumentFactory;
import net.sf.openrocket.file.GeneralRocketLoader; import net.sf.openrocket.file.GeneralRocketLoader;
import net.sf.openrocket.file.RocketLoadException; import net.sf.openrocket.file.RocketLoadException;
import net.sf.openrocket.file.openrocket.OpenRocketSaver;
import net.sf.openrocket.file.openrocket.OpenRocketSaverTest; import net.sf.openrocket.file.openrocket.OpenRocketSaverTest;
import net.sf.openrocket.file.wavefrontobj.CoordTransform; import net.sf.openrocket.file.wavefrontobj.CoordTransform;
import net.sf.openrocket.file.wavefrontobj.DefaultCoordTransform; import net.sf.openrocket.file.wavefrontobj.DefaultCoordTransform;
@ -33,8 +32,6 @@ import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
import net.sf.openrocket.rocketcomponent.TubeFinSet; import net.sf.openrocket.rocketcomponent.TubeFinSet;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.TestRockets;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -47,13 +44,8 @@ import java.util.List;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
public class OBJExporterFactoryTest { public class OBJExporterFactoryTest {
private final OpenRocketSaver saver = new OpenRocketSaver();
private static final File TMP_DIR = new File("./tmp/"); private static final File TMP_DIR = new File("./tmp/");
public static final String SIMULATION_EXTENSION_SCRIPT = "// Test < &\n// >\n// <![CDATA[";
private static Injector injector;
@BeforeClass @BeforeClass
public static void setup() { public static void setup() {
Module applicationModule = new ServicesForTesting(); Module applicationModule = new ServicesForTesting();
@ -68,7 +60,7 @@ public class OBJExporterFactoryTest {
} }
}; };
injector = Guice.createInjector(Modules.override(applicationModule).with(dbOverrides), pluginModule); Injector injector = Guice.createInjector(Modules.override(applicationModule).with(dbOverrides), pluginModule);
Application.setInjector(injector); Application.setInjector(injector);
if (!(TMP_DIR.exists() && TMP_DIR.isDirectory())) { if (!(TMP_DIR.exists() && TMP_DIR.isDirectory())) {
@ -81,6 +73,7 @@ public class OBJExporterFactoryTest {
@Test @Test
public void testExport() throws IOException { public void testExport() throws IOException {
// Rocket generation
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket(); Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
AxialStage sustainer = rocket.getStage(0); AxialStage sustainer = rocket.getStage(0);
@ -156,43 +149,35 @@ public class OBJExporterFactoryTest {
InnerTube innerTube = new InnerTube(); InnerTube innerTube = new InnerTube();
bodyTube.addChild(innerTube); bodyTube.addChild(innerTube);
rocket = loadRocket("/Users/SiboVanGool/Downloads/blbl.ork").getRocket(); // TODO: delete me
// ------------------------------
// Create a list of components to export
List<RocketComponent> components = List.of(rocket); List<RocketComponent> components = List.of(rocket);
// Create a temp file for storing the exported OBJ
Path tempFile = Files.createTempFile("testExport", ".obj"); Path tempFile = Files.createTempFile("testExport", ".obj");
String filePath = tempFile.toAbsolutePath().toString(); String filePath = tempFile.toAbsolutePath().toString();
filePath = "/Users/SiboVanGool/Downloads/testExport.obj"; // TODO: delete me
TestRockets.dumpRocket(rocket, "/Users/SiboVanGool/Downloads/test.ork"); // TODO: delete me
// Do the exporting
CoordTransform transformer = new DefaultCoordTransform(rocket.getLength()); CoordTransform transformer = new DefaultCoordTransform(rocket.getLength());
OBJExporterFactory exporterFactory = new OBJExporterFactory(components, rocket.getSelectedConfiguration(), true, false, true, OBJExporterFactory exporterFactory = new OBJExporterFactory(components, rocket.getSelectedConfiguration(), true, false, true,
transformer, filePath); transformer, filePath);
exporterFactory.doExport(); exporterFactory.doExport();
// Test with other parameters
/*noseCone.setShoulderCapped(false);
railButton.setScrewHeight(0);
// Test with other parameters
noseCone.setShoulderCapped(false);
railButton.setScrewHeight(0);
bodyTube.setFilled(true);
transformer = new DefaultCoordTransform(rocket.getLength()); transformer = new DefaultCoordTransform(rocket.getLength());
exporterFactory = new OBJExporterFactory(components, false, false, true, exporterFactory = new OBJExporterFactory(components, rocket.getSelectedConfiguration(), false, false, true,
transformer, filePath); transformer, filePath);
exporterFactory.doExport();*/ exporterFactory.doExport();
// Clean up
Files.delete(tempFile); Files.delete(tempFile);
} }
private OpenRocketDocument loadRocket(String fileName) {
GeneralRocketLoader loader = new GeneralRocketLoader(new File(fileName));
OpenRocketDocument rocketDoc = null;
try {
rocketDoc = loader.load();
} catch (RocketLoadException e) {
e.printStackTrace();
fail("RocketLoadException while loading file " + fileName + " : " + e.getMessage());
}
return rocketDoc;
}
} }