Importing of image to freeform fin set
This commit is contained in:
parent
34b6151596
commit
d320dc7086
@ -1,3 +1,7 @@
|
||||
2012-03-14 Jason Blood
|
||||
|
||||
* Importing images to freeform fin sets
|
||||
|
||||
2012-03-13 Sampo Niskanne
|
||||
|
||||
* [BUG] Threads piled up when running simulations
|
||||
|
||||
@ -49,6 +49,10 @@ RocketPanel.FigTypeAct.Sideview = Side view
|
||||
RocketPanel.FigTypeAct.ttip.Sideview = Side view
|
||||
RocketPanel.FigTypeAct.Backview = Back view
|
||||
RocketPanel.FigTypeAct.ttip.Backview = Rear view
|
||||
RocketPanel.FigViewAct.2D = 2D View
|
||||
RocketPanel.FigViewAct.ttip.2D = 2D View
|
||||
RocketPanel.FigViewAct.3D = 3D View
|
||||
RocketPanel.FigViewAct.ttip.3D = 3D View
|
||||
RocketPanel.lbl.Motorcfg = Motor configuration:
|
||||
RocketPanel.lbl.infoMessage = <html>Click to select Shift+click to select other Double-click to edit Click+drag to move
|
||||
|
||||
@ -713,6 +717,7 @@ FreeformFinSetConfig.lbl.doubleClick1 = Double-click
|
||||
FreeformFinSetConfig.lbl.doubleClick2 = to edit
|
||||
FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points
|
||||
FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Remove point
|
||||
FreeformFinSetConfig.lbl.scaleFin = Scale Fin
|
||||
|
||||
|
||||
!InnerTubeConfig
|
||||
@ -1568,3 +1573,13 @@ GuidedTourSelectionDialog.lbl.length = Number of slides:
|
||||
GuidedTourSelectionDialog.btn.start = Start tour!
|
||||
|
||||
|
||||
! Custom Fin BMP Importer
|
||||
CustomFinImport.button.label = Import from BMP
|
||||
CustomFinImport.filter = Bitmap Files (*.bmp)
|
||||
CustomFinImport.badFinImage = Invalid fin image. Must be a black and white image (black for the fin), not touching any side, except the bottom of the image, which is the base of the fin.
|
||||
CustomFinImport.errorLoadingFile = Error loading file:
|
||||
CustomFinImport.errorParsingFile = Error parsing fin image:
|
||||
CustomFinImport.undo = Import freeform fin set
|
||||
CustomFinImport.error.title = Error loading fin profile
|
||||
CustomFinImport.error.badimage = Could not deduce fin shape from image.
|
||||
|
||||
|
||||
@ -2,11 +2,18 @@ package net.sf.openrocket.gui.configdialog;
|
||||
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSeparator;
|
||||
@ -14,6 +21,7 @@ import javax.swing.JSpinner;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
@ -25,9 +33,13 @@ import net.sf.openrocket.gui.adaptors.IntegerModel;
|
||||
import net.sf.openrocket.gui.components.BasicSlider;
|
||||
import net.sf.openrocket.gui.components.StyledLabel;
|
||||
import net.sf.openrocket.gui.components.UnitSelector;
|
||||
import net.sf.openrocket.gui.dialogs.ScaleDialog;
|
||||
import net.sf.openrocket.gui.scalefigure.FinPointFigure;
|
||||
import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
|
||||
import net.sf.openrocket.gui.scalefigure.ScaleSelector;
|
||||
import net.sf.openrocket.gui.util.CustomFinImporter;
|
||||
import net.sf.openrocket.gui.util.FileHelper;
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.material.Material;
|
||||
@ -56,18 +68,16 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
this.finset = (FreeformFinSet) component;
|
||||
|
||||
//// General and General properties
|
||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.General"), null, generalPane(),
|
||||
trans.get("FreeformFinSetCfg.tab.ttip.General"), 0);
|
||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.General"), null, generalPane(), trans.get("FreeformFinSetCfg.tab.ttip.General"), 0);
|
||||
//// Shape and Fin shape
|
||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.Shape"), null, shapePane(),
|
||||
trans.get("FreeformFinSetCfg.tab.ttip.Finshape"), 1);
|
||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.Shape"), null, shapePane(), trans.get("FreeformFinSetCfg.tab.ttip.Finshape"), 1);
|
||||
tabbedPane.setSelectedIndex(0);
|
||||
|
||||
addFinSetButtons();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private JPanel generalPane() {
|
||||
|
||||
DoubleModel m;
|
||||
@ -78,8 +88,8 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
|
||||
JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel", "[][65lp::][30lp::]", ""));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// Number of fins:
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Numberoffins")));
|
||||
|
||||
@ -89,7 +99,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
panel.add(spin, "growx, wrap");
|
||||
|
||||
|
||||
|
||||
//// Base rotation
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Finrotation")));
|
||||
|
||||
@ -102,39 +112,31 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
panel.add(new UnitSelector(m), "growx");
|
||||
panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// Fin cant
|
||||
JLabel label = new JLabel(trans.get("FreeformFinSetCfg.lbl.Fincant"));
|
||||
//// The angle that the fins are canted with respect to the rocket body.
|
||||
label.setToolTipText(trans.get("FreeformFinSetCfg.lbl.ttip.Fincant"));
|
||||
panel.add(label);
|
||||
|
||||
m = new DoubleModel(component, "CantAngle", UnitGroup.UNITS_ANGLE,
|
||||
-FinSet.MAX_CANT, FinSet.MAX_CANT);
|
||||
m = new DoubleModel(component, "CantAngle", UnitGroup.UNITS_ANGLE, -FinSet.MAX_CANT, FinSet.MAX_CANT);
|
||||
|
||||
spin = new JSpinner(m.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
panel.add(spin, "growx");
|
||||
|
||||
panel.add(new UnitSelector(m), "growx");
|
||||
panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)),
|
||||
"w 100lp, wrap 40lp");
|
||||
panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)), "w 100lp, wrap 40lp");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// Position
|
||||
//// Position relative to:
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Posrelativeto")));
|
||||
|
||||
combo = new JComboBox(
|
||||
new EnumModel<RocketComponent.Position>(component, "RelativePosition",
|
||||
new RocketComponent.Position[] {
|
||||
RocketComponent.Position.TOP,
|
||||
RocketComponent.Position.MIDDLE,
|
||||
RocketComponent.Position.BOTTOM,
|
||||
RocketComponent.Position.ABSOLUTE
|
||||
}));
|
||||
combo = new JComboBox(new EnumModel<RocketComponent.Position>(component, "RelativePosition", new RocketComponent.Position[] { RocketComponent.Position.TOP, RocketComponent.Position.MIDDLE,
|
||||
RocketComponent.Position.BOTTOM, RocketComponent.Position.ABSOLUTE }));
|
||||
panel.add(combo, "spanx 3, growx, wrap");
|
||||
//// plus
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.plus")), "right");
|
||||
@ -145,32 +147,28 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
panel.add(spin, "growx");
|
||||
|
||||
panel.add(new UnitSelector(m), "growx");
|
||||
panel.add(new BasicSlider(m.getSliderModel(
|
||||
new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE),
|
||||
new DoubleModel(component.getParent(), "Length"))),
|
||||
"w 100lp, wrap");
|
||||
panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE), new DoubleModel(component.getParent(), "Length"))), "w 100lp, wrap");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
mainPanel.add(panel, "aligny 20%");
|
||||
mainPanel.add(new JSeparator(SwingConstants.VERTICAL), "growy, height 150lp");
|
||||
|
||||
|
||||
|
||||
panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// Cross section
|
||||
//// Fin cross section:
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.FincrossSection")), "span, split");
|
||||
combo = new JComboBox(
|
||||
new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
|
||||
combo = new JComboBox(new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
|
||||
panel.add(combo, "growx, wrap unrel");
|
||||
|
||||
|
||||
|
||||
//// Thickness:
|
||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Thickness")));
|
||||
|
||||
@ -183,23 +181,23 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
panel.add(new UnitSelector(m), "growx");
|
||||
panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 30lp");
|
||||
|
||||
|
||||
|
||||
//// Material
|
||||
materialPanel(panel, Material.Type.BULK);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
mainPanel.add(panel, "aligny 20%");
|
||||
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private JPanel shapePane() {
|
||||
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||
|
||||
|
||||
|
||||
// Create the figure
|
||||
figure = new FinPointFigure(finset);
|
||||
ScaleScrollPane figurePane = new FinPointScrollPane();
|
||||
@ -211,35 +209,86 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
table = new JTable(tableModel);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
for (int i = 0; i < Columns.values().length; i++) {
|
||||
table.getColumnModel().getColumn(i).
|
||||
setPreferredWidth(Columns.values()[i].getWidth());
|
||||
table.getColumnModel().getColumn(i).setPreferredWidth(Columns.values()[i].getWidth());
|
||||
}
|
||||
JScrollPane tablePane = new JScrollPane(table);
|
||||
|
||||
|
||||
JButton scaleButton = new JButton(trans.get("FreeformFinSetConfig.lbl.scaleFin"));
|
||||
scaleButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
log.user("Scaling free-form fin");
|
||||
ScaleDialog dialog = new ScaleDialog(document, finset, SwingUtilities.getWindowAncestor(FreeformFinSetConfig.this), true);
|
||||
dialog.setVisible(true);
|
||||
dialog.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
// panel.add(new JLabel("Coordinates:"), "aligny bottom, alignx 50%");
|
||||
// panel.add(new JLabel(" View:"), "wrap, aligny bottom");
|
||||
|
||||
|
||||
|
||||
panel.add(tablePane, "growy, width 100lp:100lp:, height 100lp:250lp:");
|
||||
panel.add(figurePane, "gap unrel, spanx, growx, growy 1000, height 100lp:250lp:, wrap");
|
||||
panel.add(figurePane, "gap unrel, spanx, spany 3, growx, growy 1000, height 100lp:250lp:, wrap");
|
||||
|
||||
panel.add(new StyledLabel(trans.get("lbl.doubleClick1"), -2), "alignx 50%");
|
||||
panel.add(new StyledLabel(trans.get("lbl.doubleClick1"), -2), "alignx 50%, wrap");
|
||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "alignx 50%, wrap");
|
||||
|
||||
panel.add(new ScaleSelector(figurePane), "spany 2");
|
||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.clickDrag") + " " +
|
||||
trans.get("FreeformFinSetConfig.lbl.ctrlClick"), -2), "spany 2, right, wrap");
|
||||
panel.add(scaleButton, "spany 2, alignx 50%, aligny 50%");
|
||||
panel.add(new ScaleSelector(figurePane), "spany 2, aligny 50%");
|
||||
|
||||
|
||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "alignx 50%");
|
||||
JButton importButton = new JButton(trans.get("CustomFinImport.button.label"));
|
||||
importButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
importImage();
|
||||
}
|
||||
});
|
||||
panel.add(importButton, "spany 2, bottom");
|
||||
|
||||
// panel.add(new CustomFinBmpImporter(finset), "spany 2, bottom");
|
||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.clickDrag"), -2), "right, wrap");
|
||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.ctrlClick"), -2), "right");
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void importImage() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
|
||||
chooser.addChoosableFileFilter(FileHelper.BMP_FILE_FILTER);
|
||||
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
|
||||
int option = chooser.showOpenDialog(this);
|
||||
|
||||
|
||||
if (option == JFileChooser.APPROVE_OPTION) {
|
||||
try {
|
||||
CustomFinImporter importer = new CustomFinImporter();
|
||||
List<Coordinate> points = importer.getPoints(chooser.getSelectedFile());
|
||||
document.startUndo(trans.get("CustomFinImport.undo"));
|
||||
finset.setPoints(points);
|
||||
} catch (IllegalFinPointException e) {
|
||||
log.warn("Error storing fin points", e);
|
||||
JOptionPane.showMessageDialog(this, trans.get("CustomFinImport.error.badimage"),
|
||||
trans.get("CustomFinImport.error.title"), JOptionPane.ERROR_MESSAGE);
|
||||
} catch (IOException e) {
|
||||
log.warn("Error loading file", e);
|
||||
JOptionPane.showMessageDialog(this, e.getLocalizedMessage(),
|
||||
trans.get("CustomFinImport.error.title"), JOptionPane.ERROR_MESSAGE);
|
||||
} finally {
|
||||
document.stopUndo();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void updateFields() {
|
||||
super.updateFields();
|
||||
@ -253,13 +302,10 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private class FinPointScrollPane extends ScaleScrollPane {
|
||||
private static final int ANY_MASK =
|
||||
(MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK |
|
||||
MouseEvent.META_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK |
|
||||
MouseEvent.SHIFT_DOWN_MASK);
|
||||
private static final int ANY_MASK = (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK | MouseEvent.META_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK | MouseEvent.SHIFT_DOWN_MASK);
|
||||
|
||||
private int dragIndex = -1;
|
||||
|
||||
@ -271,8 +317,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
public void mousePressed(MouseEvent event) {
|
||||
int mods = event.getModifiersEx();
|
||||
|
||||
if (event.getButton() != MouseEvent.BUTTON1 ||
|
||||
(mods & ANY_MASK) != 0) {
|
||||
if (event.getButton() != MouseEvent.BUTTON1 || (mods & ANY_MASK) != 0) {
|
||||
super.mousePressed(event);
|
||||
return;
|
||||
}
|
||||
@ -303,9 +348,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent event) {
|
||||
int mods = event.getModifiersEx();
|
||||
if (dragIndex < 0 ||
|
||||
(mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) !=
|
||||
MouseEvent.BUTTON1_DOWN_MASK) {
|
||||
if (dragIndex < 0 || (mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) != MouseEvent.BUTTON1_DOWN_MASK) {
|
||||
super.mouseDragged(event);
|
||||
return;
|
||||
}
|
||||
@ -314,8 +357,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
try {
|
||||
finset.setPoint(dragIndex, point.x, point.y);
|
||||
} catch (IllegalFinPointException ignore) {
|
||||
log.debug("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex +
|
||||
" x=" + point.x + " y=" + point.y);
|
||||
log.debug("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex + " x=" + point.x + " y=" + point.y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,8 +371,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent event) {
|
||||
int mods = event.getModifiersEx();
|
||||
if (event.getButton() != MouseEvent.BUTTON1 ||
|
||||
(mods & ANY_MASK) != MouseEvent.CTRL_DOWN_MASK) {
|
||||
if (event.getButton() != MouseEvent.BUTTON1 || (mods & ANY_MASK) != MouseEvent.CTRL_DOWN_MASK) {
|
||||
super.mouseClicked(event);
|
||||
return;
|
||||
}
|
||||
@ -375,13 +416,13 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
return figure.convertPoint(x, y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private enum Columns {
|
||||
// NUMBER {
|
||||
// @Override
|
||||
@ -405,8 +446,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
|
||||
@Override
|
||||
public String getValue(FreeformFinSet finset, int row) {
|
||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit()
|
||||
.toString(finset.getFinPoints()[row].x);
|
||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit().toString(finset.getFinPoints()[row].x);
|
||||
}
|
||||
},
|
||||
Y {
|
||||
@ -417,8 +457,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
|
||||
@Override
|
||||
public String getValue(FreeformFinSet finset, int row) {
|
||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit()
|
||||
.toString(finset.getFinPoints()[row].y);
|
||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit().toString(finset.getFinPoints()[row].y);
|
||||
}
|
||||
};
|
||||
|
||||
@ -468,10 +507,8 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
if (!(o instanceof String))
|
||||
return;
|
||||
|
||||
if (rowIndex < 0 || rowIndex >= finset.getFinPoints().length ||
|
||||
columnIndex < 0 || columnIndex >= Columns.values().length) {
|
||||
throw new IllegalArgumentException("Index out of bounds, row=" + rowIndex +
|
||||
" column=" + columnIndex + " fin point count=" + finset.getFinPoints().length);
|
||||
if (rowIndex < 0 || rowIndex >= finset.getFinPoints().length || columnIndex < 0 || columnIndex >= Columns.values().length) {
|
||||
throw new IllegalArgumentException("Index out of bounds, row=" + rowIndex + " column=" + columnIndex + " fin point count=" + finset.getFinPoints().length);
|
||||
}
|
||||
|
||||
String str = (String) o;
|
||||
|
||||
@ -67,7 +67,7 @@ public class ScaleDialog extends JDialog {
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Scaler implementations
|
||||
*
|
||||
@ -179,9 +179,9 @@ public class ScaleDialog extends JDialog {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static final double DEFAULT_INITIAL_SIZE = 0.1; // meters
|
||||
private static final double SCALE_MIN = 0.01;
|
||||
private static final double SCALE_MAX = 100.0;
|
||||
@ -190,18 +190,19 @@ public class ScaleDialog extends JDialog {
|
||||
private static final String SCALE_SUBSELECTION = trans.get("lbl.scaleSubselection");
|
||||
private static final String SCALE_SELECTION = trans.get("lbl.scaleSelection");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private final DoubleModel multiplier = new DoubleModel(1.0, UnitGroup.UNITS_RELATIVE, SCALE_MIN, SCALE_MAX);
|
||||
private final DoubleModel fromField = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
|
||||
private final DoubleModel toField = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
|
||||
|
||||
private final OpenRocketDocument document;
|
||||
private final RocketComponent selection;
|
||||
private final boolean onlySelection;
|
||||
|
||||
private final JComboBox selectionOption;
|
||||
private final JCheckBox scaleMassValues;
|
||||
private JComboBox selectionOption;
|
||||
private JCheckBox scaleMassValues;
|
||||
|
||||
private boolean changing = false;
|
||||
|
||||
@ -213,14 +214,32 @@ public class ScaleDialog extends JDialog {
|
||||
* @param parent the parent window.
|
||||
*/
|
||||
public ScaleDialog(OpenRocketDocument document, RocketComponent selection, Window parent) {
|
||||
this(document, selection, parent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sole constructor.
|
||||
*
|
||||
* @param document the document to modify.
|
||||
* @param selection the currently selected component (or <code>null</code> if none selected).
|
||||
* @param parent the parent window.
|
||||
* @param onlySelection true to only allow scaling on the selected component (not the whole rocket)
|
||||
*/
|
||||
public ScaleDialog(OpenRocketDocument document, RocketComponent selection, Window parent, Boolean onlySelection) {
|
||||
super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
|
||||
|
||||
this.document = document;
|
||||
this.selection = selection;
|
||||
this.onlySelection = onlySelection;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// Generate options for scaling
|
||||
List<String> options = new ArrayList<String>();
|
||||
options.add(SCALE_ROCKET);
|
||||
if (!onlySelection)
|
||||
options.add(SCALE_ROCKET);
|
||||
if (selection != null && selection.getChildCount() > 0) {
|
||||
options.add(SCALE_SUBSELECTION);
|
||||
}
|
||||
@ -228,7 +247,7 @@ public class ScaleDialog extends JDialog {
|
||||
options.add(SCALE_SELECTION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Select initial size for "from" field.
|
||||
*
|
||||
@ -262,7 +281,7 @@ public class ScaleDialog extends JDialog {
|
||||
fromField.setValue(initialSize);
|
||||
toField.setValue(initialSize);
|
||||
|
||||
|
||||
|
||||
// Add actions to the values
|
||||
multiplier.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
@ -295,13 +314,13 @@ public class ScaleDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
String tip;
|
||||
JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
|
||||
this.add(panel);
|
||||
|
||||
|
||||
|
||||
// Scaling selection
|
||||
tip = trans.get("lbl.scale.ttip");
|
||||
JLabel label = new JLabel(trans.get("lbl.scale"));
|
||||
@ -313,14 +332,14 @@ public class ScaleDialog extends JDialog {
|
||||
selectionOption.setToolTipText(tip);
|
||||
panel.add(selectionOption, "growx, wrap para*2");
|
||||
|
||||
|
||||
|
||||
// Scale multiplier
|
||||
tip = trans.get("lbl.scaling.ttip");
|
||||
label = new JLabel(trans.get("lbl.scaling"));
|
||||
label.setToolTipText(tip);
|
||||
panel.add(label, "gapright unrel");
|
||||
|
||||
|
||||
|
||||
JSpinner spin = new JSpinner(multiplier.getSpinnerModel());
|
||||
spin.setEditor(new SpinnerEditor(spin));
|
||||
spin.setToolTipText(tip);
|
||||
@ -333,7 +352,7 @@ public class ScaleDialog extends JDialog {
|
||||
slider.setToolTipText(tip);
|
||||
panel.add(slider, "w 100lp, growx, wrap para");
|
||||
|
||||
|
||||
|
||||
// Scale from ... to ...
|
||||
tip = trans.get("lbl.scaleFromTo.ttip");
|
||||
label = new JLabel(trans.get("lbl.scaleFrom"));
|
||||
@ -362,7 +381,7 @@ public class ScaleDialog extends JDialog {
|
||||
unit.setToolTipText(tip);
|
||||
panel.add(unit, "w 30lp, wrap para*2");
|
||||
|
||||
|
||||
|
||||
// Scale override
|
||||
scaleMassValues = new JCheckBox(trans.get("checkbox.scaleMass"));
|
||||
scaleMassValues.setToolTipText(trans.get("checkbox.scaleMass.ttip"));
|
||||
@ -377,7 +396,7 @@ public class ScaleDialog extends JDialog {
|
||||
scaleMassValues.setEnabled(overridden);
|
||||
panel.add(scaleMassValues, "span, wrap para*3");
|
||||
|
||||
|
||||
|
||||
// Buttons
|
||||
|
||||
JButton scale = new JButton(trans.get("button.scale"));
|
||||
@ -399,13 +418,13 @@ public class ScaleDialog extends JDialog {
|
||||
});
|
||||
panel.add(cancel, "right, gap para");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GUIUtil.setDisposableDialogOptions(this, scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void doScale() {
|
||||
double mul = multiplier.getValue();
|
||||
if (!(SCALE_MIN <= mul && mul <= SCALE_MAX)) {
|
||||
@ -502,7 +521,7 @@ public class ScaleDialog extends JDialog {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for scaling a specific component/value.
|
||||
*/
|
||||
|
||||
@ -152,6 +152,7 @@ public class BasicFrame extends JFrame {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sole constructor. Creates a new frame based on the supplied document
|
||||
* and adds it to the current frames list.
|
||||
|
||||
@ -19,7 +19,6 @@ import javax.swing.BorderFactory;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
@ -52,10 +51,9 @@ public class ScaleScrollPane extends JScrollPane
|
||||
public static final int MINOR_TICKS = 3;
|
||||
public static final int MAJOR_TICKS = 30;
|
||||
|
||||
|
||||
|
||||
private JComponent component;
|
||||
private ScaleFigure figure;
|
||||
private JViewport viewport;
|
||||
|
||||
private DoubleModel rulerUnit;
|
||||
private Ruler horizontalRuler;
|
||||
@ -92,7 +90,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
this.figure = (ScaleFigure) component;
|
||||
this.allowFit = allowFit;
|
||||
|
||||
|
||||
|
||||
rulerUnit = new DoubleModel(0.0, UnitGroup.UNITS_LENGTH);
|
||||
rulerUnit.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
@ -114,8 +112,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
|
||||
this.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||
|
||||
|
||||
viewport = this.getViewport();
|
||||
|
||||
viewport.addMouseListener(this);
|
||||
viewport.addMouseMotionListener(this);
|
||||
|
||||
@ -183,7 +180,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public double getScaling() {
|
||||
return figure.getScaling();
|
||||
}
|
||||
@ -209,7 +206,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
|
||||
//////////////// Mouse handlers ////////////////
|
||||
|
||||
|
||||
|
||||
private int dragStartX = 0;
|
||||
private int dragStartY = 0;
|
||||
private Rectangle dragRectangle = null;
|
||||
@ -257,10 +254,10 @@ public class ScaleScrollPane extends JScrollPane
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////// The view port rulers ////////////////
|
||||
|
||||
|
||||
|
||||
private class Ruler extends JComponent {
|
||||
public static final int HORIZONTAL = 0;
|
||||
public static final int VERTICAL = 1;
|
||||
@ -326,7 +323,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
g2.setColor(getBackground());
|
||||
g2.fillRect(area.x, area.y, area.width, area.height + 100);
|
||||
|
||||
|
||||
|
||||
int startpx, endpx;
|
||||
if (orientation == HORIZONTAL) {
|
||||
startpx = area.x;
|
||||
@ -345,7 +342,7 @@ public class ScaleScrollPane extends JScrollPane
|
||||
|
||||
Tick[] ticks = unit.getTicks(start, end, minor, major);
|
||||
|
||||
|
||||
|
||||
// Set color & hints
|
||||
g2.setColor(Color.BLACK);
|
||||
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
||||
|
||||
270
core/src/net/sf/openrocket/gui/util/CustomFinImporter.java
Normal file
270
core/src/net/sf/openrocket/gui/util/CustomFinImporter.java
Normal file
@ -0,0 +1,270 @@
|
||||
package net.sf.openrocket.gui.util;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.sf.openrocket.l10n.LocalizedIOException;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
public class CustomFinImporter {
|
||||
|
||||
private enum FacingDirections {
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
}
|
||||
|
||||
private int startX;
|
||||
private FacingDirections facing;
|
||||
private int currentX, currentY;
|
||||
|
||||
|
||||
|
||||
public List<Coordinate> getPoints(File file) throws IOException {
|
||||
ArrayList<Coordinate> points = new ArrayList<Coordinate>();
|
||||
|
||||
BufferedImage pic = ImageIO.read(file);
|
||||
|
||||
// Set initial values for parsing
|
||||
startX = -1;
|
||||
facing = FacingDirections.UP;
|
||||
|
||||
if (validateImage(pic)) {
|
||||
points.add(Coordinate.NUL);
|
||||
loadFin(pic, points);
|
||||
} else {
|
||||
throw new LocalizedIOException("CustomFinImport.error.badimage");
|
||||
}
|
||||
|
||||
optimizePoints(points);
|
||||
return points;
|
||||
}
|
||||
|
||||
|
||||
private boolean validateImage(BufferedImage pic) {
|
||||
int height = pic.getHeight();
|
||||
int width = pic.getWidth();
|
||||
Boolean bottomEdgeFound = false;
|
||||
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
|
||||
if ((pixel == 0xFFFFFF) || (pixel == 0)) // black or white only
|
||||
{
|
||||
if ((x == 0) || (x == width - 1) || (y == 0)) {
|
||||
// Left, right and top must have no black (fin)
|
||||
if (pixel == 0)
|
||||
return false;
|
||||
} else if (y == height - 1) {
|
||||
if (pixel == 0) {
|
||||
bottomEdgeFound = true;
|
||||
if (startX == -1)
|
||||
startX = x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Found something other than a black or white pixel
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bottomEdgeFound;
|
||||
}
|
||||
|
||||
private void loadFin(BufferedImage pic, ArrayList<Coordinate> points) {
|
||||
boolean calledTurnedAround = false;
|
||||
int height = pic.getHeight();
|
||||
|
||||
currentX = startX;
|
||||
currentY = pic.getHeight() - 1;
|
||||
|
||||
do {
|
||||
if (CheckLeftIsFin(pic, currentX, currentY))
|
||||
RotateLeft();
|
||||
else if (CheckForwardIsFin(pic, currentX, currentY)) {
|
||||
// Do nothing
|
||||
} else if (CheckRightIsFin(pic, currentX, currentY))
|
||||
RotateRight();
|
||||
else {
|
||||
TurnAround();
|
||||
calledTurnedAround = true;
|
||||
}
|
||||
|
||||
MoveForward(pic);
|
||||
if (pixelIsFin(pic, currentX, currentY)) {
|
||||
if (!calledTurnedAround) {
|
||||
double x = (currentX - startX) * 0.001;
|
||||
double y = (height - currentY - 1) * 0.001;
|
||||
points.add(new Coordinate(x, y));
|
||||
} else
|
||||
calledTurnedAround = false;
|
||||
}
|
||||
} while (currentY < height - 1 && currentY >= 0);
|
||||
}
|
||||
|
||||
private boolean pixelIsFin(BufferedImage pic, int x, int y) {
|
||||
int height = pic.getHeight();
|
||||
int width = pic.getWidth();
|
||||
|
||||
if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
|
||||
int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
|
||||
|
||||
if (pixel == 0) // black is fin
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean CheckLeftIsFin(BufferedImage pic, int x, int y) {
|
||||
if (facing == FacingDirections.DOWN)
|
||||
return pixelIsFin(pic, x + 1, y);
|
||||
else if (facing == FacingDirections.UP)
|
||||
return pixelIsFin(pic, x - 1, y);
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
return pixelIsFin(pic, x, y + 1);
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
return pixelIsFin(pic, x, y - 1);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean CheckRightIsFin(BufferedImage pic, int x, int y) {
|
||||
if (facing == FacingDirections.DOWN)
|
||||
return pixelIsFin(pic, x - 1, y);
|
||||
else if (facing == FacingDirections.UP)
|
||||
return pixelIsFin(pic, x + 1, y);
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
return pixelIsFin(pic, x, y - 1);
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
return pixelIsFin(pic, x, y + 1);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean CheckForwardIsFin(BufferedImage pic, int x, int y) {
|
||||
if (facing == FacingDirections.DOWN)
|
||||
return pixelIsFin(pic, x, y + 1);
|
||||
else if (facing == FacingDirections.UP)
|
||||
return pixelIsFin(pic, x, y - 1);
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
return pixelIsFin(pic, x - 1, y);
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
return pixelIsFin(pic, x + 1, y);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RotateLeft() {
|
||||
if (facing == FacingDirections.UP)
|
||||
facing = FacingDirections.LEFT;
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
facing = FacingDirections.UP;
|
||||
else if (facing == FacingDirections.DOWN)
|
||||
facing = FacingDirections.RIGHT;
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
facing = FacingDirections.DOWN;
|
||||
}
|
||||
|
||||
private void RotateRight() {
|
||||
if (facing == FacingDirections.UP)
|
||||
facing = FacingDirections.RIGHT;
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
facing = FacingDirections.DOWN;
|
||||
else if (facing == FacingDirections.DOWN)
|
||||
facing = FacingDirections.LEFT;
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
facing = FacingDirections.UP;
|
||||
}
|
||||
|
||||
private void MoveForward(BufferedImage pic) {
|
||||
if (facing == FacingDirections.UP) {
|
||||
if (currentY > 0)
|
||||
currentY--;
|
||||
} else if (facing == FacingDirections.RIGHT) {
|
||||
if (currentX < pic.getWidth() - 1)
|
||||
currentX++;
|
||||
} else if (facing == FacingDirections.DOWN) {
|
||||
if (currentY < pic.getHeight() - 1)
|
||||
currentY++;
|
||||
} else if (facing == FacingDirections.LEFT) {
|
||||
if (currentX > 0)
|
||||
currentX--;
|
||||
}
|
||||
}
|
||||
|
||||
private void TurnAround() {
|
||||
if (facing == FacingDirections.UP)
|
||||
facing = FacingDirections.DOWN;
|
||||
else if (facing == FacingDirections.DOWN)
|
||||
facing = FacingDirections.UP;
|
||||
else if (facing == FacingDirections.RIGHT)
|
||||
facing = FacingDirections.LEFT;
|
||||
else if (facing == FacingDirections.LEFT)
|
||||
facing = FacingDirections.RIGHT;
|
||||
}
|
||||
|
||||
private void optimizePoints(ArrayList<Coordinate> points) {
|
||||
int startIx;
|
||||
ListIterator<Coordinate> start, entry, entry2;
|
||||
Coordinate startPoint, endPoint, testPoint;
|
||||
|
||||
startIx = 0;
|
||||
start = points.listIterator();
|
||||
startPoint = start.next();
|
||||
while ((start.hasNext()) && (startPoint != points.get(points.size() - 1))) {
|
||||
entry = points.listIterator(points.size());
|
||||
endPoint = entry.previous();
|
||||
for (; endPoint != startPoint; endPoint = entry.previous()) {
|
||||
entry2 = points.listIterator(start.nextIndex());
|
||||
testPoint = entry2.next();
|
||||
for (; testPoint != endPoint; testPoint = entry2.next()) {
|
||||
if (pointDistanceFromLine(startPoint, endPoint, testPoint) > 0.001) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((testPoint == endPoint) && (endPoint != startPoint)) {
|
||||
// Entire segment was within distance, it's a strait line.
|
||||
// Remove all but the first and last point
|
||||
entry2 = points.listIterator(start.nextIndex());
|
||||
int nextIx = entry2.nextIndex();
|
||||
Coordinate check = entry2.next();
|
||||
while ((entry2.nextIndex() != points.size()) && (check != endPoint)) {
|
||||
entry2.remove();
|
||||
nextIx = entry2.nextIndex();
|
||||
check = entry2.next();
|
||||
}
|
||||
startIx = nextIx;
|
||||
start = points.listIterator(startIx);
|
||||
startPoint = start.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (endPoint == startPoint) {
|
||||
startIx = start.nextIndex();
|
||||
if (start.hasNext())
|
||||
startPoint = start.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double pointDistanceFromLine(Coordinate startPoint, Coordinate endPoint, Coordinate testPoint) {
|
||||
Coordinate pt = closestPointOnSegment(startPoint, endPoint, testPoint);
|
||||
|
||||
return testPoint.sub(pt).length();
|
||||
}
|
||||
|
||||
private Coordinate closestPointOnSegment(Coordinate a, Coordinate b, Coordinate p) {
|
||||
Coordinate D = b.sub(a);
|
||||
double numer = p.sub(a).dot(D);
|
||||
if (numer <= 0.0f)
|
||||
return a;
|
||||
double denom = D.dot(D);
|
||||
if (numer >= denom)
|
||||
return b;
|
||||
return a.add(D.multiply(numer / denom));
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,17 @@
|
||||
package net.sf.openrocket.gui.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import net.sf.openrocket.l10n.L10N;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Helper methods related to user-initiated file manipulation.
|
||||
* <p>
|
||||
@ -22,7 +23,7 @@ public final class FileHelper {
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
|
||||
|
||||
// TODO: HIGH: Rename translation keys
|
||||
|
||||
/** File filter for any rocket designs (*.ork, *.rkt) */
|
||||
@ -46,14 +47,25 @@ public final class FileHelper {
|
||||
public static final FileFilter CSV_FILE_FILTER =
|
||||
new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
|
||||
|
||||
/** File filter for BMP files (*.bmp) */
|
||||
public static final FileFilter BMP_FILE_FILTER =
|
||||
new SimpleFileFilter(trans.get("CustomFinImport.filter"), ".bmp");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private FileHelper() {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
||||
|
||||
// public FileFilter getImageFileFilter() {
|
||||
// String[] extensions = ImageIO.getReaderFileSuffixes();
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Ensure that the provided file has a file extension. If the file does not have
|
||||
* any extension, append the provided extension to it.
|
||||
@ -76,31 +88,31 @@ public final class FileHelper {
|
||||
|
||||
/**
|
||||
* Ensure that the provided file has the given file extension. This differs from ensureExtension in that this
|
||||
* method guarantees that the file will have the extension, whereas ensureExtension only treats the extension
|
||||
* as a default.
|
||||
* method guarantees that the file will have the extension, whereas ensureExtension only treats the extension
|
||||
* as a default.
|
||||
*
|
||||
* @param original the original file
|
||||
* @param extension the extension to guarantee (without preceding dot)
|
||||
* @return the resulting file
|
||||
*/
|
||||
public static File forceExtension(File original, String extension) {
|
||||
|
||||
|
||||
if (!original.getName().toLowerCase().endsWith(extension.toLowerCase())) {
|
||||
log.debug(1, "File name does not contain extension, adding '" + extension + "'");
|
||||
String name = original.getAbsolutePath();
|
||||
if (extension.startsWith(".")) {
|
||||
name = name + extension;
|
||||
}
|
||||
else {
|
||||
name = name + "." + extension;
|
||||
}
|
||||
return new File(name);
|
||||
if (extension.startsWith(".")) {
|
||||
name = name + extension;
|
||||
}
|
||||
else {
|
||||
name = name + "." + extension;
|
||||
}
|
||||
return new File(name);
|
||||
}
|
||||
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Confirm that it is allowed to write to a file. If the file exists,
|
||||
* a confirmation dialog will be presented to the user to ensure overwriting is ok.
|
||||
|
||||
28
core/src/net/sf/openrocket/l10n/LocalizedIOException.java
Normal file
28
core/src/net/sf/openrocket/l10n/LocalizedIOException.java
Normal file
@ -0,0 +1,28 @@
|
||||
package net.sf.openrocket.l10n;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
public class LocalizedIOException extends IOException {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
public LocalizedIOException(String key) {
|
||||
super(key);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public LocalizedIOException(String key, Throwable cause) {
|
||||
super(key, cause);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedMessage() {
|
||||
return trans.get(key);
|
||||
}
|
||||
}
|
||||
@ -44,8 +44,8 @@ public class FreeformFinSet extends FinSet {
|
||||
this.length = points.get(points.size()-1).x - points.get(0).x;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert an existing fin set into a freeform fin set. The specified
|
||||
* fin set is taken out of the rocket tree (if any) and the new component
|
||||
@ -77,7 +77,7 @@ public class FreeformFinSet extends FinSet {
|
||||
position = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create the freeform fin set
|
||||
Coordinate[] finpoints = finset.getFinPoints();
|
||||
try {
|
||||
@ -118,7 +118,7 @@ public class FreeformFinSet extends FinSet {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a fin point between indices <code>index-1</code> and <code>index</code>.
|
||||
* The point is placed at the midpoint of the current segment.
|
||||
@ -166,14 +166,15 @@ public class FreeformFinSet extends FinSet {
|
||||
}
|
||||
|
||||
public void setPoints(Coordinate[] points) throws IllegalFinPointException {
|
||||
ArrayList<Coordinate> list = new ArrayList<Coordinate>(points.length);
|
||||
for (Coordinate p : points) {
|
||||
list.add(p);
|
||||
}
|
||||
setPoints(Arrays.asList(points));
|
||||
}
|
||||
|
||||
public void setPoints(List<Coordinate> points) throws IllegalFinPointException {
|
||||
ArrayList<Coordinate> list = new ArrayList<Coordinate>(points);
|
||||
validate(list);
|
||||
this.points = list;
|
||||
|
||||
this.length = points[points.length - 1].x;
|
||||
this.length = points.get(points.size() - 1).x;
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
@ -230,8 +231,8 @@ public class FreeformFinSet extends FinSet {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Check for intersecting
|
||||
double px0, py0, px1, py1;
|
||||
px0 = 0;
|
||||
@ -275,7 +276,7 @@ public class FreeformFinSet extends FinSet {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private boolean intersects(double ax0, double ay0, double ax1, double ay1,
|
||||
double bx0, double by0, double bx1, double by1) {
|
||||
|
||||
@ -326,7 +327,7 @@ public class FreeformFinSet extends FinSet {
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
for (int j = i + 2; j < n - 1; j++) {
|
||||
if (intersects(pts.get(i).x, pts.get(i).y, pts.get(i + 1).x, pts.get(i + 1).y,
|
||||
pts.get(j).x, pts.get(j).y, pts.get(j + 1).x, pts.get(j + 1).y)) {
|
||||
pts.get(j).x, pts.get(j).y, pts.get(j + 1).x, pts.get(j + 1).y)) {
|
||||
throw new IllegalFinPointException("segments intersect");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user