Add triangulation method setting to OBJ export dialog

This commit is contained in:
SiboVG 2024-02-14 13:19:18 +01:00
parent dfd497b9d1
commit cca0ec4a24
7 changed files with 114 additions and 1 deletions

View File

@ -1556,6 +1556,8 @@ OBJOptionChooser.checkbox.removeOffset.ttip = <html>If true, remove the offset o
OBJOptionChooser.btn.showAdvanced = Show Advanced options
OBJOptionChooser.checkbox.triangulate = Triangulate mesh
OBJOptionChooser.checkbox.triangulate.ttip = If true, triangulate the mesh before exporting (convert all quads or high-order polygons to a triangle).
OBJOptionChooser.lbl.triangulationMethod = Triangulation method:
OBJOptionChooser.lbl.triangulationMethod.ttip = Select the desired algorithm to use for the triangulation.
OBJOptionChooser.checkbox.sRGB = Export colors in sRGB
OBJOptionChooser.checkbox.sRGB.ttip = <html>If true, export colors in sRGB instead of a linear color scheme.<br>Is useful for instance when exporting for use in Blender.</html>
OBJOptionChooser.lbl.Scaling = Scaling:
@ -1574,6 +1576,12 @@ LevelOfDetail.LOW_QUALITY = Low quality
LevelOfDetail.NORMAL_QUALITY = Normal quality
LevelOfDetail.HIGH_QUALITY = High quality
! TriangulationMethod
TriangulationMethod.SIMPLE = Simple (fast)
TriangulationMethod.SIMPLE.ttip = Simple triangulation method (fast, but may produce poor results)
TriangulationMethod.DELAUNAY = Delaunay (recommended)
TriangulationMethod.DELAUNAY.ttip = Constrained Delaunay triangulation method (recommended, but may be slow for large models)
! ThrustCurveMotorSelectionPanel
TCMotorSelPan.lbl.Selrocketmotor = Select rocket motor:
TCMotorSelPan.checkbox.hideSimilar = Hide very similar thrust curves

View File

@ -76,6 +76,43 @@ public class ObjUtils {
}
}
public enum TriangulationMethod {
SIMPLE(trans.get("TriangulationMethod.SIMPLE"), trans.get("TriangulationMethod.SIMPLE.ttip"), "SIMPLE"),
DELAUNAY(trans.get("TriangulationMethod.DELAUNAY"), trans.get("TriangulationMethod.DELAUNAY.ttip"), "DELAUNAY");
private final String label;
private final String tooltip;
private final String exportLabel;
TriangulationMethod(String label, String tooltip, String exportLabel) {
this.label = label;
this.tooltip = tooltip;
this.exportLabel = exportLabel;
}
@Override
public String toString() {
return label;
}
public String getTooltip() {
return tooltip;
}
public String getExportLabel() {
return exportLabel;
}
public static TriangulationMethod fromExportLabel(String exportLabel) {
for (TriangulationMethod tm : TriangulationMethod.values()) {
if (tm.getExportLabel().equals(exportLabel)) {
return tm;
}
}
return TriangulationMethod.DELAUNAY;
}
}
/**
* Offset the indices by the given offset

View File

@ -33,6 +33,10 @@ public class OBJExportOptions {
* If true, triangulate all faces (convert quads and higher-order polygons to triangles)
*/
private boolean triangulate;
/**
* The method to use for triangulation.
*/
private ObjUtils.TriangulationMethod triangulationMethod;
/**
* If true, use sRGB colors instead of linear color space.
*/
@ -94,6 +98,14 @@ public class OBJExportOptions {
this.triangulate = triangulate;
}
public ObjUtils.TriangulationMethod getTriangulationMethod() {
return triangulationMethod;
}
public void setTriangulationMethod(ObjUtils.TriangulationMethod triangulationMethod) {
this.triangulationMethod = triangulationMethod;
}
public boolean isExportAppearance() {
return exportAppearance;
}

View File

@ -175,7 +175,14 @@ public class OBJExporterFactory {
// Triangulate mesh
if (this.options.isTriangulate()) {
obj = TriangulationHelper.constrainedDelaunayTriangulate(obj);
ObjUtils.TriangulationMethod triangulationMethod = this.options.getTriangulationMethod();
if (triangulationMethod == ObjUtils.TriangulationMethod.DELAUNAY) {
obj = TriangulationHelper.constrainedDelaunayTriangulate(obj);
} else if (triangulationMethod == ObjUtils.TriangulationMethod.SIMPLE) {
obj = TriangulationHelper.simpleTriangulate(obj);
} else {
throw new IllegalArgumentException("Unsupported triangulation method: " + triangulationMethod);
}
}
// Remove position offset

View File

@ -128,6 +128,7 @@ public abstract class Preferences implements ChangeSource {
private static final String OBJ_EXPORT_AS_SEPARATE_FILES = "ExportAsSeparateFiles";
private static final String OBJ_REMOVE_OFFSET = "RemoveOffset";
private static final String OBJ_TRIANGULATE = "Triangulate";
private static final String OBJ_TRIANGULATION_METHOD = "TriangulationMethod";
private static final String OBJ_SRGB = "sRGB";
private static final String OBJ_LOD = "LOD";
private static final String OBJ_SCALING = "Scaling";
@ -1051,6 +1052,7 @@ public abstract class Preferences implements ChangeSource {
objExportOptionsNode.putBoolean(OBJ_EXPORT_AS_SEPARATE_FILES, options.isExportAsSeparateFiles());
objExportOptionsNode.putBoolean(OBJ_REMOVE_OFFSET, options.isRemoveOffset());
objExportOptionsNode.putBoolean(OBJ_TRIANGULATE, options.isTriangulate());
objExportOptionsNode.put(OBJ_TRIANGULATION_METHOD, options.getTriangulationMethod().getExportLabel());
objExportOptionsNode.putBoolean(OBJ_SRGB, options.isUseSRGB());
objExportOptionsNode.putFloat(OBJ_SCALING, options.getScaling());
@ -1081,6 +1083,9 @@ public abstract class Preferences implements ChangeSource {
options.setExportAsSeparateFiles(objExportOptionsNode.getBoolean(OBJ_EXPORT_AS_SEPARATE_FILES, false));
options.setRemoveOffset(objExportOptionsNode.getBoolean(OBJ_REMOVE_OFFSET, true));
options.setTriangulate(objExportOptionsNode.getBoolean(OBJ_TRIANGULATE, true));
options.setTriangulationMethod(ObjUtils.TriangulationMethod.fromExportLabel(
objExportOptionsNode.get(OBJ_TRIANGULATION_METHOD, ObjUtils.TriangulationMethod.DELAUNAY.getExportLabel())
));
options.setUseSRGB(objExportOptionsNode.getBoolean(OBJ_SRGB, false));
options.setScaling(objExportOptionsNode.getFloat(OBJ_SCALING, 1000));

View File

@ -175,6 +175,7 @@ public class OBJExporterFactoryTest {
bodyTube.setFilled(true);
options.setTriangulate(true);
options.setTriangulationMethod(ObjUtils.TriangulationMethod.DELAUNAY);
options.setRemoveOffset(false);
options.setExportAppearance(true);
options.setScaling(1000);
@ -193,6 +194,14 @@ public class OBJExporterFactoryTest {
//// Just hope for no exceptions :)
assertEquals(warnings.size(), 1);
// Test simple triangulation
options.setTriangulationMethod(ObjUtils.TriangulationMethod.SIMPLE);
exporterFactory = new OBJExporterFactory(components, rocket.getSelectedConfiguration(), tempFile.toFile(), options, warnings);
exporterFactory.doExport();
//// Just hope for no exceptions :)
assertEquals(warnings.size(), 1);
// Clean up
Files.delete(tempFile);
}

View File

@ -15,11 +15,13 @@ import net.sf.openrocket.unit.UnitGroup;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
@ -29,6 +31,7 @@ import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.Color;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -53,6 +56,7 @@ public class OBJOptionChooser extends JPanel {
private final JCheckBox exportAsSeparateFiles;
private final JCheckBox removeOffset;
private final JCheckBox triangulate;
private final JComboBox<ObjUtils.TriangulationMethod> triangulationMethod;
private final JCheckBox sRGB;
private final JComboBox<ObjUtils.LevelOfDetail> LOD;
private final DoubleModel scalingModel;
@ -236,6 +240,17 @@ public class OBJOptionChooser extends JPanel {
}
});
//// Triangulation method
JLabel tmLabel = new JLabel(trans.get("OBJOptionChooser.lbl.triangulationMethod"));
tmLabel.setToolTipText(trans.get("OBJOptionChooser.lbl.triangulationMethod.ttip"));
advancedOptionsPanel.add(tmLabel, "spanx, split 2");
this.triangulationMethod = new JComboBox<>(ObjUtils.TriangulationMethod.values());
this.triangulationMethod.setToolTipText(trans.get("OBJOptionChooser.lbl.triangulationMethod.ttip"));
this.triangulationMethod.setRenderer(new TriangulationMethodRenderer());
destroyTheMagic(triangulationMethod);
addOptimizationListener(triangulationMethod);
advancedOptionsPanel.add(triangulationMethod, "growx, wrap unrel");
//// Level of detail
JLabel LODLabel = new JLabel(trans.get("OBJOptionChooser.lbl.LevelOfDetail"));
LODLabel.setToolTipText(trans.get("OBJOptionChooser.lbl.LevelOfDetail.ttip"));
@ -394,6 +409,7 @@ public class OBJOptionChooser extends JPanel {
if (!opts.isTriangulate()) {
this.exportAppearance.setSelected(opts.isExportAppearance());
}
this.triangulationMethod.setSelectedItem(opts.getTriangulationMethod());
this.sRGB.setSelected(opts.isUseSRGB());
this.scalingModel.setValue(opts.getScaling());
@ -422,6 +438,7 @@ public class OBJOptionChooser extends JPanel {
opts.setExportAsSeparateFiles(exportAsSeparateFiles.isSelected());
opts.setRemoveOffset(removeOffset.isSelected());
opts.setTriangulate(triangulate.isSelected());
opts.setTriangulationMethod((ObjUtils.TriangulationMethod) triangulationMethod.getSelectedItem());
opts.setUseSRGB(sRGB.isSelected());
opts.setScaling((float) scalingModel.getValue());
opts.setLOD((ObjUtils.LevelOfDetail) LOD.getSelectedItem());
@ -441,6 +458,7 @@ public class OBJOptionChooser extends JPanel {
options.setRemoveOffset(true);
options.setScaling(1000);
options.setTriangulate(true);
options.setTriangulationMethod(ObjUtils.TriangulationMethod.DELAUNAY);
options.setLOD(ObjUtils.LevelOfDetail.HIGH_QUALITY);
loadOptions(options);
@ -453,6 +471,7 @@ public class OBJOptionChooser extends JPanel {
*/
private boolean isOptimizedFor3DPrinting(OBJExportOptions options) {
return !options.isExportMotors() && !options.isExportAppearance() && options.isTriangulate() &&
options.getTriangulationMethod() == ObjUtils.TriangulationMethod.DELAUNAY &&
options.getLOD() == ObjUtils.LevelOfDetail.HIGH_QUALITY && options.isRemoveOffset() && options.getScaling() == 1000;
}
@ -581,6 +600,22 @@ public class OBJOptionChooser extends JPanel {
}
}
private static class TriangulationMethodRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list,
value, index, isSelected, cellHasFocus);
if (index > -1 && value instanceof ObjUtils.TriangulationMethod) {
list.setToolTipText(((ObjUtils.TriangulationMethod) value).getTooltip());
}
return comp;
}
}
/*private void coordTransComboAction(ItemEvent e, JComboBox<Axis> otherCombo) {
if (e.getStateChange() != ItemEvent.SELECTED) {
return;