WIP - FIX COORDINATE SYSTEM!!

This commit is contained in:
SiboVG 2023-08-09 01:30:16 +02:00
parent 081afdb635
commit 6efd39b453
15 changed files with 153 additions and 168 deletions

View File

@ -4,6 +4,8 @@ import de.javagl.obj.FloatTuple;
import de.javagl.obj.Obj; import de.javagl.obj.Obj;
import de.javagl.obj.ObjFace; import de.javagl.obj.ObjFace;
import de.javagl.obj.ObjGroup; import de.javagl.obj.ObjGroup;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate;
import java.util.List; import java.util.List;
@ -298,6 +300,29 @@ public class ObjUtils {
} }
} }
/**
* Translates the vertices in the obj file so that the component is at the specified location.
* See explanation in {@link net.sf.openrocket.file.wavefrontobj.export.OBJExporterFactory} about the difference in
* coordinate system between OpenRocket and Wavefront OBJ.
* @param obj The obj file to translate
* @param component The component to translate
* @param startIdx The index of the first vertex to translate
* @param endIdx The index of the last vertex to translate (inclusive)
* @param location The location to translate the component to (in OpenRocket coordinate system)
* @param yOffset The offset to apply to the y coordinate of the location
*/
public static void translateVerticesFromComponentLocation(DefaultObj obj, RocketComponent component,
int startIdx, int endIdx, Coordinate location, double yOffset) {
final double rocketLength = component.getRocket().getLength();
// Translate the mesh
final float x = (float) location.y;
final float y = (float) (rocketLength + yOffset - location.x);
final float z = (float) - location.z;
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
}
/** /**
* Merge a list of objs into a single obj. * Merge a list of objs into a single obj.
* @param objs The objs to merge * @param objs The objs to merge

View File

@ -32,6 +32,20 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
/**
* Exporter for rocket components to a Wavefront OBJ file.
* <b>NOTE: </b> The coordinate system of the Wavefront OBJ file and OpenRocket is different.
* An OBJ file has the y-axis pointing up, the z-axis pointing towards the viewer, and the x-axis pointing to the right (right-handed system).
* OpenRocket uses a left-handed system with the y-axis pointing up, the z-axis pointing away from the viewer, and the
* x-axis pointing to the right (in the side view). Its origin is also at the tip of the rocket, whereas for the OBJ it
* would be the bottom of the rocket.
* => the following transformation applies from OBJ coordinate system to OpenRocket coordinate system:
* x = y
* y = rocketLength - x
* z = -z
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public class OBJExporterFactory { public class OBJExporterFactory {
private final List<RocketComponent> components; private final List<RocketComponent> components;

View File

@ -5,7 +5,6 @@ import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter;
import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter;
import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
public class BodyTubeExporter extends RocketComponentExporter { public class BodyTubeExporter extends RocketComponentExporter {
@ -21,17 +20,16 @@ public class BodyTubeExporter extends RocketComponentExporter {
final float innerRadius = (float) bodyTube.getInnerRadius(); final float innerRadius = (float) bodyTube.getInnerRadius();
final float length = (float) bodyTube.getLength(); final float length = (float) bodyTube.getLength();
final boolean isFilled = bodyTube.isFilled(); final boolean isFilled = bodyTube.isFilled();
final double rocketLength = bodyTube.getRocket().getLength();
final Coordinate[] locations = bodyTube.getComponentLocations(); final Coordinate[] locations = bodyTube.getComponentLocations();
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(outerRadius, innerRadius, length, isFilled, rocketLength, location); generateMesh(bodyTube, outerRadius, innerRadius, length, isFilled, location);
} }
} }
private void generateMesh(float outerRadius, float innerRadius, float length, boolean isFilled, private void generateMesh(BodyTube bodyTube, float outerRadius, float innerRadius, float length, boolean isFilled,
double rocketLength, Coordinate location) { Coordinate location) {
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
if (isFilled || Float.compare(innerRadius, 0) == 0) { if (isFilled || Float.compare(innerRadius, 0) == 0) {
@ -46,10 +44,7 @@ public class BodyTubeExporter extends RocketComponentExporter {
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 // Translate the mesh to the position in the rocket
final float x = (float) location.y; ObjUtils.translateVerticesFromComponentLocation(obj, bodyTube, startIdx, endIdx, location, -length);
final float y = (float) (rocketLength - length - location.x);
final float z = (float) location.z;
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
} }
} }

View File

@ -4,9 +4,6 @@ import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.PolygonExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.PolygonExporter;
import net.sf.openrocket.rocketcomponent.FinSet; import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
import net.sf.openrocket.util.ArrayUtils;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
import java.util.ArrayList; import java.util.ArrayList;
@ -43,12 +40,12 @@ public class FinSetExporter extends RocketComponentExporter {
// Generate the fin meshes // Generate the fin meshes
for (int i = 0; i < locations.length; i++) { for (int i = 0; i < locations.length; i++) {
generateMesh(finSet,floatPoints, floatTabPoints, thickness, hasTabs, rocketLength, locations[i], angles[i]); generateMesh(finSet,floatPoints, floatTabPoints, thickness, hasTabs, locations[i], angles[i]);
} }
} }
private void generateMesh(FinSet finSet, FloatPoints floatPoints, FloatPoints floatTabPoints, float thickness, private void generateMesh(FinSet finSet, FloatPoints floatPoints, FloatPoints floatTabPoints, float thickness,
boolean hasTabs, double rocketLength, Coordinate location, double angle) { boolean hasTabs, Coordinate location, double angle) {
// Generate the mesh // Generate the mesh
final int startIdx = obj.getNumVertices(); final int startIdx = obj.getNumVertices();
final int normalsStartIdx = obj.getNumNormals(); final int normalsStartIdx = obj.getNumNormals();
@ -58,7 +55,6 @@ public class FinSetExporter extends RocketComponentExporter {
floatPoints.getXCoords(), floatPoints.getYCoords(), thickness); floatPoints.getXCoords(), floatPoints.getYCoords(), thickness);
// Generate the fin tabs // Generate the fin tabs
final int tabStartIdx = obj.getNumVertices();
if (hasTabs) { if (hasTabs) {
PolygonExporter.addPolygonMesh(obj, null, PolygonExporter.addPolygonMesh(obj, null,
floatTabPoints.getXCoords(), floatTabPoints.getYCoords(), thickness); floatTabPoints.getXCoords(), floatTabPoints.getYCoords(), thickness);
@ -67,23 +63,18 @@ public class FinSetExporter extends RocketComponentExporter {
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
int normalsEndIdx = Math.max(obj.getNumNormals() - 1, normalsStartIdx); // Clamp in case no normals were added int normalsEndIdx = Math.max(obj.getNumNormals() - 1, normalsStartIdx); // Clamp in case no normals were added
// First rotate the fin for a correct orientation // First rotate for the cant angle
final float axialRot = (float) angle; final float cantAngle = (float) - finSet.getCantAngle();
final float cantAngle = (float) finSet.getCantAngle();
ObjUtils.rotateVertices(obj, startIdx, endIdx, normalsStartIdx, normalsEndIdx, ObjUtils.rotateVertices(obj, startIdx, endIdx, normalsStartIdx, normalsEndIdx,
-(float) Math.PI/2, cantAngle, axialRot, 0, 0, 0); cantAngle, 0, 0, 0, (float) - finSet.getLength(), 0);
// Translate the mesh // Then do the axial rotation
final float x = (float) location.y; final float axialRot = (float) angle;
final float y = (float) (rocketLength - location.x); ObjUtils.rotateVertices(obj, startIdx, endIdx, normalsStartIdx, normalsEndIdx,
final float z = (float) location.z; 0, axialRot, 0, 0, 0, 0);
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
// Offset the tabs // Translate the mesh to the position in the rocket
if (hasTabs) { ObjUtils.translateVerticesFromComponentLocation(obj, finSet, startIdx, endIdx, location, 0);
float yTab = - (float) finSet.getTabPosition(AxialMethod.TOP);
ObjUtils.translateVertices(obj, tabStartIdx, endIdx, 0, yTab, 0);
}
} }
/** /**

View File

@ -5,7 +5,6 @@ import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter;
import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter;
import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
public class LaunchLugExporter extends RocketComponentExporter { public class LaunchLugExporter extends RocketComponentExporter {
@ -18,19 +17,18 @@ public class LaunchLugExporter extends RocketComponentExporter {
final LaunchLug lug = (LaunchLug) component; final LaunchLug lug = (LaunchLug) component;
final Coordinate[] locations = lug.getComponentLocations(); final Coordinate[] locations = lug.getComponentLocations();
final double rocketLength = lug.getRocket().getLength();
final float outerRadius = (float) lug.getOuterRadius(); final float outerRadius = (float) lug.getOuterRadius();
final float innerRadius = (float) lug.getInnerRadius(); final float innerRadius = (float) lug.getInnerRadius();
final float length = (float) lug.getLength(); final float length = (float) lug.getLength();
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(lug, outerRadius, innerRadius, length, rocketLength, location); generateMesh(lug, outerRadius, innerRadius, length, location);
} }
} }
private void generateMesh(LaunchLug lug, float outerRadius, float innerRadius, float length, double rocketLength, Coordinate location) { private void generateMesh(LaunchLug lug, float outerRadius, float innerRadius, float length, Coordinate location) {
int startIdx2 = obj.getNumVertices(); int startIdx = obj.getNumVertices();
// Generate the instance mesh // Generate the instance mesh
if (Float.compare(innerRadius, 0) == 0) { if (Float.compare(innerRadius, 0) == 0) {
@ -43,12 +41,9 @@ public class LaunchLugExporter extends RocketComponentExporter {
} }
} }
int endIdx2 = Math.max(obj.getNumVertices() - 1, startIdx2); // Clamp in case no vertices were added int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Translate the lug instance // Translate the mesh to the position in the rocket
final float x = (float) location.y; ObjUtils.translateVerticesFromComponentLocation(obj, lug, startIdx, endIdx, location, -length);
final float y = (float) (rocketLength - lug.getLength() - location.x);
final float z = (float) location.z;
ObjUtils.translateVertices(obj, startIdx2, endIdx2, x, y, z);
} }
} }

View File

@ -4,7 +4,6 @@ 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 net.sf.openrocket.rocketcomponent.MassObject; import net.sf.openrocket.rocketcomponent.MassObject;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.RocketComponentUtils; import net.sf.openrocket.util.RocketComponentUtils;
@ -20,20 +19,18 @@ public class MassObjectExporter extends RocketComponentExporter {
obj.setActiveGroupNames(groupName); obj.setActiveGroupNames(groupName);
final Coordinate[] locations = massObject.getComponentLocations(); final Coordinate[] locations = massObject.getComponentLocations();
final double rocketLength = massObject.getRocket().getLength();
final int numSides = LOD.getValue() / 2; final int numSides = LOD.getValue() / 2;
final int numStacks = LOD.getValue() / 2; final int numStacks = LOD.getValue() / 2;
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(massObject, numSides, numStacks, rocketLength, location); generateMesh(massObject, numSides, numStacks, location);
} }
} }
private void generateMesh(MassObject massObject, int numSides, int numStacks, double rocketLength, Coordinate location) { private void generateMesh(MassObject massObject, int numSides, int numStacks, Coordinate location) {
// Other meshes may have been added to the obj, so we need to keep track of the starting indices // Other meshes may have been added to the obj, so we need to keep track of the starting indices
int verticesStartIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
int normalsStartIdx = obj.getNumNormals(); int normalsStartIdx = obj.getNumNormals();
double dy = massObject.getLength() / numStacks; double dy = massObject.getLength() / numStacks;
double da = 2.0f * Math.PI / numSides; double da = 2.0f * Math.PI / numSides;
@ -72,7 +69,7 @@ public class MassObjectExporter extends RocketComponentExporter {
} }
} }
int endIdx = Math.max(obj.getNumVertices() - 1, verticesStartIdx); // Clamp in case no vertices were added int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Create bottom tip faces // Create bottom tip faces
for (int i = 0; i < numSides; i++) { for (int i = 0; i < numSides; i++) {
@ -86,7 +83,7 @@ public class MassObjectExporter extends RocketComponentExporter {
int[] normalIndices = vertexIndices.clone(); // For a smooth surface, the vertex and normal indices are the same int[] normalIndices = vertexIndices.clone(); // For a smooth surface, the vertex and normal indices are the same
ObjUtils.offsetIndex(normalIndices, normalsStartIdx); ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
ObjUtils.offsetIndex(vertexIndices, verticesStartIdx); // Only do this after normals are added, since the vertex indices are used for normals ObjUtils.offsetIndex(vertexIndices, startIdx); // Only do this after normals are added, since the vertex indices are used for normals
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices); DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face); obj.addFace(face);
@ -106,7 +103,7 @@ public class MassObjectExporter extends RocketComponentExporter {
int[] normalIndices = vertexIndices.clone(); // For a smooth surface, the vertex and normal indices are the same int[] normalIndices = vertexIndices.clone(); // For a smooth surface, the vertex and normal indices are the same
ObjUtils.offsetIndex(normalIndices, normalsStartIdx); ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
ObjUtils.offsetIndex(vertexIndices, verticesStartIdx); // Only do this after normals are added, since the vertex indices are used for normals ObjUtils.offsetIndex(vertexIndices, startIdx); // Only do this after normals are added, since the vertex indices are used for normals
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices); DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face); obj.addFace(face);
@ -134,12 +131,18 @@ public class MassObjectExporter extends RocketComponentExporter {
obj.addFace(face); obj.addFace(face);
} }
// Translate the mesh // Translate the mesh to the position in the rocket
// We will create an offset location that has the same effect as the axial rotation of the mass object
Coordinate offsetLocation = getOffsetLocation(massObject, location);
ObjUtils.translateVerticesFromComponentLocation(obj, massObject, startIdx, endIdx, offsetLocation, -massObject.getLength());
}
private static Coordinate getOffsetLocation(MassObject massObject, Coordinate location) {
// ! This is all still referenced to the OpenRocket coordinate system, not the OBJ one
final double radialPosition = massObject.getRadialPosition(); final double radialPosition = massObject.getRadialPosition();
final double radialDirection = massObject.getRadialDirection(); final double radialDirection = massObject.getRadialDirection();
final float x = (float) (location.y + radialPosition * Math.cos(radialDirection)); final double y = location.y + radialPosition * Math.cos(radialDirection);
final float y = (float) (rocketLength - massObject.getLength() - location.x); final double z = location.z + radialPosition * Math.sin(radialDirection);
final float z = (float) (location.z + radialPosition * Math.sin(radialDirection)); return new Coordinate(location.x, y, z);
ObjUtils.translateVertices(obj, verticesStartIdx, endIdx, x, y, z);
} }
} }

View File

@ -5,7 +5,6 @@ import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter;
import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter;
import net.sf.openrocket.rocketcomponent.RadiusRingComponent; import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
public class RadiusRingComponentExporter extends RocketComponentExporter { public class RadiusRingComponentExporter extends RocketComponentExporter {
@ -25,11 +24,11 @@ public class RadiusRingComponentExporter extends RocketComponentExporter {
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(outerRadius, innerRadius, thickness, rocketLength, location); generateMesh(outerRadius, innerRadius, thickness, location);
} }
} }
private void generateMesh(float outerRadius, float innerRadius, float thickness, double rocketLength, Coordinate location) { private void generateMesh(float outerRadius, float innerRadius, float thickness, Coordinate location) {
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
if (Float.compare(innerRadius, 0) == 0) { if (Float.compare(innerRadius, 0) == 0) {
@ -44,10 +43,7 @@ public class RadiusRingComponentExporter extends RocketComponentExporter {
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 // Translate the mesh to the position in the rocket
final float x = (float) location.y; ObjUtils.translateVerticesFromComponentLocation(obj, component, startIdx, endIdx, location, -thickness);
final float y = (float) (rocketLength - thickness - location.x);
final float z = (float) location.z;
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
} }
} }

View File

@ -38,19 +38,18 @@ public class RailButtonExporter extends RocketComponentExporter {
final float flangeHeight = (float) railButton.getFlangeHeight(); final float flangeHeight = (float) railButton.getFlangeHeight();
final float screwHeight = (float) railButton.getScrewHeight(); final float screwHeight = (float) railButton.getScrewHeight();
final Coordinate[] locations = railButton.getComponentLocations(); final Coordinate[] locations = railButton.getComponentLocations();
final double[] angles = railButton.getInstanceAngles(); final double[] angles = railButton.getComponentAngles();
final double rocketLength = railButton.getRocket().getLength();
// Generate the mesh // Generate the mesh
for (int i = 0; i < locations.length; i++) { for (int i = 0; i < locations.length; i++) {
generateMesh(outerRadius, innerRadius, baseHeight, innerHeight, flangeHeight, screwHeight, generateMesh(outerRadius, innerRadius, baseHeight, innerHeight, flangeHeight, screwHeight,
rocketLength, locations[i], angles[i]); locations[i], angles[i]);
} }
} }
private void generateMesh(float outerRadius, float innerRadius, float baseHeight, float innerHeight, float flangeHeight, private void generateMesh(float outerRadius, float innerRadius, float baseHeight, float innerHeight, float flangeHeight,
float screwHeight, double rocketLength, Coordinate location, double angle) { float screwHeight, Coordinate location, double angle) {
final int vertexStartIdx = obj.getNumVertices(); final int startIdx = obj.getNumVertices();
final int normalStartIdx = obj.getNumNormals(); final int normalStartIdx = obj.getNumNormals();
// Generate base cylinder // Generate base cylinder
@ -94,21 +93,20 @@ public class RailButtonExporter extends RocketComponentExporter {
} }
final int vertexEndIdx = Math.max(obj.getNumVertices() - 1, vertexStartIdx); final int endIdx = Math.max(obj.getNumVertices() - 1, startIdx);
final int normalEndIdx = Math.max(obj.getNumNormals() - 1, normalStartIdx); final int normalEndIdx = Math.max(obj.getNumNormals() - 1, normalStartIdx);
// Rotate the mesh (also PI/2!) // Rotate the mesh (also PI/2!)
final float rX = - (float) Math.PI / 2; final float rX = 0;
final float rY = (float) angle; final float rY = (float) angle;
final float rZ = 0; final float rZ = (float) - Math.PI / 2;
ObjUtils.rotateVertices(obj, vertexStartIdx, vertexEndIdx, normalStartIdx, normalEndIdx, ObjUtils.rotateVertices(obj, startIdx, endIdx, normalStartIdx, normalEndIdx,
rX, rY, rZ, 0, 0, 0); rX, rY, rZ, 0, 0, 0);
// Translate the mesh ObjUtils.translateVertices(obj, startIdx, endIdx, 1, 0, 0);
final float x = (float) location.y;
final float y = (float) location.x; // Translate the mesh to the position in the rocket
final float z = (float) location.z; ObjUtils.translateVerticesFromComponentLocation(obj, component, startIdx, endIdx, location, 0);
ObjUtils.translateVertices(obj, vertexStartIdx, vertexEndIdx, x, y, z);
} }
private void addScrew(DefaultObj obj, float baseHeight, float innerHeight, float flangeHeight, float outerRadius, private void addScrew(DefaultObj obj, float baseHeight, float innerHeight, float flangeHeight, float outerRadius,
@ -149,14 +147,14 @@ public class RailButtonExporter extends RocketComponentExporter {
// Generate the faces between the flange cylinder and the quad faces // Generate the faces between the flange cylinder and the quad faces
for (int i = 0; i < nrOfSlices; i++) { for (int i = 0; i < nrOfSlices; i++) {
int nextIdx = (i+1) % nrOfSlices; int nextIdx = (i + 1) % nrOfSlices;
int[] vertexIndices = new int[]{ int[] vertexIndices = new int[] {
flangeCylinderTopVertices.get(i), // Bottom-left of quad flangeCylinderTopVertices.get(i), // Bottom-left of quad
startIdx + i, // Top-left of quad startIdx + i, // Top-left of quad
startIdx + nextIdx, // Top-right of quad startIdx + nextIdx, // Top-right of quad
flangeCylinderTopVertices.get(nextIdx), // Bottom-right of quad flangeCylinderTopVertices.get(nextIdx), // Bottom-right of quad
}; };
int[] normalIndices = new int[]{ int[] normalIndices = new int[] {
flangeCylinderTopVertices.get(i), // Bottom-left of quad flangeCylinderTopVertices.get(i), // Bottom-left of quad
normalStartIdx + i, // Top-left of quad normalStartIdx + i, // Top-left of quad
normalStartIdx + nextIdx, // Top-right of quad normalStartIdx + nextIdx, // Top-right of quad
@ -170,13 +168,13 @@ public class RailButtonExporter extends RocketComponentExporter {
} }
// Generate the quad mesh faces (no tip) // Generate the quad mesh faces (no tip)
for (int i = 0; i <= nrOfStacks-2; i++) { for (int i = 0; i <= nrOfStacks-3; i++) { // We do -3 instead of -2 because we offset the i entirely by starting at 0 instead of 1 (so we don't have to offset the indices)
for (int j = 0; j < nrOfSlices; j++) { for (int j = 0; j < nrOfSlices; j++) {
int nextIdx = (j+1) % nrOfSlices; int nextIdx = (j + 1) % nrOfSlices;
int[] vertexIndices = new int[]{ int[] vertexIndices = new int[] {
i * nrOfSlices + j, // Bottom-left of quad outside vertex i * nrOfSlices + j, // Bottom-left of quad outside vertex
(i+1) * nrOfSlices + j, // Top-left of quad outside vertex (i + 1) * nrOfSlices + j, // Top-left of quad outside vertex
(i+1) * nrOfSlices + nextIdx, // Top-right of quad inside vertex (i + 1) * nrOfSlices + nextIdx, // Top-right of quad inside vertex
i * nrOfSlices + nextIdx // Bottom-right of quad inside vertex i * nrOfSlices + nextIdx // Bottom-right of quad inside vertex
}; };
int[] normalIndices = vertexIndices.clone(); int[] normalIndices = vertexIndices.clone();
@ -193,13 +191,13 @@ public class RailButtonExporter extends RocketComponentExporter {
final int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); final int endIdx = Math.max(obj.getNumVertices() - 1, startIdx);
final int normalEndIdx = Math.max(obj.getNumNormals() - 1, normalStartIdx); final int normalEndIdx = Math.max(obj.getNumNormals() - 1, normalStartIdx);
for (int i = 0; i < nrOfSlices; i++) { for (int i = 0; i < nrOfSlices; i++) {
int nextIdx = (i+1) % nrOfSlices; int nextIdx = (i + 1) % nrOfSlices;
int[] vertexIndices = new int[]{ int[] vertexIndices = new int[] {
endIdx, // Tip vertex endIdx, // Tip vertex
endIdx - nrOfSlices + nextIdx, endIdx - nrOfSlices + nextIdx,
endIdx - nrOfSlices + i, endIdx - nrOfSlices + i,
}; };
int[] normalIndices = new int[]{ int[] normalIndices = new int[] {
normalEndIdx, // Tip normal normalEndIdx, // Tip normal
normalEndIdx - nrOfSlices + nextIdx, normalEndIdx - nrOfSlices + nextIdx,
normalEndIdx - nrOfSlices + i, normalEndIdx - nrOfSlices + i,

View File

@ -4,7 +4,6 @@ import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter;
import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.ThicknessRingComponent; import net.sf.openrocket.rocketcomponent.ThicknessRingComponent;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
@ -20,16 +19,15 @@ public class ThicknessRingComponentExporter extends RocketComponentExporter {
final float outerRadius = (float) thicknessRing.getOuterRadius(); final float outerRadius = (float) thicknessRing.getOuterRadius();
final float innerRadius = (float) thicknessRing.getInnerRadius(); final float innerRadius = (float) thicknessRing.getInnerRadius();
final float length = (float) thicknessRing.getLength(); final float length = (float) thicknessRing.getLength();
final double rocketLength = thicknessRing.getRocket().getLength();
final Coordinate[] locations = thicknessRing.getComponentLocations(); final Coordinate[] locations = thicknessRing.getComponentLocations();
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(outerRadius, innerRadius, length, rocketLength, location); generateMesh(outerRadius, innerRadius, length, location);
} }
} }
private void generateMesh(float outerRadius, float innerRadius, float length, double rocketLength, Coordinate location) { private void generateMesh(float outerRadius, float innerRadius, float length, Coordinate location) {
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
if (Float.compare(innerRadius, 0) == 0) { if (Float.compare(innerRadius, 0) == 0) {
@ -44,10 +42,7 @@ public class ThicknessRingComponentExporter extends RocketComponentExporter {
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 // Translate the mesh to the position in the rocket
final float x = (float) location.y; ObjUtils.translateVerticesFromComponentLocation(obj, component, startIdx, endIdx, location, -length);
final float y = (float) (rocketLength - length - location.x);
final float z = (float) location.z;
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
} }
} }

View File

@ -35,15 +35,14 @@ public class TransitionExporter extends RocketComponentExporter {
obj.setActiveGroupNames(groupName); obj.setActiveGroupNames(groupName);
final Coordinate[] locations = transition.getComponentLocations(); final Coordinate[] locations = transition.getComponentLocations();
final double rocketLength = transition.getRocket().getLength();
// Generate the mesh // Generate the mesh
for (Coordinate location : locations) { for (Coordinate location : locations) {
generateMesh(transition, rocketLength, location); generateMesh(transition, location);
} }
} }
private void generateMesh(Transition transition, double rocketLength, Coordinate location) { private void generateMesh(Transition transition, Coordinate location) {
int startIdx = obj.getNumVertices(); int startIdx = obj.getNumVertices();
final boolean hasForeShoulder = Double.compare(transition.getForeShoulderRadius(), 0) > 0 final boolean hasForeShoulder = Double.compare(transition.getForeShoulderRadius(), 0) > 0
@ -104,11 +103,8 @@ public class TransitionExporter extends RocketComponentExporter {
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 // Translate the mesh to the position in the rocket
final float x = (float) location.y; ObjUtils.translateVerticesFromComponentLocation(obj, transition, startIdx, endIdx, location, -transition.getLength());
final float y = (float) (rocketLength - transition.getLength() - location.x);
final float z = (float) location.z;
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
} }
/** /**
@ -127,7 +123,7 @@ public class TransitionExporter extends RocketComponentExporter {
List<Integer> foreRingVertices, List<Integer> aftRingVertices, List<Integer> foreRingVertices, List<Integer> aftRingVertices,
boolean hasForeShoulder, boolean hasAftShoulder) { boolean hasForeShoulder, boolean hasAftShoulder) {
// Other meshes may have been added to the obj, so we need to keep track of the starting indices // Other meshes may have been added to the obj, so we need to keep track of the starting indices
final int verticesStartIdx = obj.getNumVertices(); final int startIdx = obj.getNumVertices();
final int normalsStartIdx = obj.getNumNormals(); final int normalsStartIdx = obj.getNumNormals();
final double dyBase = transition.getLength() / numStacks; // Base step size in the longitudinal direction final double dyBase = transition.getLength() / numStacks; // Base step size in the longitudinal direction
@ -255,16 +251,16 @@ public class TransitionExporter extends RocketComponentExporter {
// Create aft/fore tip faces // Create aft/fore tip faces
if (isAftTip || isForeTip) { if (isAftTip || isForeTip) {
addTipFaces(obj, numSlices, isOutside, isAftTip, normalsStartIdx, verticesStartIdx); addTipFaces(obj, numSlices, isOutside, isAftTip, startIdx, normalsStartIdx);
} }
// Create regular faces // Create regular faces
int corrVStartIdx = isAftTip ? verticesStartIdx + 1 : verticesStartIdx; int corrVStartIdx = isAftTip ? startIdx + 1 : startIdx;
int corrNStartIdx = isAftTip ? normalsStartIdx + 1 : normalsStartIdx; int corrNStartIdx = isAftTip ? normalsStartIdx + 1 : normalsStartIdx;
addQuadFaces(obj, numSlices, actualNumStacks, corrVStartIdx, corrNStartIdx, isOutside); addQuadFaces(obj, numSlices, actualNumStacks, corrVStartIdx, corrNStartIdx, isOutside);
} }
private static void addTipFaces(DefaultObj obj, int numSlices, boolean isOutside, boolean isAftTip, int normalsStartIdx, int verticesStartIdx) { private static void addTipFaces(DefaultObj obj, int numSlices, boolean isOutside, boolean isAftTip, int startIdx, int normalsStartIdx) {
final int lastIdx = obj.getNumVertices() - 1; final int lastIdx = obj.getNumVertices() - 1;
for (int i = 0; i < numSlices; i++) { for (int i = 0; i < numSlices; i++) {
int nextIdx = (i + 1) % numSlices; int nextIdx = (i + 1) % numSlices;
@ -282,7 +278,7 @@ public class TransitionExporter extends RocketComponentExporter {
normalIndices = vertexIndices.clone(); // No need to reverse, already done by vertices normalIndices = vertexIndices.clone(); // No need to reverse, already done by vertices
ObjUtils.offsetIndex(normalIndices, normalsStartIdx); ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
ObjUtils.offsetIndex(vertexIndices, verticesStartIdx); // Do this last, otherwise the normal indices will be wrong ObjUtils.offsetIndex(vertexIndices, startIdx); // Do this last, otherwise the normal indices will be wrong
} }
// Fore tip // Fore tip
else { else {
@ -334,7 +330,7 @@ public class TransitionExporter extends RocketComponentExporter {
} }
} }
private static void addQuadFaces(DefaultObj obj, int numSlices, int numStacks, int verticesStartIdx, int normalsStartIdx, boolean isOutside) { private static void addQuadFaces(DefaultObj obj, int numSlices, int numStacks, int startIdx, int normalsStartIdx, boolean isOutside) {
for (int i = 0; i < numStacks - 1; i++) { for (int i = 0; i < numStacks - 1; i++) {
for (int j = 0; j < numSlices; j++) { for (int j = 0; j < numSlices; j++) {
final int nextIdx = (j + 1) % numSlices; final int nextIdx = (j + 1) % numSlices;
@ -349,7 +345,7 @@ public class TransitionExporter extends RocketComponentExporter {
int[] normalIndices = vertexIndices.clone(); // No reversing needed, already done by vertices int[] normalIndices = vertexIndices.clone(); // No reversing needed, already done by vertices
ObjUtils.offsetIndex(normalIndices, normalsStartIdx); ObjUtils.offsetIndex(normalIndices, normalsStartIdx);
ObjUtils.offsetIndex(vertexIndices, verticesStartIdx); // Do this last, otherwise the normal indices will be wrong ObjUtils.offsetIndex(vertexIndices, startIdx); // Do this last, otherwise the normal indices will be wrong
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices); DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
obj.addFace(face); obj.addFace(face);

View File

@ -2,9 +2,7 @@ package net.sf.openrocket.file.wavefrontobj.export.components;
import net.sf.openrocket.file.wavefrontobj.DefaultObj; import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.shapes.PolygonExporter;
import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter; import net.sf.openrocket.file.wavefrontobj.export.shapes.TubeExporter;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.TubeFinSet; import net.sf.openrocket.rocketcomponent.TubeFinSet;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
@ -45,12 +43,18 @@ public class TubeFinSetExporter extends RocketComponentExporter {
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 // Translate the mesh to the position in the rocket
final float dx = outerRadius * (float) Math.cos(angle); // We will create an offset location that has the same effect as the axial rotation of the launch lug
Coordinate offsetLocation = getOffsetLocation(outerRadius, location, angle);
ObjUtils.translateVerticesFromComponentLocation(obj, component, startIdx, endIdx, offsetLocation, -length);
}
private static Coordinate getOffsetLocation(float outerRadius, Coordinate location, double angle) {
// ! This is all still referenced to the OpenRocket coordinate system, not the OBJ one
final float dy = outerRadius * (float) Math.cos(angle);
final float dz = outerRadius * (float) Math.sin(angle); final float dz = outerRadius * (float) Math.sin(angle);
final float x = (float) location.y + dx; final double y = location.y + dy;
final float y = (float) (rocketLength - length - location.x); final double z = location.z + dz;
final float z = (float) location.z + dz; return new Coordinate(location.x, y, z);
ObjUtils.translateVertices(obj, startIdx, endIdx, x, y, z);
} }
} }

View File

@ -1,12 +1,9 @@
package net.sf.openrocket.file.wavefrontobj.export.shapes; package net.sf.openrocket.file.wavefrontobj.export.shapes;
import de.javagl.obj.ObjWriter;
import net.sf.openrocket.file.wavefrontobj.DefaultObj; 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.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List; import java.util.List;
public class CylinderExporter { public class CylinderExporter {
@ -171,12 +168,4 @@ public class CylinderExporter {
public static void addCylinderMesh(DefaultObj obj, String groupName, float radius, float height, boolean solid) { public static void addCylinderMesh(DefaultObj obj, String groupName, float radius, float height, boolean solid) {
addCylinderMesh(obj, groupName, radius, height, solid, ObjUtils.LevelOfDetail.NORMAL); addCylinderMesh(obj, groupName, radius, height, solid, ObjUtils.LevelOfDetail.NORMAL);
} }
public static void main(String[] args) throws Exception {
DefaultObj obj = new DefaultObj();
addCylinderMesh(obj, "cylinder", 1, 2, 15, true, null, null);
try (OutputStream objOutputStream = new FileOutputStream("/Users/SiboVanGool/Downloads/cylinder.obj")) {
ObjWriter.write(obj, objOutputStream);
}
}
} }

View File

@ -1,18 +1,13 @@
package net.sf.openrocket.file.wavefrontobj.export.shapes; package net.sf.openrocket.file.wavefrontobj.export.shapes;
import de.javagl.obj.ObjWriter;
import net.sf.openrocket.file.wavefrontobj.DefaultObj; 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.DefaultObjGroup;
import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class PolygonExporter { public class PolygonExporter {
/** /**
* Add a polygon mesh to the obj. It is drawn in the XY plane with the bottom left corner at the origin. * Add a polygon mesh to the obj. It is drawn in the X-Y plane (negative Y) with the bottom left corner at the origin.
* @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 pointLocationsX The x locations of the points --> NOTE: points should follow a clockwise direction * @param pointLocationsX The x locations of the points --> NOTE: points should follow a clockwise direction
@ -37,12 +32,12 @@ public class PolygonExporter {
// Generate front face vertices // Generate front face vertices
for (int i = 0; i < pointLocationsX.length; i++) { for (int i = 0; i < pointLocationsX.length; i++) {
obj.addVertex(pointLocationsX[i], pointLocationsY[i], thickness/2); obj.addVertex(pointLocationsY[i], -pointLocationsX[i], thickness/2);
} }
// Generate back face vertices // Generate back face vertices
for (int i = 0; i < pointLocationsX.length; i++) { for (int i = 0; i < pointLocationsX.length; i++) {
obj.addVertex(pointLocationsX[i], pointLocationsY[i], -thickness/2); obj.addVertex(pointLocationsY[i], -pointLocationsX[i], -thickness/2);
} }
// Create front face // Create front face
@ -79,8 +74,8 @@ public class PolygonExporter {
ObjUtils.offsetIndex(vertexIndices, verticesStartIdx); ObjUtils.offsetIndex(vertexIndices, verticesStartIdx);
// Calculate normals for side faces // Calculate normals for side faces
final float dx = pointLocationsX[nextIdx] - pointLocationsX[i]; final float dx = pointLocationsY[nextIdx] - pointLocationsY[i];
final float dy = pointLocationsY[nextIdx] - pointLocationsY[i]; final float dy = pointLocationsX[nextIdx] - pointLocationsX[i];
// Perpendicular vector in 2D (for clockwise vertices) // Perpendicular vector in 2D (for clockwise vertices)
final float nx = -dy; final float nx = -dy;
@ -111,14 +106,4 @@ public class PolygonExporter {
throw new IllegalArgumentException("The first and last points must be different"); throw new IllegalArgumentException("The first and last points must be different");
} }
} }
public static void main(String[] args) throws Exception {
DefaultObj obj = new DefaultObj();
float[] x = new float[]{0, 0.3f, 1, 0.7f};
float[] y = new float[]{0, 0.5f, 0.5f, 0};
addPolygonMesh(obj, "polygon", x, y, 0.025f);
try (OutputStream objOutputStream = new FileOutputStream("/Users/SiboVanGool/Downloads/poly.obj")) {
ObjWriter.write(obj, objOutputStream);
}
}
} }

View File

@ -1,12 +1,9 @@
package net.sf.openrocket.file.wavefrontobj.export.shapes; package net.sf.openrocket.file.wavefrontobj.export.shapes;
import de.javagl.obj.ObjWriter;
import net.sf.openrocket.file.wavefrontobj.DefaultObj; 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.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List; import java.util.List;
public class TubeExporter { public class TubeExporter {
@ -237,13 +234,4 @@ public class TubeExporter {
public static void addTubeMesh(DefaultObj obj, String groupName, float outerRadius, float innerRadius, float height) { public static void addTubeMesh(DefaultObj obj, String groupName, float outerRadius, float innerRadius, float height) {
addTubeMesh(obj, groupName, outerRadius, outerRadius, innerRadius, innerRadius, height); addTubeMesh(obj, groupName, outerRadius, outerRadius, innerRadius, innerRadius, height);
} }
public static void main(String[] args) throws Exception {
DefaultObj obj = new DefaultObj();
//addTubeMesh(obj, "tube", 0.1f, 0.085f, 0.3f);
addTubeMesh(obj, "tube", 0.14f, 0.06f, 0.13f, 0.05f, 0.3f);
try (OutputStream objOutputStream = new FileOutputStream("/Users/SiboVanGool/Downloads/tube.obj")) {
ObjWriter.write(obj, objOutputStream);
}
}
} }

View File

@ -3,7 +3,6 @@ package net.sf.openrocket.file.wavefrontobj.export;
import net.sf.openrocket.document.OpenRocketDocumentFactory; import net.sf.openrocket.document.OpenRocketDocumentFactory;
import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.Parachute; import net.sf.openrocket.rocketcomponent.Parachute;
@ -17,11 +16,14 @@ import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.TestRockets; import net.sf.openrocket.util.TestRockets;
import org.junit.Test; import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List; import java.util.List;
public class OBJExporterFactoryTest extends BaseTestCase { public class OBJExporterFactoryTest extends BaseTestCase {
@Test @Test
public void testExport() { public void testExport() throws IOException {
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket(); Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
AxialStage sustainer = rocket.getStage(0); AxialStage sustainer = rocket.getStage(0);
@ -52,7 +54,8 @@ public class OBJExporterFactoryTest extends BaseTestCase {
finSet.setRootChord(0.05); finSet.setRootChord(0.05);
finSet.setTabLength(0.03); finSet.setTabLength(0.03);
finSet.setTabHeight(0.01); finSet.setTabHeight(0.01);
finSet.setTabOffset(0); finSet.setTabOffset(-0.0075);
finSet.setCantAngle(Math.toRadians(10));
bodyTube.addChild(finSet); bodyTube.addChild(finSet);
TubeFinSet tubeFinSet = new TubeFinSet(); TubeFinSet tubeFinSet = new TubeFinSet();
@ -82,12 +85,20 @@ public class OBJExporterFactoryTest extends BaseTestCase {
RailButton railButton = new RailButton(); RailButton railButton = new RailButton();
railButton.setScrewHeight(0.0025); railButton.setScrewHeight(0.0025);
railButton.setAngleOffset(Math.toRadians(67));
bodyTube.addChild(railButton); bodyTube.addChild(railButton);
List<RocketComponent> components = List.of(rocket);
List<RocketComponent> components = List.of(noseCone); Path tempFile = Files.createTempFile("testExport", ".obj");
OBJExporterFactory exporterFactory = new OBJExporterFactory(components, false, false, true, finSet.setFinCount(1);
finSet.setAngleOffset(Math.toRadians(45));
TestRockets.dumpRocket(rocket, "/Users/SiboVanGool/Downloads/test.ork");
OBJExporterFactory exporterFactory = new OBJExporterFactory(components, true, false, true,
"/Users/SiboVanGool/Downloads/testExport.obj"); "/Users/SiboVanGool/Downloads/testExport.obj");
exporterFactory.doExport(); exporterFactory.doExport();
Files.delete(tempFile);
} }
} }