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
|
2012-03-13 Sampo Niskanne
|
||||||
|
|
||||||
* [BUG] Threads piled up when running simulations
|
* [BUG] Threads piled up when running simulations
|
||||||
|
|||||||
@ -49,6 +49,10 @@ RocketPanel.FigTypeAct.Sideview = Side view
|
|||||||
RocketPanel.FigTypeAct.ttip.Sideview = Side view
|
RocketPanel.FigTypeAct.ttip.Sideview = Side view
|
||||||
RocketPanel.FigTypeAct.Backview = Back view
|
RocketPanel.FigTypeAct.Backview = Back view
|
||||||
RocketPanel.FigTypeAct.ttip.Backview = Rear 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.Motorcfg = Motor configuration:
|
||||||
RocketPanel.lbl.infoMessage = <html>Click to select Shift+click to select other Double-click to edit Click+drag to move
|
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.doubleClick2 = to edit
|
||||||
FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points
|
FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points
|
||||||
FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Remove point
|
FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Remove point
|
||||||
|
FreeformFinSetConfig.lbl.scaleFin = Scale Fin
|
||||||
|
|
||||||
|
|
||||||
!InnerTubeConfig
|
!InnerTubeConfig
|
||||||
@ -1568,3 +1573,13 @@ GuidedTourSelectionDialog.lbl.length = Number of slides:
|
|||||||
GuidedTourSelectionDialog.btn.start = Start tour!
|
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.Point;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSeparator;
|
import javax.swing.JSeparator;
|
||||||
@ -14,6 +21,7 @@ import javax.swing.JSpinner;
|
|||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
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.BasicSlider;
|
||||||
import net.sf.openrocket.gui.components.StyledLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
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.FinPointFigure;
|
||||||
import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
|
import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
|
||||||
import net.sf.openrocket.gui.scalefigure.ScaleSelector;
|
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.l10n.Translator;
|
||||||
import net.sf.openrocket.logging.LogHelper;
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
@ -56,11 +68,9 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
this.finset = (FreeformFinSet) component;
|
this.finset = (FreeformFinSet) component;
|
||||||
|
|
||||||
//// General and General properties
|
//// General and General properties
|
||||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.General"), null, generalPane(),
|
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.General"), null, generalPane(), trans.get("FreeformFinSetCfg.tab.ttip.General"), 0);
|
||||||
trans.get("FreeformFinSetCfg.tab.ttip.General"), 0);
|
|
||||||
//// Shape and Fin shape
|
//// Shape and Fin shape
|
||||||
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.Shape"), null, shapePane(),
|
tabbedPane.insertTab(trans.get("FreeformFinSetCfg.tab.Shape"), null, shapePane(), trans.get("FreeformFinSetCfg.tab.ttip.Finshape"), 1);
|
||||||
trans.get("FreeformFinSetCfg.tab.ttip.Finshape"), 1);
|
|
||||||
tabbedPane.setSelectedIndex(0);
|
tabbedPane.setSelectedIndex(0);
|
||||||
|
|
||||||
addFinSetButtons();
|
addFinSetButtons();
|
||||||
@ -110,16 +120,14 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
label.setToolTipText(trans.get("FreeformFinSetCfg.lbl.ttip.Fincant"));
|
label.setToolTipText(trans.get("FreeformFinSetCfg.lbl.ttip.Fincant"));
|
||||||
panel.add(label);
|
panel.add(label);
|
||||||
|
|
||||||
m = new DoubleModel(component, "CantAngle", UnitGroup.UNITS_ANGLE,
|
m = new DoubleModel(component, "CantAngle", UnitGroup.UNITS_ANGLE, -FinSet.MAX_CANT, FinSet.MAX_CANT);
|
||||||
-FinSet.MAX_CANT, FinSet.MAX_CANT);
|
|
||||||
|
|
||||||
spin = new JSpinner(m.getSpinnerModel());
|
spin = new JSpinner(m.getSpinnerModel());
|
||||||
spin.setEditor(new SpinnerEditor(spin));
|
spin.setEditor(new SpinnerEditor(spin));
|
||||||
panel.add(spin, "growx");
|
panel.add(spin, "growx");
|
||||||
|
|
||||||
panel.add(new UnitSelector(m), "growx");
|
panel.add(new UnitSelector(m), "growx");
|
||||||
panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)),
|
panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)), "w 100lp, wrap 40lp");
|
||||||
"w 100lp, wrap 40lp");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -127,14 +135,8 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
//// Position relative to:
|
//// Position relative to:
|
||||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Posrelativeto")));
|
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Posrelativeto")));
|
||||||
|
|
||||||
combo = new JComboBox(
|
combo = new JComboBox(new EnumModel<RocketComponent.Position>(component, "RelativePosition", new RocketComponent.Position[] { RocketComponent.Position.TOP, RocketComponent.Position.MIDDLE,
|
||||||
new EnumModel<RocketComponent.Position>(component, "RelativePosition",
|
RocketComponent.Position.BOTTOM, RocketComponent.Position.ABSOLUTE }));
|
||||||
new RocketComponent.Position[] {
|
|
||||||
RocketComponent.Position.TOP,
|
|
||||||
RocketComponent.Position.MIDDLE,
|
|
||||||
RocketComponent.Position.BOTTOM,
|
|
||||||
RocketComponent.Position.ABSOLUTE
|
|
||||||
}));
|
|
||||||
panel.add(combo, "spanx 3, growx, wrap");
|
panel.add(combo, "spanx 3, growx, wrap");
|
||||||
//// plus
|
//// plus
|
||||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.plus")), "right");
|
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.plus")), "right");
|
||||||
@ -145,10 +147,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
panel.add(spin, "growx");
|
panel.add(spin, "growx");
|
||||||
|
|
||||||
panel.add(new UnitSelector(m), "growx");
|
panel.add(new UnitSelector(m), "growx");
|
||||||
panel.add(new BasicSlider(m.getSliderModel(
|
panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE), new DoubleModel(component.getParent(), "Length"))), "w 100lp, wrap");
|
||||||
new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE),
|
|
||||||
new DoubleModel(component.getParent(), "Length"))),
|
|
||||||
"w 100lp, wrap");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -166,8 +165,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
//// Cross section
|
//// Cross section
|
||||||
//// Fin cross section:
|
//// Fin cross section:
|
||||||
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.FincrossSection")), "span, split");
|
panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.FincrossSection")), "span, split");
|
||||||
combo = new JComboBox(
|
combo = new JComboBox(new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
|
||||||
new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
|
|
||||||
panel.add(combo, "growx, wrap unrel");
|
panel.add(combo, "growx, wrap unrel");
|
||||||
|
|
||||||
|
|
||||||
@ -211,27 +209,46 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
table = new JTable(tableModel);
|
table = new JTable(tableModel);
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
for (int i = 0; i < Columns.values().length; i++) {
|
for (int i = 0; i < Columns.values().length; i++) {
|
||||||
table.getColumnModel().getColumn(i).
|
table.getColumnModel().getColumn(i).setPreferredWidth(Columns.values()[i].getWidth());
|
||||||
setPreferredWidth(Columns.values()[i].getWidth());
|
|
||||||
}
|
}
|
||||||
JScrollPane tablePane = new JScrollPane(table);
|
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("Coordinates:"), "aligny bottom, alignx 50%");
|
||||||
// panel.add(new JLabel(" View:"), "wrap, aligny bottom");
|
// panel.add(new JLabel(" View:"), "wrap, aligny bottom");
|
||||||
|
|
||||||
|
|
||||||
panel.add(tablePane, "growy, width 100lp:100lp:, height 100lp:250lp:");
|
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(scaleButton, "spany 2, alignx 50%, aligny 50%");
|
||||||
panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.clickDrag") + " " +
|
panel.add(new ScaleSelector(figurePane), "spany 2, aligny 50%");
|
||||||
trans.get("FreeformFinSetConfig.lbl.ctrlClick"), -2), "spany 2, right, wrap");
|
|
||||||
|
|
||||||
|
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 StyledLabel(trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "alignx 50%");
|
// 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;
|
return panel;
|
||||||
}
|
}
|
||||||
@ -240,6 +257,38 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public void updateFields() {
|
public void updateFields() {
|
||||||
super.updateFields();
|
super.updateFields();
|
||||||
@ -256,10 +305,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
|
|
||||||
|
|
||||||
private class FinPointScrollPane extends ScaleScrollPane {
|
private class FinPointScrollPane extends ScaleScrollPane {
|
||||||
private static final int ANY_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);
|
||||||
(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;
|
private int dragIndex = -1;
|
||||||
|
|
||||||
@ -271,8 +317,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
public void mousePressed(MouseEvent event) {
|
public void mousePressed(MouseEvent event) {
|
||||||
int mods = event.getModifiersEx();
|
int mods = event.getModifiersEx();
|
||||||
|
|
||||||
if (event.getButton() != MouseEvent.BUTTON1 ||
|
if (event.getButton() != MouseEvent.BUTTON1 || (mods & ANY_MASK) != 0) {
|
||||||
(mods & ANY_MASK) != 0) {
|
|
||||||
super.mousePressed(event);
|
super.mousePressed(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -303,9 +348,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
@Override
|
@Override
|
||||||
public void mouseDragged(MouseEvent event) {
|
public void mouseDragged(MouseEvent event) {
|
||||||
int mods = event.getModifiersEx();
|
int mods = event.getModifiersEx();
|
||||||
if (dragIndex < 0 ||
|
if (dragIndex < 0 || (mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) != MouseEvent.BUTTON1_DOWN_MASK) {
|
||||||
(mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) !=
|
|
||||||
MouseEvent.BUTTON1_DOWN_MASK) {
|
|
||||||
super.mouseDragged(event);
|
super.mouseDragged(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -314,8 +357,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
try {
|
try {
|
||||||
finset.setPoint(dragIndex, point.x, point.y);
|
finset.setPoint(dragIndex, point.x, point.y);
|
||||||
} catch (IllegalFinPointException ignore) {
|
} catch (IllegalFinPointException ignore) {
|
||||||
log.debug("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex +
|
log.debug("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex + " x=" + point.x + " y=" + point.y);
|
||||||
" x=" + point.x + " y=" + point.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,8 +371,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent event) {
|
public void mouseClicked(MouseEvent event) {
|
||||||
int mods = event.getModifiersEx();
|
int mods = event.getModifiersEx();
|
||||||
if (event.getButton() != MouseEvent.BUTTON1 ||
|
if (event.getButton() != MouseEvent.BUTTON1 || (mods & ANY_MASK) != MouseEvent.CTRL_DOWN_MASK) {
|
||||||
(mods & ANY_MASK) != MouseEvent.CTRL_DOWN_MASK) {
|
|
||||||
super.mouseClicked(event);
|
super.mouseClicked(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -405,8 +446,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(FreeformFinSet finset, int row) {
|
public String getValue(FreeformFinSet finset, int row) {
|
||||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit()
|
return UnitGroup.UNITS_LENGTH.getDefaultUnit().toString(finset.getFinPoints()[row].x);
|
||||||
.toString(finset.getFinPoints()[row].x);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Y {
|
Y {
|
||||||
@ -417,8 +457,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(FreeformFinSet finset, int row) {
|
public String getValue(FreeformFinSet finset, int row) {
|
||||||
return UnitGroup.UNITS_LENGTH.getDefaultUnit()
|
return UnitGroup.UNITS_LENGTH.getDefaultUnit().toString(finset.getFinPoints()[row].y);
|
||||||
.toString(finset.getFinPoints()[row].y);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -468,10 +507,8 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
if (!(o instanceof String))
|
if (!(o instanceof String))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (rowIndex < 0 || rowIndex >= finset.getFinPoints().length ||
|
if (rowIndex < 0 || rowIndex >= finset.getFinPoints().length || columnIndex < 0 || columnIndex >= Columns.values().length) {
|
||||||
columnIndex < 0 || columnIndex >= Columns.values().length) {
|
throw new IllegalArgumentException("Index out of bounds, row=" + rowIndex + " column=" + columnIndex + " fin point count=" + finset.getFinPoints().length);
|
||||||
throw new IllegalArgumentException("Index out of bounds, row=" + rowIndex +
|
|
||||||
" column=" + columnIndex + " fin point count=" + finset.getFinPoints().length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String str = (String) o;
|
String str = (String) o;
|
||||||
|
|||||||
@ -199,9 +199,10 @@ public class ScaleDialog extends JDialog {
|
|||||||
|
|
||||||
private final OpenRocketDocument document;
|
private final OpenRocketDocument document;
|
||||||
private final RocketComponent selection;
|
private final RocketComponent selection;
|
||||||
|
private final boolean onlySelection;
|
||||||
|
|
||||||
private final JComboBox selectionOption;
|
private JComboBox selectionOption;
|
||||||
private final JCheckBox scaleMassValues;
|
private JCheckBox scaleMassValues;
|
||||||
|
|
||||||
private boolean changing = false;
|
private boolean changing = false;
|
||||||
|
|
||||||
@ -213,14 +214,32 @@ public class ScaleDialog extends JDialog {
|
|||||||
* @param parent the parent window.
|
* @param parent the parent window.
|
||||||
*/
|
*/
|
||||||
public ScaleDialog(OpenRocketDocument document, RocketComponent selection, Window parent) {
|
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);
|
super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
|
||||||
|
|
||||||
this.document = document;
|
this.document = document;
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
|
this.onlySelection = onlySelection;
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
// Generate options for scaling
|
// Generate options for scaling
|
||||||
List<String> options = new ArrayList<String>();
|
List<String> options = new ArrayList<String>();
|
||||||
options.add(SCALE_ROCKET);
|
if (!onlySelection)
|
||||||
|
options.add(SCALE_ROCKET);
|
||||||
if (selection != null && selection.getChildCount() > 0) {
|
if (selection != null && selection.getChildCount() > 0) {
|
||||||
options.add(SCALE_SUBSELECTION);
|
options.add(SCALE_SUBSELECTION);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,6 +152,7 @@ public class BasicFrame extends JFrame {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sole constructor. Creates a new frame based on the supplied document
|
* Sole constructor. Creates a new frame based on the supplied document
|
||||||
* and adds it to the current frames list.
|
* and adds it to the current frames list.
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import javax.swing.BorderFactory;
|
|||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JViewport;
|
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
@ -55,7 +54,6 @@ public class ScaleScrollPane extends JScrollPane
|
|||||||
|
|
||||||
private JComponent component;
|
private JComponent component;
|
||||||
private ScaleFigure figure;
|
private ScaleFigure figure;
|
||||||
private JViewport viewport;
|
|
||||||
|
|
||||||
private DoubleModel rulerUnit;
|
private DoubleModel rulerUnit;
|
||||||
private Ruler horizontalRuler;
|
private Ruler horizontalRuler;
|
||||||
@ -115,7 +113,6 @@ public class ScaleScrollPane extends JScrollPane
|
|||||||
this.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
this.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
|
||||||
|
|
||||||
|
|
||||||
viewport = this.getViewport();
|
|
||||||
viewport.addMouseListener(this);
|
viewport.addMouseListener(this);
|
||||||
viewport.addMouseMotionListener(this);
|
viewport.addMouseMotionListener(this);
|
||||||
|
|
||||||
|
|||||||
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;
|
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.L10N;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.logging.LogHelper;
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.startup.Application;
|
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.
|
* Helper methods related to user-initiated file manipulation.
|
||||||
* <p>
|
* <p>
|
||||||
@ -46,6 +47,10 @@ public final class FileHelper {
|
|||||||
public static final FileFilter CSV_FILE_FILTER =
|
public static final FileFilter CSV_FILE_FILTER =
|
||||||
new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
|
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");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,6 +59,13 @@ public final class FileHelper {
|
|||||||
// Prevent instantiation
|
// Prevent instantiation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public FileFilter getImageFileFilter() {
|
||||||
|
// String[] extensions = ImageIO.getReaderFileSuffixes();
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the provided file has a file extension. If the file does not have
|
* Ensure that the provided file has a file extension. If the file does not have
|
||||||
* any extension, append the provided extension to it.
|
* any extension, append the provided extension to it.
|
||||||
@ -76,8 +88,8 @@ public final class FileHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the provided file has the given file extension. This differs from ensureExtension in that this
|
* 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
|
* method guarantees that the file will have the extension, whereas ensureExtension only treats the extension
|
||||||
* as a default.
|
* as a default.
|
||||||
*
|
*
|
||||||
* @param original the original file
|
* @param original the original file
|
||||||
* @param extension the extension to guarantee (without preceding dot)
|
* @param extension the extension to guarantee (without preceding dot)
|
||||||
@ -88,13 +100,13 @@ public final class FileHelper {
|
|||||||
if (!original.getName().toLowerCase().endsWith(extension.toLowerCase())) {
|
if (!original.getName().toLowerCase().endsWith(extension.toLowerCase())) {
|
||||||
log.debug(1, "File name does not contain extension, adding '" + extension + "'");
|
log.debug(1, "File name does not contain extension, adding '" + extension + "'");
|
||||||
String name = original.getAbsolutePath();
|
String name = original.getAbsolutePath();
|
||||||
if (extension.startsWith(".")) {
|
if (extension.startsWith(".")) {
|
||||||
name = name + extension;
|
name = name + extension;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
name = name + "." + extension;
|
name = name + "." + extension;
|
||||||
}
|
}
|
||||||
return new File(name);
|
return new File(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return original;
|
return original;
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -166,14 +166,15 @@ public class FreeformFinSet extends FinSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setPoints(Coordinate[] points) throws IllegalFinPointException {
|
public void setPoints(Coordinate[] points) throws IllegalFinPointException {
|
||||||
ArrayList<Coordinate> list = new ArrayList<Coordinate>(points.length);
|
setPoints(Arrays.asList(points));
|
||||||
for (Coordinate p : points) {
|
}
|
||||||
list.add(p);
|
|
||||||
}
|
public void setPoints(List<Coordinate> points) throws IllegalFinPointException {
|
||||||
|
ArrayList<Coordinate> list = new ArrayList<Coordinate>(points);
|
||||||
validate(list);
|
validate(list);
|
||||||
this.points = list;
|
this.points = list;
|
||||||
|
|
||||||
this.length = points[points.length - 1].x;
|
this.length = points.get(points.size() - 1).x;
|
||||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +327,7 @@ public class FreeformFinSet extends FinSet {
|
|||||||
for (int i = 0; i < n - 1; i++) {
|
for (int i = 0; i < n - 1; i++) {
|
||||||
for (int j = i + 2; j < n - 1; j++) {
|
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,
|
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");
|
throw new IllegalFinPointException("segments intersect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user