]> git.gag.com Git - debian/openrocket/commitdiff
DGP - ripped out visitor; temp fix for Windows IAE
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sat, 5 Mar 2011 21:16:42 +0000 (21:16 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sat, 5 Mar 2011 21:16:42 +0000 (21:16 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@116 180e2498-e6e9-4542-8430-84ac67f01cd8

34 files changed:
src/net/sf/openrocket/gui/dialogs/PrintDialog.java
src/net/sf/openrocket/gui/dialogs/PrintPanel.java
src/net/sf/openrocket/gui/print/DesignReport.java
src/net/sf/openrocket/gui/print/PDFPrintStreamDoc.java
src/net/sf/openrocket/gui/print/PaperSize.java
src/net/sf/openrocket/gui/print/PrintController.java
src/net/sf/openrocket/gui/print/PrintServiceDialog.java [new file with mode: 0644]
src/net/sf/openrocket/gui/print/PrintUtilities.java
src/net/sf/openrocket/gui/print/PrintableContext.java
src/net/sf/openrocket/gui/print/visitor/BaseVisitorStrategy.java [deleted file]
src/net/sf/openrocket/gui/print/visitor/FinSetVisitorStrategy.java
src/net/sf/openrocket/gui/print/visitor/MotorMountVisitorStrategy.java [deleted file]
src/net/sf/openrocket/gui/print/visitor/PartsDetailVisitorStrategy.java
src/net/sf/openrocket/gui/print/visitor/PartsListVisitorStrategy.java
src/net/sf/openrocket/gui/print/visitor/StageVisitorStrategy.java [deleted file]
src/net/sf/openrocket/rocketcomponent/BodyComponent.java
src/net/sf/openrocket/rocketcomponent/BodyTube.java
src/net/sf/openrocket/rocketcomponent/CenteringRing.java
src/net/sf/openrocket/rocketcomponent/ComponentVisitor.java [deleted file]
src/net/sf/openrocket/rocketcomponent/ComponentVisitorStrategy.java [deleted file]
src/net/sf/openrocket/rocketcomponent/EllipticalFinSet.java
src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java
src/net/sf/openrocket/rocketcomponent/InnerTube.java
src/net/sf/openrocket/rocketcomponent/LaunchLug.java
src/net/sf/openrocket/rocketcomponent/MassObject.java
src/net/sf/openrocket/rocketcomponent/NoseCone.java
src/net/sf/openrocket/rocketcomponent/RadiusRingComponent.java
src/net/sf/openrocket/rocketcomponent/RingComponent.java
src/net/sf/openrocket/rocketcomponent/Rocket.java
src/net/sf/openrocket/rocketcomponent/RocketComponent.java
src/net/sf/openrocket/rocketcomponent/Stage.java
src/net/sf/openrocket/rocketcomponent/Transition.java
src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java

index a9769eed69407fcf0d7e9b03641eeee5eab82318..f8ffed70f32366b875a78cb8451e043134400e62 100644 (file)
@@ -5,31 +5,18 @@ package net.sf.openrocket.gui.dialogs;
 
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.print.PDFPrintStreamDoc;
+import net.sf.openrocket.gui.print.PrintServiceDialog;
 import net.sf.openrocket.gui.print.PrintUtilities;
-import sun.print.ServiceDialog;
 
-import javax.print.DocFlavor;
-import javax.print.DocPrintJob;
-import javax.print.PrintException;
-import javax.print.PrintService;
-import javax.print.PrintServiceLookup;
+import javax.print.*;
 import javax.print.attribute.Attribute;
 import javax.print.attribute.AttributeSet;
 import javax.print.attribute.HashPrintRequestAttributeSet;
 import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.standard.Destination;
 import javax.print.attribute.standard.Fidelity;
-import javax.swing.JDialog;
-import javax.swing.JMenu;
-import javax.swing.JTabbedPane;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dialog;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.HeadlessException;
-import java.awt.Rectangle;
+import javax.swing.*;
+import java.awt.*;
 import java.io.ByteArrayOutputStream;
 
 /**
@@ -41,7 +28,7 @@ public class PrintDialog {
     /**
      * The service UI dialog.
      */
-    private ServiceDialog dialog;
+    private PrintServiceDialog dialog;
 
     /**
      * A javax doc flavor specific for printing PDF documents.
@@ -65,12 +52,12 @@ public class PrintDialog {
         if (ps != null) {
             DocPrintJob dpj = ps.createPrintJob();
             try {
-                System.err.println(attrs.size());
                 ByteArrayOutputStream baos = panel.generateReport();
                 dpj.print(new PDFPrintStreamDoc(baos, null), attrs);
             }
             catch (PrintException e) {
-                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                e.printStackTrace();
+                //dgp
             }
         }
     }
@@ -155,7 +142,7 @@ public class PrintDialog {
                 getLocalGraphicsEnvironment().getDefaultScreenDevice().
                 getDefaultConfiguration().getBounds() : gc.getBounds();
 
-        dialog = new ServiceDialog(gc,
+        dialog = new PrintServiceDialog(gc,
                                    x + gcBounds.x,
                                    y + gcBounds.y,
                                    services, defaultIndex,
@@ -183,7 +170,7 @@ public class PrintDialog {
 
         dialog.setVisible(true);
 
-        if (dialog.getStatus() == ServiceDialog.APPROVE) {
+        if (dialog.getStatus() == PrintServiceDialog.APPROVE) {
             PrintRequestAttributeSet newas = dialog.getAttributes();
             Class dstCategory = Destination.class;
             Class fdCategory = Fidelity.class;
@@ -232,7 +219,7 @@ public class PrintDialog {
     /**
      * Removes any attributes from the given AttributeSet that are unsupported by the given PrintService/DocFlavor
      * combination.
-     * 
+     *
      * @param ps      the print service for which unsupported attributes will be determined
      * @param flavor  the document flavor; PDF in our case
      * @param aset    the set of attributes requested
index ecd1fd8f754a379274fc9c7e030cbadc21bb678d..73aefd42f5d114ef0939a4f84909c0eb26c4cefd 100644 (file)
@@ -18,23 +18,13 @@ import net.sf.openrocket.startup.Application;
 
 import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.standard.MediaSizeName;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JColorChooser;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.UIManager;
+import javax.swing.*;
 import javax.swing.event.TreeSelectionEvent;
 import javax.swing.event.TreeSelectionListener;
 import javax.swing.filechooser.FileFilter;
 import javax.swing.tree.TreeNode;
 import javax.swing.tree.TreePath;
-import java.awt.Color;
-import java.awt.Desktop;
+import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.ByteArrayOutputStream;
@@ -45,12 +35,18 @@ import java.util.Enumeration;
 import java.util.Iterator;
 
 /**
- * This class isolates the Swing components used to create a panel that is added to the standard Java print dialog.
+ * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog.
  */
 public class PrintPanel extends JPanel implements TreeSelectionListener {
 
     private static final LogHelper log = Application.getLogger();
 
+    private static final String TAB_TITLE = "Rocket";
+    private static final String SETTINGS_BUTTON_TEXT = "Settings";
+    private static final String PREVIEW_BUTTON_TEXT = "Preview";
+    private static final String SAVE_AS_PDF_BUTTON_TEXT = "Save as PDF";
+    private static final String SHOW_BY_STAGE = "Show By Stage";
+
     private final RocketPrintTree stagedTree;
     private final RocketPrintTree noStagedTree;
     private OpenRocketDocument rocDoc;
@@ -61,7 +57,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
 
     JButton previewButton;
     JButton saveAsPDF;
-    
+
     /**
      * Constructor.
      *
@@ -102,9 +98,9 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
         currentTree = stagedTree;
 
         final JScrollPane scrollPane = new JScrollPane(stagedTree);
-        add(scrollPane, "width 475!, wrap");
+        add(scrollPane, "width 416!, wrap");
 
-        final JCheckBox sortByStage = new JCheckBox("Show By Stage");
+        final JCheckBox sortByStage = new JCheckBox(SHOW_BY_STAGE);
         sortByStage.setEnabled(stages > 1);
         sortByStage.setSelected(stages > 1);
         sortByStage.addActionListener(new ActionListener() {
@@ -125,7 +121,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
         });
         add(sortByStage, "wrap");
 
-        saveAsPDF = new JButton("Save as PDF");
+        saveAsPDF = new JButton(SAVE_AS_PDF_BUTTON_TEXT);
         saveAsPDF.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed (ActionEvent e) {
@@ -134,7 +130,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
         });
         add(saveAsPDF, "span 2, tag save");
 
-        previewButton = new JButton("Preview");
+        previewButton = new JButton(PREVIEW_BUTTON_TEXT);
         previewButton.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed (ActionEvent e) {
@@ -143,7 +139,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
         });
         add(previewButton, "x 150");
 
-        JButton settingsButton = new JButton("Settings");
+        JButton settingsButton = new JButton(SETTINGS_BUTTON_TEXT);
         settingsButton.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed (ActionEvent e) {
@@ -151,7 +147,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
                 settingsDialog.setVisible(true);
             }
         });
-        add(settingsButton, "x 400");
+        add(settingsButton, "x 340");
 
         expandAll(currentTree, true);
         if (currentTree != noStagedTree) {
@@ -166,10 +162,10 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
      * @return a title
      */
     public String getTitle () {
-        return "Rocket";
+        return TAB_TITLE;
     }
 
-    @Override 
+    @Override
     public void valueChanged (final TreeSelectionEvent e) {
         final TreePath path = e.getNewLeadSelectionPath();
         if (path != null){
@@ -190,7 +186,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
      */
     public void expandAll (RocketPrintTree theTree, boolean expand) {
         TreeNode root = (TreeNode) theTree.getModel().getRoot();
-        // Traverse theTree from root 
+        // Traverse theTree from root
         expandAll(theTree, new TreePath(root), expand);
     }
 
@@ -204,7 +200,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
      */
     private void expandAll (RocketPrintTree theTree, TreePath parent, boolean expand) {
         theTree.addSelectionPath(parent);
-        // Traverse children 
+        // Traverse children
         TreeNode node = (TreeNode) parent.getLastPathComponent();
         if (node.getChildCount() >= 0) {
             for (Enumeration e = node.children(); e.hasMoreElements();) {
@@ -213,7 +209,7 @@ public class PrintPanel extends JPanel implements TreeSelectionListener {
                 expandAll(theTree, path, expand);
             }
         }
-        // Expansion or collapse must be done bottom-up 
+        // Expansion or collapse must be done bottom-up
         if (expand) {
             theTree.expandPath(parent);
         }
index 247881e8071f9b9f0050bec8a2d975cb45d762a1..8bc1f0fd19dfd85f545cc6c52b49dbac29ec70ba 100644 (file)
@@ -3,37 +3,29 @@
  */
 package net.sf.openrocket.gui.print;
 
-import com.itextpdf.text.Document;
-import com.itextpdf.text.DocumentException;
-import com.itextpdf.text.Element;
-import com.itextpdf.text.Paragraph;
+import com.itextpdf.text.*;
 import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.pdf.BaseFont;
-import com.itextpdf.text.pdf.DefaultFontMapper;
-import com.itextpdf.text.pdf.PdfContentByte;
-import com.itextpdf.text.pdf.PdfPCell;
-import com.itextpdf.text.pdf.PdfPTable;
-import com.itextpdf.text.pdf.PdfWriter;
+import com.itextpdf.text.pdf.*;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.figureelements.FigureElement;
 import net.sf.openrocket.gui.figureelements.RocketInfo;
-import net.sf.openrocket.gui.print.visitor.BaseVisitorStrategy;
-import net.sf.openrocket.gui.print.visitor.MotorMountVisitorStrategy;
-import net.sf.openrocket.gui.print.visitor.StageVisitorStrategy;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.rocketcomponent.ComponentVisitor;
-import net.sf.openrocket.rocketcomponent.Configuration;
-import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.*;
 import net.sf.openrocket.simulation.FlightData;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.Prefs;
 
-import java.awt.Graphics2D;
+import java.awt.*;
 import java.io.IOException;
 import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import java.util.List;
 
 /**
@@ -67,7 +59,12 @@ import java.util.List;
  * <p/>
  * </pre>
  */
-public class DesignReport extends BaseVisitorStrategy {
+public class DesignReport {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
 
     /**
      * The OR Document.
@@ -80,9 +77,34 @@ public class DesignReport extends BaseVisitorStrategy {
     final RocketPanel panel;
 
     /**
-     * A stage visitor.
+     * The iText document.
      */
-    private StageVisitorStrategy svs = new StageVisitorStrategy();
+    protected Document document;
+
+    /** The displayed strings. */
+    private static final String STAGES = "Stages: ";
+    private static final String MASS_WITH_MOTORS = "Mass (with motors): ";
+    private static final String MASS_WITH_MOTOR = "Mass (with motor): ";
+    private static final String MASS_EMPTY = "Mass (Empty): ";
+    private static final String STABILITY = "Stability: ";
+    private static final String CG = "Cg: ";
+    private static final String CP = "Cp: ";
+    private static final String MOTOR = "Motor";
+    private static final String AVG_THRUST = "Avg Thrust";
+    private static final String BURN_TIME = "Burn Time";
+    private static final String MAX_THRUST = "Max Thrust";
+    private static final String TOTAL_IMPULSE = "Total Impulse";
+    private static final String THRUST_TO_WT = "Thrust to Wt";
+    private static final String PROPELLANT_WT = "Propellant Wt";
+    private static final String SIZE = "Size";
+    private static final String ALTITUDE = "Altitude";
+    private static final String FLIGHT_TIME = "Flight Time";
+    private static final String TIME_TO_APOGEE = "Time to Apogee";
+    private static final String VELOCITY_OFF_PAD = "Velocity off Pad";
+    private static final String MAX_VELOCITY = "Max Velocity";
+    private static final String LANDING_VELOCITY = "Landing Velocity";
+    private static final String ROCKET_DESIGN = "Rocket Design";
+    private static final double GRAVITY_CONSTANT = 9.80665d;
 
     /**
      * Constructor.
@@ -91,7 +113,7 @@ public class DesignReport extends BaseVisitorStrategy {
      * @param theIDoc   the iText document
      */
     public DesignReport (OpenRocketDocument theRocDoc, Document theIDoc) {
-        super(theIDoc, null);
+        document = theIDoc;
         rocketDocument = theRocDoc;
         panel = new RocketPanel(rocketDocument);
     }
@@ -101,7 +123,7 @@ public class DesignReport extends BaseVisitorStrategy {
      *
      * @param writer a direct byte writer
      */
-    public void print (PdfWriter writer) {
+    public void writeToDocument (PdfWriter writer) {
         if (writer == null) {
             return;
         }
@@ -109,7 +131,7 @@ public class DesignReport extends BaseVisitorStrategy {
         int pageImageableWidth = (int) pageSize.getWidth() - (int) pageSize.getBorderWidth() * 2;
         int pageImageableHeight = (int) pageSize.getHeight() / 2 - (int) pageSize.getBorderWidthTop();
 
-        PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, "Rocket Design");
+        PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN);
 
         Rocket rocket = rocketDocument.getRocket();
         final Configuration configuration = rocket.getDefaultConfiguration();
@@ -130,10 +152,10 @@ public class DesignReport extends BaseVisitorStrategy {
                                                       BaseFont.EMBEDDED), PrintUtilities.NORMAL_FONT_SIZE);
         }
         catch (DocumentException e) {
-            e.printStackTrace();
+            log.error("Could not set font.", e);
         }
         catch (IOException e) {
-            e.printStackTrace();
+            log.error("Could not create font.", e);
         }
         int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getFigureHeight()) * 0.4 * (scale / PrintUnit.METERS
                 .toPoints(1)));
@@ -145,25 +167,30 @@ public class DesignReport extends BaseVisitorStrategy {
 
         canvas.showText(rocketDocument.getRocket().getName());
 
-        canvas.newlineShowText("Stages: ");
+        canvas.newlineShowText(STAGES);
         canvas.showText("" + rocket.getStageCount());
 
 
         if (configuration.hasMotors()) {
-            canvas.newlineShowText("Mass (with motor" + ((configuration.getStageCount() > 1) ? "s): " : "): "));
+            if (configuration.getStageCount() > 1) {
+                canvas.newlineShowText(MASS_WITH_MOTORS);
+            }
+            else {
+                canvas.newlineShowText(MASS_WITH_MOTOR);
+            }
         }
         else {
-            canvas.newlineShowText("Mass (Empty): ");
+            canvas.newlineShowText(MASS_EMPTY);
         }
         canvas.showText(text.getMass(UnitGroup.UNITS_MASS.getDefaultUnit()));
 
-        canvas.newlineShowText("Stability: ");
+        canvas.newlineShowText(STABILITY);
         canvas.showText(text.getStability());
 
-        canvas.newlineShowText("Cg: ");
+        canvas.newlineShowText(CG);
         canvas.showText(text.getCg());
 
-        canvas.newlineShowText("Cp: ");
+        canvas.newlineShowText(CP);
         canvas.showText(text.getCp());
         canvas.endText();
 
@@ -180,12 +207,11 @@ public class DesignReport extends BaseVisitorStrategy {
 
             List<Double> stages = getStageWeights(rocket);
 
-
             for (int j = 0; j < mids.length; j++) {
                 String mid = mids[j];
                 if (mid != null) {
-                    MotorMountVisitorStrategy mmvs = new MotorMountVisitorStrategy(document, mid);
-                    rocket.accept(new ComponentVisitor(mmvs));
+                    final List<Motor> motorList = getMotorList(rocket, mid);
+
                     PdfPTable parent = new PdfPTable(2);
                     parent.setWidthPercentage(100);
                     parent.setHorizontalAlignment(Element.ALIGN_LEFT);
@@ -197,14 +223,38 @@ public class DesignReport extends BaseVisitorStrategy {
                         leading = 25;
                     }
                     addFlightData(rocket, mid, parent, leading);
-                    addMotorData(mmvs.getMotors(), parent, stages);
+                    addMotorData(motorList, parent, stages);
                     document.add(parent);
                 }
             }
         }
         catch (DocumentException e) {
-            e.printStackTrace();
+            log.error("Could not modify document.", e);
+        }
+    }
+
+    /**
+     * Get the motor list for all motor mounts.
+     *
+     * @param theRocket the rocket object
+     * @param theMid    the motor id
+     *
+     * @return a list of Motor
+     */
+    private List<Motor> getMotorList (final Rocket theRocket, final String theMid) {
+        Iterator<RocketComponent> components = theRocket.deepIterator();
+        final List<Motor> motorList = new ArrayList<Motor>();
+        while (components.hasNext()) {
+            RocketComponent rocketComponent = components.next();
+            if (rocketComponent instanceof MotorMount) {
+                MotorMount mm = (MotorMount) rocketComponent;
+                final Motor motor = mm.getMotor(theMid);
+                if (motor != null) {
+                    motorList.add(motor);
+                }
+            }
         }
+        return motorList;
     }
 
     /**
@@ -262,17 +312,17 @@ public class DesignReport extends BaseVisitorStrategy {
         motorTable.setWidthPercentage(68);
         motorTable.setHorizontalAlignment(Element.ALIGN_LEFT);
 
-        final PdfPCell motorCell = ITextHelper.createCell("Motor", PdfPCell.BOTTOM);
+        final PdfPCell motorCell = ITextHelper.createCell(MOTOR, PdfPCell.BOTTOM);
         final int mPad = 10;
         motorCell.setPaddingLeft(mPad);
         motorTable.addCell(motorCell);
-        motorTable.addCell(ITextHelper.createCell("Avg Thrust", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Burn Time", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Max Thrust", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Total Impulse", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Thrust to Wt", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Propellant Wt", PdfPCell.BOTTOM));
-        motorTable.addCell(ITextHelper.createCell("Size", PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(AVG_THRUST, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(BURN_TIME, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(MAX_THRUST, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(TOTAL_IMPULSE, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(THRUST_TO_WT, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(PROPELLANT_WT, PdfPCell.BOTTOM));
+        motorTable.addCell(ITextHelper.createCell(SIZE, PdfPCell.BOTTOM));
 
         DecimalFormat df = new DecimalFormat("#,##0.0#");
         for (int i = 0; i < motors.size(); i++) {
@@ -299,7 +349,7 @@ public class DesignReport extends BaseVisitorStrategy {
                     .UNITS_IMPULSE
                     .getDefaultUnit().toString(), border));
             double ttw = motor.getAverageThrustEstimate() / (getStageWeight(stageWeights, i) + (motor
-                    .getLaunchCG().weight * 9.80665));
+                    .getLaunchCG().weight * GRAVITY_CONSTANT));
             motorTable.addCell(ITextHelper.createCell(df.format(ttw) + ":1", border));
 
             motorTable.addCell(ITextHelper.createCell(df.format(motorWeight) + " " + UnitGroup.UNITS_MASS
@@ -330,7 +380,7 @@ public class DesignReport extends BaseVisitorStrategy {
     private void addFlightData (final Rocket theRocket, final String mid, final PdfPTable parent, int leading) {
         FlightData flight = null;
         if (theRocket.getMotorConfigurationIDs().length > 1) {
-            Rocket duplicate= theRocket.copyWithOriginalID();
+            Rocket duplicate = theRocket.copyWithOriginalID();
             Simulation simulation = Prefs.getBackgroundSimulation(duplicate);
             simulation.getConditions().setMotorConfigurationID(mid);
 
@@ -353,30 +403,30 @@ public class DesignReport extends BaseVisitorStrategy {
 
                     DecimalFormat df = new DecimalFormat("#,##0.0#");
 
-                    final PdfPCell cell = ITextHelper.createCell("Altitude", 2, 2);
+                    final PdfPCell cell = ITextHelper.createCell(ALTITUDE, 2, 2);
                     cell.setUseBorderPadding(false);
                     cell.setBorderWidthTop(0f);
                     labelTable.addCell(cell);
                     labelTable.addCell(ITextHelper.createCell(df.format(flight.getMaxAltitude()) + " " + distanceUnit,
                                                               2, 2));
 
-                    labelTable.addCell(ITextHelper.createCell("Flight Time", 2, 2));
+                    labelTable.addCell(ITextHelper.createCell(FLIGHT_TIME, 2, 2));
                     labelTable.addCell(ITextHelper.createCell(df.format(flight.getFlightTime()) + " " + flightUnit, 2,
                                                               2));
 
-                    labelTable.addCell(ITextHelper.createCell("Time to Apogee", 2, 2));
+                    labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
                     labelTable.addCell(ITextHelper.createCell(df.format(flight.getTimeToApogee()) + " " + flightUnit, 2,
                                                               2));
 
-                    labelTable.addCell(ITextHelper.createCell("Velocity off Pad", 2, 2));
+                    labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
                     labelTable.addCell(ITextHelper.createCell(df.format(
                             flight.getLaunchRodVelocity()) + " " + velocityUnit, 2, 2));
 
-                    labelTable.addCell(ITextHelper.createCell("Max Velocity", 2, 2));
+                    labelTable.addCell(ITextHelper.createCell(MAX_VELOCITY, 2, 2));
                     labelTable.addCell(ITextHelper.createCell(df.format(flight.getMaxVelocity()) + " " + velocityUnit,
                                                               2, 2));
 
-                    labelTable.addCell(ITextHelper.createCell("Landing Velocity", 2, 2));
+                    labelTable.addCell(ITextHelper.createCell(LANDING_VELOCITY, 2, 2));
                     labelTable.addCell(ITextHelper.createCell(df.format(
                             flight.getGroundHitVelocity()) + " " + velocityUnit, 2, 2));
 
@@ -388,7 +438,7 @@ public class DesignReport extends BaseVisitorStrategy {
                     parent.addCell(c);
                 }
                 catch (DocumentException e) {
-                    e.printStackTrace();
+                    log.error("Could not add flight data to document.", e);
                 }
             }
         }
@@ -428,20 +478,48 @@ public class DesignReport extends BaseVisitorStrategy {
     }
 
     /**
-     * Use a visitor to get the sorted list of Stage references, then from those get the stage masses and convert to
-     * weight.
+     * From a list of Stages get the stage masses and convert to weight.
      *
      * @param rocket the rocket
      *
      * @return a sorted list of Stage weights (mass * gravity), in Newtons
      */
     private List<Double> getStageWeights (Rocket rocket) {
-        rocket.accept(new ComponentVisitor(svs));
-        svs.close();
-        List<Double> stages = svs.getStages();
+        List<Double> stages = getStageMasses(rocket);
+
         for (int i = 0; i < stages.size(); i++) {
             Double stage = stages.get(i);
-            stages.set(i, stage * 9.80665);
+            stages.set(i, stage * GRAVITY_CONSTANT);
+        }
+        return stages;
+    }
+
+    /**
+     * From a list of Stages get the stage masses.
+     *
+     * @param rocket  the rocket
+     *
+     * @return a sorted list of Stage masses
+     */
+    private List<Double> getStageMasses (final Rocket rocket) {
+        Double mass = 0d;
+
+        List<Double> stages = new ArrayList<Double>();
+        Iterator<RocketComponent> iter = rocket.deepIterator();
+        while (iter.hasNext()) {
+            RocketComponent rocketComponent = iter.next();
+            if (rocketComponent instanceof Stage) {
+                if (mass > 0d) {
+                    stages.add(mass);
+                    mass = 0d;
+                }
+            }
+            else {
+                mass += rocketComponent.getMass();
+            }
+        }
+        if (mass > 0d) {
+            stages.add(mass);
         }
         return stages;
     }
index 4b6a56b972c0804cec839105cf39d07683230655..90cf46105c3c482be9982c46a75fe8c4e662d577 100644 (file)
@@ -7,19 +7,25 @@ import javax.print.Doc;
 import javax.print.DocFlavor;
 import javax.print.attribute.AttributeSetUtilities;
 import javax.print.attribute.DocAttributeSet;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
+import java.io.*;
 
 /**
+ * This class implements a javax Doc specifically for PDF printing. All reports in OpenRocket are PDF (iText) based.
  */
 public class PDFPrintStreamDoc implements Doc {
 
+    /** The source stream of the PDF document. */
     private InputStream stream;
+
+    /** The document's attributes. */
     private DocAttributeSet attributeSet;
 
+    /**
+     * Constructor.
+     *
+     * @param ostream  an output stream representing the pdf doc
+     * @param attributes the attributes of the document
+     */
     public PDFPrintStreamDoc (ByteArrayOutputStream ostream, DocAttributeSet attributes) {
         stream = new ByteArrayInputStream(ostream.toByteArray());
         if (attributes != null) {
@@ -27,10 +33,17 @@ public class PDFPrintStreamDoc implements Doc {
         }
     }
 
+    /**
+     * Flavor is PDF.
+     *
+     * @return PDF flavor
+     */
+    @Override
     public DocFlavor getDocFlavor () {
         return DocFlavor.INPUT_STREAM.PDF;
     }
 
+    @Override
     public DocAttributeSet getAttributes () {
         return attributeSet;
     }
@@ -38,11 +51,17 @@ public class PDFPrintStreamDoc implements Doc {
     /* Since the data is to be supplied as an InputStream delegate to
      * getStreamForBytes().
      */
-
+    @Override
     public Object getPrintData () throws IOException {
         return getStreamForBytes();
     }
 
+    /**
+     * Intentionally null since the flavor is PDF.
+     *
+     * @return null
+     */
+    @Override
     public Reader getReaderForText () {
         return null;
     }
@@ -50,7 +69,7 @@ public class PDFPrintStreamDoc implements Doc {
     /* Return the print data as an InputStream.
      * Always return the same instance.
      */
-
+    @Override
     public InputStream getStreamForBytes () throws IOException {
         return stream;
     }
index e40d6f1cf569deae51f49c25799d1933daee6298..63930e2a2f4e6576e8e12575b585ca6f02e3278c 100644 (file)
@@ -12,27 +12,62 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * Various mappings of paper sizes.
+ * Various mappings of paper sizes and their names.
  */
 public class PaperSize {
-    
+
+    /** Map of name to MediaSizeName instance. */
     private static Map<String, MediaSizeName> paperNames = new HashMap<String, MediaSizeName>();
+    /** Map of identifying name to displayable name. */
+    private static Map<String, String> displayableNames = new HashMap<String, String>();
+    /** Map of MediaSizeName to rectangle, which defines the paper size. */
     private static Map<MediaSizeName, Rectangle> paperItext = new HashMap<MediaSizeName, Rectangle>();
-    
+
+    /**
+     * Init.
+     */
     static {
         populateNameMap();
         populateITextSizeMap();
+        populateDisplayableNameMap();
     }
+
+    /** Disallow construction. */
     private PaperSize() {}
-    
+
+    /**
+     * Map an identifying paper name to it's corresponding MediaSizeName.
+     *
+     * @param name  a paper name
+     *
+     * @return  the associated MediaSizeName (or null if not found).
+     */
     public static MediaSizeName convert(String name) {
         return paperNames.get(name);
     }
 
+    /**
+     * Map a MediaSizeName to it's size Rectangle.
+     *
+     * @param name  a paper name
+     *
+     * @return a Rectangle or null
+     */
     public static Rectangle convert(MediaSizeName name) {
         return paperItext.get(name);
     }
-    
+
+    /**
+     * Map an identifying paper name to a displayable name (usually it's common name).
+     *
+     * @param name  a paper name
+     *
+     * @return a displayable name
+     */
+    public static String toDisplayable(String name) {
+        return displayableNames.get(name);
+    }
+
     private static void populateNameMap() {
         paperNames.put("iso-a0", MediaSizeName.ISO_A0);
         paperNames.put("iso-a1", MediaSizeName.ISO_A1);
@@ -124,5 +159,89 @@ public class PaperSize {
         paperItext.put(MediaSizeName.D, new RectangleReadOnly(PrintUnit.INCHES.toPoints(22), PrintUnit.INCHES.toPoints(34)));
         paperItext.put(MediaSizeName.E, new RectangleReadOnly(PrintUnit.INCHES.toPoints(34), PrintUnit.INCHES.toPoints(44)));
     }
-    
+
+    /**
+     * Create a name map from standard to displayable names
+     */
+    private static void populateDisplayableNameMap() {
+        displayableNames.put("iso-a0", "A0");
+        displayableNames.put("iso-a1", "A1");
+        displayableNames.put("iso-a2", "A2");
+        displayableNames.put("iso-a3", "A3");
+        displayableNames.put("iso-a4", "A4");
+        displayableNames.put("iso-a5", "A5");
+        displayableNames.put("iso-a6", "A6");
+        displayableNames.put("iso-a7", "A7");
+        displayableNames.put("iso-a8", "A8");
+        displayableNames.put("iso-a9", "A9");
+        displayableNames.put("iso-a10", "A10");
+        displayableNames.put("iso-b0", "B0");
+        displayableNames.put("iso-b1", "B1");
+        displayableNames.put("iso-b2", "B2");
+        displayableNames.put("iso-b3", "B3");
+        displayableNames.put("iso-b4", "B4");
+        displayableNames.put("iso-b5", "B5");
+        displayableNames.put("iso-b6", "B6");
+        displayableNames.put("iso-b7", "B7");
+        displayableNames.put("iso-b8", "B8");
+        displayableNames.put("iso-b9", "B9");
+        displayableNames.put("iso-b10", "B10");
+        displayableNames.put("na-letter", "US Letter");
+        displayableNames.put("na-legal", "US Legal");
+        displayableNames.put("na-8x10", "US 8x10 inch");
+        displayableNames.put("na-5x7", "US 5x7 inch");
+        displayableNames.put("executive", "Executive");
+        displayableNames.put("folio", "Folio");
+        displayableNames.put("invoice", "Invoice");
+        displayableNames.put("tabloid", "Tabloid");
+        displayableNames.put("ledger", "Ledger");
+        displayableNames.put("quarto", "Quarto");
+        displayableNames.put("iso-c0", "C0");
+        displayableNames.put("iso-c1", "C1");
+        displayableNames.put("iso-c2", "C2");
+        displayableNames.put("iso-c3", "C3");
+        displayableNames.put("iso-c4", "C4");
+        displayableNames.put("iso-c5", "C5");
+        displayableNames.put("iso-c6", "C6");
+        displayableNames.put("iso-designated-long", "ISO Designated Long Size");
+        displayableNames.put("jis-b0", "Japanese B0");
+        displayableNames.put("jis-b1", "Japanese B1");
+        displayableNames.put("jis-b2", "Japanese B2");
+        displayableNames.put("jis-b3", "Japanese B3");
+        displayableNames.put("jis-b4", "Japanese B4");
+        displayableNames.put("jis-b5", "Japanese B5");
+        displayableNames.put("jis-b6", "Japanese B6");
+        displayableNames.put("jis-b7", "Japanese B7");
+        displayableNames.put("jis-b8", "Japanese B8");
+        displayableNames.put("jis-b9", "Japanese B9");
+        displayableNames.put("jis-b10", "Japanese B10");
+        displayableNames.put("a", "US Letter");
+        displayableNames.put("b", "Engineering ANSI B");
+        displayableNames.put("c", "Engineering ANSI C");
+        displayableNames.put("d", "Engineering ANSI D");
+        displayableNames.put("e", "Engineering ANSI E");
+        displayableNames.put("arch-a", "Architectural A");
+        displayableNames.put("arch-b", "Architectural B");
+        displayableNames.put("arch-c", "Architectural C");
+        displayableNames.put("arch-d", "Architectural D");
+        displayableNames.put("arch-e", "Architectural E");
+        displayableNames.put("japanese-postcard", "Japanese Postcard");
+        displayableNames.put("oufuko-postcard", "Oufuko Postcard");
+        displayableNames.put("italian-envelope", "Italian Envelope");
+        displayableNames.put("personal-envelope", "Personal Envelope");
+        displayableNames.put("na-number-11-envelope", "#11 Envelope");
+        displayableNames.put("na-number-12-envelope", "#12 Envelope");
+        displayableNames.put("na-number-14-envelope", "#14 Envelope");
+        displayableNames.put("na-10x13-envelope", "10\"x13\" Envelope");
+        displayableNames.put("na-9x12-envelope", "9\"x12\" Envelope");
+        displayableNames.put("na-number-10-envelope", "#10 Envelope");
+        displayableNames.put("na-7x9-envelope", "7\"x9\" Envelope");
+        displayableNames.put("na-9x11-envelope", "9\"x11\" Envelope");
+        displayableNames.put("na-10x14-envelope", "10\"x14\" Envelope");
+        displayableNames.put("na-number-9-envelope", "#9 Envelope");
+        displayableNames.put("na-6x9-envelope", "6\"x9\" Envelope");
+        displayableNames.put("na-10x15-envelope", "10\"x15\" Envelope");
+        displayableNames.put("monarch-envelope", "Monarch Envelope");
+    }
+
 }
index 1cb64c430e65dde7ec2316f779e62ec504465f96..000288710099088f90bd31e1141da0f3921f021c 100644 (file)
@@ -14,9 +14,9 @@ import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.print.visitor.FinSetVisitorStrategy;
 import net.sf.openrocket.gui.print.visitor.PartsDetailVisitorStrategy;
-import net.sf.openrocket.rocketcomponent.ComponentVisitor;
 
 import javax.print.attribute.standard.MediaSizeName;
+import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Iterator;
 import java.util.Set;
@@ -59,33 +59,23 @@ public class PrintController {
                 switch (printableContext.getPrintable()) {
                     case DESIGN_REPORT:
                         DesignReport dp = new DesignReport(doc, idoc);
-                        dp.print(writer);
+                        dp.writeToDocument(writer);
                         idoc.newPage();
                         break;
                     case FIN_TEMPLATE:
-                        final ComponentVisitor finVisitor = new ComponentVisitor(new FinSetVisitorStrategy(idoc,
-                                                                                                           writer,
-                                                                                                           stages));
-                        finVisitor.visit(doc.getRocket());
-                        finVisitor.close();
+                        final FinSetVisitorStrategy finWriter = new FinSetVisitorStrategy(idoc,
+                                                                                           writer,
+                                                                                           stages);
+                        finWriter.writeToDocument(doc.getRocket());
                         break;
                     case PARTS_DETAIL:
-                        final ComponentVisitor detailVisitor = new ComponentVisitor(new PartsDetailVisitorStrategy(idoc,
-                                                                                                                   writer,
-                                                                                                                   stages));
-                        detailVisitor.visit(doc.getRocket());
+                        final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc,
+                                                                                                        writer,
+                                                                                                        stages);
+                        detailVisitor.writeToDocument(doc.getRocket());
                         detailVisitor.close();
                         idoc.newPage();
                         break;
-                    /*     case PARTS_LIST:
-                            final ComponentVisitor partsVisitor = new ComponentVisitor(new PartsListVisitorStrategy(idoc,
-                                                                                                                    writer,
-                                                                                                                    stages));
-                            partsVisitor.visit(doc.getRocket());
-                            partsVisitor.close();
-                            idoc.newPage();
-                            break;
-                    */
                 }
             }
             //Stupid iText throws a really nasty exception if there is no data when close is called.
@@ -99,16 +89,16 @@ public class PrintController {
         }
         catch (ExceptionConverter ec) {
         }
-/*        finally {
-            if (fileOutputStream != null) {
+        finally {
+            if (outputFile != null) {
                 try {
-                    fileOutputStream.close();
+                    outputFile.close();
                 }
                 catch (IOException e) {
                 }
             }
         }
-  */
+
     }
 
     private Rectangle convertWithDefault (final MediaSizeName msn) {
diff --git a/src/net/sf/openrocket/gui/print/PrintServiceDialog.java b/src/net/sf/openrocket/gui/print/PrintServiceDialog.java
new file mode 100644 (file)
index 0000000..98045f8
--- /dev/null
@@ -0,0 +1,562 @@
+/*\r
+ * PrintServiceDialog.java\r
+ *\r
+ */\r
+package net.sf.openrocket.gui.print;\r
+\r
+import net.miginfocom.swing.MigLayout;\r
+\r
+import javax.print.DocFlavor;\r
+import javax.print.PrintService;\r
+import javax.print.ServiceUIFactory;\r
+import javax.print.attribute.HashPrintRequestAttributeSet;\r
+import javax.print.attribute.PrintRequestAttribute;\r
+import javax.print.attribute.PrintRequestAttributeSet;\r
+import javax.print.attribute.PrintServiceAttribute;\r
+import javax.print.attribute.standard.*;\r
+import javax.swing.*;\r
+import javax.swing.border.EmptyBorder;\r
+import javax.swing.event.PopupMenuEvent;\r
+import javax.swing.event.PopupMenuListener;\r
+import java.awt.*;\r
+import java.awt.event.*;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+public class PrintServiceDialog extends JDialog implements ActionListener {\r
+\r
+    public static final int APPROVE = 1;\r
+    private JButton btnCancel, btnPrint;\r
+    private boolean pdfFlavorSupported = true;\r
+    private PrintService services[];\r
+    private int defaultServiceIndex, status;\r
+    private PrintRequestAttributeSet asOriginal;\r
+    private HashPrintRequestAttributeSet asCurrent;\r
+    private PrintService psCurrent;\r
+    private DocFlavor docFlavor;\r
+    private GeneralPanel pnlGeneral;\r
+    private static final String GENERAL_TAB_TITLE = "General";\r
+    private static final String PRINT_BUTTON_LABEL = "Print";\r
+    private static final String CANCEL_BUTTON_LABEL = "Cancel";\r
+\r
+    private class MediaPanel extends JPanel\r
+            implements ItemListener {\r
+\r
+        private static final String strTitle = "Media";\r
+        private static final String SOURCE = "Source:";\r
+        private static final String SIZE = "Size:";\r
+\r
+        private JLabel lblSize, lblSource;\r
+        private JComboBox cbSize, cbSource;\r
+        private ArrayList<MediaSizeName> sizes;\r
+        private ArrayList sources;\r
+\r
+        private String getMediaName (String s) {\r
+            String s1 = s.replace(' ', '-');\r
+            s1 = s1.replace('#', 'n');\r
+            return PaperSize.toDisplayable(s1);\r
+        }\r
+\r
+        public void itemStateChanged (ItemEvent itemevent) {\r
+            Object obj = itemevent.getSource();\r
+            if (itemevent.getStateChange() == 1) {\r
+                if (obj == cbSize) {\r
+                    int i = cbSize.getSelectedIndex();\r
+                    if (i >= 0 && i < sizes.size()) {\r
+                        if (cbSource.getItemCount() > 1 && cbSource.getSelectedIndex() >= 1) {\r
+                            int k = cbSource.getSelectedIndex() - 1;\r
+                            MediaTray mediatray = (MediaTray) sources.get(k);\r
+                            asCurrent.add(new MediaWrapper(mediatray));\r
+                        }\r
+                        asCurrent.add(sizes.get(i));\r
+                    }\r
+                }\r
+                else if (obj == cbSource) {\r
+                    int j = cbSource.getSelectedIndex();\r
+                    if (j >= 1 && j < sources.size() + 1) {\r
+                        asCurrent.remove(MediaWrapper.class);\r
+                        asCurrent.add((MediaTray) sources.get(j - 1));\r
+                    }\r
+                    else if (j == 0) {\r
+                        asCurrent.remove(MediaWrapper.class);\r
+                        if (cbSize.getItemCount() > 0) {\r
+                            int l = cbSize.getSelectedIndex();\r
+                            asCurrent.add(sizes.get(l));\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        public void updateInfo () {\r
+            boolean flag = false;\r
+            cbSize.removeItemListener(this);\r
+            cbSize.removeAllItems();\r
+            cbSource.removeItemListener(this);\r
+            cbSource.removeAllItems();\r
+            cbSource.addItem(getMediaName("auto-select"));\r
+            sizes.clear();\r
+            sources.clear();\r
+            if (psCurrent.isAttributeCategorySupported(Media.class)) {\r
+                flag = true;\r
+                Object obj = null;\r
+                try {\r
+                    obj = psCurrent.getSupportedAttributeValues(Media.class, docFlavor, asCurrent);\r
+                }\r
+                catch (IllegalArgumentException iae) {\r
+                    pdfFlavorSupported = false;\r
+                                             //dgp\r
+                }\r
+                if (obj instanceof Media[]) {\r
+                    Media amedia[] = (Media[]) obj;\r
+                    Set<SortableMediaSizeName> sizeSet = new TreeSet<SortableMediaSizeName>();\r
+\r
+                    for (int i = 0; i < amedia.length; i++) {\r
+                        Media media = amedia[i];\r
+                        if (media instanceof MediaSizeName) {\r
+                            sizeSet.add(new SortableMediaSizeName((MediaSizeName) media));\r
+                        }\r
+                        else if (media instanceof MediaTray) {\r
+                            sources.add(media);\r
+                            cbSource.addItem(getMediaName(media.toString()));\r
+                        }\r
+                    }\r
+\r
+                    //The set eliminates duplicates.\r
+                    for (Iterator<SortableMediaSizeName> mediaSizeNameIterator = sizeSet.iterator(); mediaSizeNameIterator\r
+                            .hasNext();) {\r
+                        SortableMediaSizeName media = mediaSizeNameIterator.next();\r
+\r
+                        sizes.add(media.getMediaSizeName());\r
+                        cbSize.addItem(media.toString());\r
+                    }\r
+\r
+                }\r
+            }\r
+            boolean flag1 = flag && sizes.size() > 0;\r
+            lblSize.setEnabled(flag1);\r
+            cbSize.setEnabled(flag1);\r
+            cbSource.setEnabled(false);\r
+            lblSource.setEnabled(false);\r
+            if (flag) {\r
+                Media media = (Media) asCurrent.get(Media.class);\r
+                boolean attributeValueSupported = false;\r
+                try {\r
+                    attributeValueSupported = psCurrent.isAttributeValueSupported(media, docFlavor, asCurrent);\r
+                }\r
+                catch (IllegalArgumentException iae) {\r
+                    pdfFlavorSupported = false;\r
+                    //dgp\r
+                }\r
+                if (media == null || !attributeValueSupported) {\r
+                    media = (Media) psCurrent.getDefaultAttributeValue(Media.class);\r
+                    if (media == null && sizes.size() > 0) {\r
+                        media = sizes.get(0);\r
+                    }\r
+                    if (media != null) {\r
+                        asCurrent.add(media);\r
+                    }\r
+                }\r
+                if (media != null) {\r
+                    if (media instanceof MediaSizeName) {\r
+                        MediaSizeName mediasizename = (MediaSizeName) media;\r
+                        cbSize.setSelectedIndex(sizes.indexOf(mediasizename));\r
+                    }\r
+                    else if (media instanceof MediaTray) {\r
+                        MediaTray mediatray = (MediaTray) media;\r
+                        cbSource.setSelectedIndex(sources.indexOf(mediatray) + 1);\r
+                    }\r
+                }\r
+                else {\r
+                    cbSize.setSelectedIndex(sizes.size() <= 0 ? -1 : 0);\r
+                    cbSource.setSelectedIndex(0);\r
+                }\r
+                int j = cbSize.getSelectedIndex();\r
+                if (j >= 0 && j < sizes.size()) {\r
+                    asCurrent.add(sizes.get(j));\r
+                }\r
+                j = cbSource.getSelectedIndex();\r
+                if (j >= 1 && j < sources.size() + 1) {\r
+                    asCurrent.add((MediaTray) sources.get(j - 1));\r
+                }\r
+            }\r
+            cbSize.addItemListener(this);\r
+            cbSource.addItemListener(this);\r
+        }\r
+\r
+        public MediaPanel () {\r
+            super(new MigLayout("fill, gap rel unrel"));\r
+            sizes = new ArrayList<MediaSizeName>();\r
+            sources = new ArrayList();\r
+            setBorder(BorderFactory.createTitledBorder(strTitle));\r
+            cbSize = new JComboBox();\r
+            cbSource = new JComboBox();\r
+            lblSize = new JLabel(SIZE, 11);\r
+            lblSize.setDisplayedMnemonic(PrintServiceDialog.getMnemonic(SIZE));\r
+            lblSize.setLabelFor(cbSize);\r
+            add(lblSize);\r
+            add(cbSize, "wrap");\r
+            lblSource = new JLabel(SOURCE, 11);\r
+            lblSource.setDisplayedMnemonic(PrintServiceDialog.getMnemonic(SOURCE));\r
+            lblSource.setLabelFor(cbSource);\r
+            add(lblSource);\r
+            add(cbSource);\r
+        }\r
+\r
+        class SortableMediaSizeName implements Comparable {\r
+            MediaSizeName delegate;\r
+\r
+            String displayableName;\r
+\r
+            SortableMediaSizeName(MediaSizeName msn) {\r
+                delegate = msn;\r
+                displayableName = getMediaName(delegate.toString());\r
+                if (displayableName == null) {\r
+                    displayableName = delegate.toString();\r
+                }\r
+            }\r
+\r
+            /**\r
+             * Returns a string value corresponding to this enumeration value.\r
+             */\r
+            @Override\r
+            public String toString () {\r
+                return displayableName;\r
+            }\r
+\r
+            @Override\r
+            public int compareTo (final Object o) {\r
+                String name = displayableName;\r
+                if (name != null) {\r
+                    return name.compareTo(o.toString());\r
+                }\r
+                return 1;\r
+            }\r
+\r
+            @Override\r
+            public boolean equals (final Object o) {\r
+                if (this == o) {\r
+                    return true;\r
+                }\r
+                if (o == null || getClass() != o.getClass()) {\r
+                    return false;\r
+                }\r
+\r
+                final SortableMediaSizeName that = (SortableMediaSizeName) o;\r
+\r
+                return displayableName.equals(that.displayableName);\r
+            }\r
+\r
+            @Override\r
+            public int hashCode () {\r
+                return displayableName.hashCode();\r
+            }\r
+\r
+            MediaSizeName getMediaSizeName() {\r
+                return delegate;\r
+            }\r
+        }\r
+    }\r
+\r
+    private class PrintServicePanel extends JPanel\r
+            implements ActionListener, ItemListener, PopupMenuListener {\r
+\r
+        private final String strTitle = "Print Service";\r
+        private JButton btnProperties;\r
+        private JComboBox cbName;\r
+        private JLabel lblType, lblStatus, lblInfo;\r
+        private JLabel vType, vStatus, vInfo;\r
+        private ServiceUIFactory uiFactory;\r
+        private boolean changedService;\r
+\r
+        public PrintServicePanel () {\r
+            super(new MigLayout("fill, gap rel unrel"));\r
+            changedService = false;\r
+            uiFactory = psCurrent.getServiceUIFactory();\r
+            setBorder(BorderFactory.createTitledBorder(strTitle));\r
+            String as[] = new String[services.length];\r
+            for (int i = 0; i < as.length; i++) {\r
+                as[i] = services[i].getName();\r
+            }\r
+\r
+            cbName = new JComboBox(as);\r
+            cbName.setSelectedIndex(defaultServiceIndex);\r
+            cbName.addItemListener(this);\r
+            cbName.addPopupMenuListener(this);\r
+            JLabel jlabel = new JLabel(("Name:"), 11);\r
+            jlabel.setDisplayedMnemonic(PrintServiceDialog.getMnemonic("Name"));\r
+            jlabel.setLabelFor(cbName);\r
+            add(jlabel);\r
+            add(cbName);\r
+            btnProperties = PrintServiceDialog.createButton("Properties...", this);\r
+            add(btnProperties, "wrap");\r
+            lblStatus = new JLabel("Status:", 11);\r
+            add(lblStatus);\r
+            vStatus = new JLabel();\r
+            add(vStatus, "wrap");\r
+            lblType = new JLabel("Type:", 11);\r
+            vType = new JLabel();\r
+            add(lblType);\r
+            add(vType, "wrap");\r
+            lblInfo = new JLabel("Info:", 11);\r
+            vInfo = new JLabel();\r
+            add(lblInfo);\r
+            add(vInfo, "wrap");\r
+        }\r
+\r
+        public void actionPerformed (ActionEvent actionevent) {\r
+            Object obj = actionevent.getSource();\r
+            if (obj == btnProperties && uiFactory != null) {\r
+                JDialog jdialog = (JDialog) uiFactory.getUI(3, "javax.swing.JDialog");\r
+                if (jdialog != null) {\r
+                    jdialog.show();\r
+                }\r
+                else {\r
+                    btnProperties.setEnabled(false);\r
+                }\r
+            }\r
+        }\r
+\r
+        public void itemStateChanged (ItemEvent itemevent) {\r
+            if (itemevent.getStateChange() == 1) {\r
+                int i = cbName.getSelectedIndex();\r
+                if (i >= 0 && i < services.length && !services[i].equals(psCurrent)) {\r
+                    psCurrent = services[i];\r
+                    uiFactory = psCurrent.getServiceUIFactory();\r
+                    changedService = true;\r
+                    Destination destination = (Destination) asOriginal.get(\r
+                            Destination.class);\r
+                    if ((destination != null) && psCurrent.isAttributeCategorySupported(\r
+                            Destination.class)) {\r
+                        asCurrent.add(destination);\r
+                    }\r
+                    else {\r
+                        asCurrent.remove(Destination.class);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        public void popupMenuWillBecomeVisible (PopupMenuEvent popupmenuevent) {\r
+            changedService = false;\r
+        }\r
+\r
+        public void popupMenuWillBecomeInvisible (PopupMenuEvent popupmenuevent) {\r
+            if (changedService) {\r
+                changedService = false;\r
+                updatePanels();\r
+            }\r
+        }\r
+\r
+        public void popupMenuCanceled (PopupMenuEvent popupmenuevent) {\r
+        }\r
+\r
+        public void updateInfo () {\r
+            PrintServiceAttribute psa = psCurrent.getAttribute(PrinterMakeAndModel.class);\r
+            if (psa != null) {\r
+                vType.setText(psa.toString());\r
+            }\r
+            psa = psCurrent.getAttribute(PrinterIsAcceptingJobs.class);\r
+            if (psa != null) {\r
+                vStatus.setText((psa.toString()));\r
+            }\r
+            psa = psCurrent.getAttribute(PrinterInfo.class);\r
+            if (psa != null) {\r
+                vInfo.setText(psa.toString());\r
+            }\r
+            btnProperties.setEnabled(uiFactory != null);\r
+        }\r
+\r
+    }\r
+\r
+    private class GeneralPanel extends JPanel {\r
+\r
+        public void updateInfo () {\r
+            pnlPrintService.updateInfo();\r
+            pnlMedia.updateInfo();\r
+        }\r
+\r
+        private PrintServicePanel pnlPrintService;\r
+        private MediaPanel pnlMedia;\r
+\r
+        public GeneralPanel () {\r
+            super(new MigLayout("fill, gap rel unrel"));\r
+            pnlPrintService = new PrintServicePanel();\r
+            add(pnlPrintService, "wrap");\r
+            pnlMedia = new MediaPanel();\r
+            add(pnlMedia, "wrap");\r
+        }\r
+    }\r
+\r
+\r
+    public PrintServiceDialog (GraphicsConfiguration graphicsconfiguration, int i, int j, PrintService aprintservice[],\r
+                               int k, DocFlavor docflavor, PrintRequestAttributeSet printrequestattributeset,\r
+                               Dialog dialog, JPanel... additional) {\r
+        super(dialog, PRINT_BUTTON_LABEL, true, graphicsconfiguration);\r
+        initPrintDialog(i, j, aprintservice, k, docflavor, printrequestattributeset, additional);\r
+    }\r
+\r
+    void initPrintDialog (int i, int j, PrintService aprintservice[], int k, DocFlavor docflavor,\r
+                          PrintRequestAttributeSet printrequestattributeset,\r
+                          JPanel... additional) {\r
+        services = aprintservice;\r
+        defaultServiceIndex = k;\r
+        asOriginal = printrequestattributeset;\r
+        asCurrent = new HashPrintRequestAttributeSet(printrequestattributeset);\r
+        psCurrent = aprintservice[k];\r
+        docFlavor = docflavor;\r
+        Container container = getContentPane();\r
+        container.setLayout(new BorderLayout());\r
+        final JTabbedPane tpTabs = new JTabbedPane();\r
+        tpTabs.setBorder(new EmptyBorder(5, 5, 5, 5));\r
+\r
+        if (additional != null) {\r
+            for (JPanel anAdditional : additional) {\r
+                tpTabs.add(anAdditional, anAdditional.getName(), 0);\r
+            }\r
+        }\r
+        pnlGeneral = new GeneralPanel();\r
+        tpTabs.add(GENERAL_TAB_TITLE, pnlGeneral);\r
+\r
+        container.add(tpTabs, "Center");\r
+        updatePanels();\r
+        JPanel jpanel = new JPanel(new MigLayout());\r
+        btnPrint = createExitButton(PRINT_BUTTON_LABEL, this);\r
+        jpanel.add(btnPrint, "x 300");\r
+        getRootPane().setDefaultButton(btnPrint);\r
+        btnPrint.setEnabled(pdfFlavorSupported);\r
+\r
+        btnCancel = createExitButton(CANCEL_BUTTON_LABEL, this);\r
+        handleEscKey(btnCancel);\r
+        jpanel.add(btnCancel, "x 380");\r
+        container.add(jpanel, "South");\r
+        addWindowListener(new WindowAdapter() {\r
+            public void windowClosing (WindowEvent windowevent) {\r
+                dispose(2);\r
+            }\r
+        }\r
+        );\r
+        setResizable(false);\r
+        setLocation(i, j);\r
+        pack();\r
+    }\r
+\r
+    private void handleEscKey (JButton jbutton) {\r
+        AbstractAction abstractaction = new AbstractAction() {\r
+\r
+            public void actionPerformed (ActionEvent actionevent) {\r
+                dispose(2);\r
+            }\r
+\r
+        };\r
+        KeyStroke keystroke = KeyStroke.getKeyStroke('\033', false);\r
+        InputMap inputmap = jbutton.getInputMap(2);\r
+        ActionMap actionmap = jbutton.getActionMap();\r
+        if (inputmap != null && actionmap != null) {\r
+            inputmap.put(keystroke, "cancel");\r
+            actionmap.put("cancel", abstractaction);\r
+        }\r
+    }\r
+\r
+    public int getStatus () {\r
+        return status;\r
+    }\r
+\r
+    public PrintRequestAttributeSet getAttributes () {\r
+        if (status == 1) {\r
+            return asCurrent;\r
+        }\r
+        else {\r
+            return asOriginal;\r
+        }\r
+    }\r
+\r
+    public PrintService getPrintService () {\r
+        if (status == 1) {\r
+            return psCurrent;\r
+        }\r
+        else {\r
+            return null;\r
+        }\r
+    }\r
+\r
+    public void dispose (int i) {\r
+        status = i;\r
+        super.dispose();\r
+    }\r
+\r
+    public void actionPerformed (ActionEvent actionevent) {\r
+        Object obj = actionevent.getSource();\r
+        boolean flag = false;\r
+        if (obj == btnPrint) {\r
+            flag = true;\r
+            if (pnlGeneral != null) {\r
+                asCurrent.remove(Destination.class);\r
+            }\r
+        }\r
+        dispose(flag ? 1 : 2);\r
+    }\r
+\r
+\r
+    private void updatePanels () {\r
+        pnlGeneral.updateInfo();\r
+    }\r
+\r
+    private static char getMnemonic (String s) {\r
+        if (s != null && s.length() > 0) {\r
+            return s.charAt(0);\r
+        }\r
+        else {\r
+            return '\0';\r
+        }\r
+    }\r
+\r
+    private static JButton createButton (String s, ActionListener actionlistener) {\r
+        JButton jbutton = new JButton(s);\r
+        jbutton.setMnemonic(getMnemonic(s));\r
+        jbutton.addActionListener(actionlistener);\r
+        return jbutton;\r
+    }\r
+\r
+    private static JButton createExitButton (String s, ActionListener actionlistener) {\r
+        JButton jbutton = new JButton(s);\r
+        jbutton.addActionListener(actionlistener);\r
+        jbutton.getAccessibleContext().setAccessibleDescription(s);\r
+        return jbutton;\r
+    }\r
+\r
+    static class MediaWrapper\r
+            implements PrintRequestAttribute {\r
+\r
+        private Media media;\r
+\r
+        MediaWrapper (Media theMedia) {\r
+            media = theMedia;\r
+        }\r
+\r
+        Media getMedia () {\r
+            return media;\r
+        }\r
+\r
+        public final Class getCategory () {\r
+            return this.getClass();\r
+        }\r
+\r
+        public final String getName () {\r
+            return "mw";\r
+        }\r
+\r
+        public String toString () {\r
+            return media.toString();\r
+        }\r
+\r
+        public int hashCode () {\r
+            return media.hashCode();\r
+        }\r
+\r
+    }\r
+\r
+}\r
index b2bc5c53ab22b95bdfaf2462ba3b69666b2ae363..a7efd907db61d03e6731f295d539f2de1a71ac41 100644 (file)
@@ -4,11 +4,10 @@
 package net.sf.openrocket.gui.print;
 
 
-import com.itextpdf.text.Chunk;
-import com.itextpdf.text.Document;
-import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.*;
 import com.itextpdf.text.Font;
-import com.itextpdf.text.Paragraph;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
 
 import javax.print.DocFlavor;
 import javax.print.PrintService;
@@ -17,18 +16,24 @@ import javax.print.ServiceUI;
 import javax.print.attribute.HashPrintRequestAttributeSet;
 import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.standard.MediaSize;
-import javax.swing.RepaintManager;
-import java.awt.Component;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
+import javax.swing.*;
+import java.awt.*;
 import java.awt.print.PageFormat;
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
 import java.awt.print.PrinterJob;
 import java.util.Locale;
 
+/**
+ * Utilities methods and fonts used for printing.
+ */
 public class PrintUtilities implements Printable {
 
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
     public static final int NORMAL_FONT_SIZE = Font.DEFAULTSIZE - 3;
     public static final int SMALL_FONT_SIZE = NORMAL_FONT_SIZE - 3;
 
@@ -127,6 +132,13 @@ public class PrintUtilities implements Printable {
         g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
     }
 
+    /**
+     * Add text as a new paragraph in a given font to the document.
+     *
+     * @param document  the document
+     * @param font      the font
+     * @param title     the title
+     */
     public static void addText (Document document, com.itextpdf.text.Font font, String title) {
         Chunk sectionHeader = new Chunk(title);
         sectionHeader.setFont(font);
@@ -136,7 +148,7 @@ public class PrintUtilities implements Printable {
             document.add(p);
         }
         catch (DocumentException e) {
-            e.printStackTrace();
+            log.error("Could not add paragraph.", e);
         }
     }
 }
index 6645b6960b010ac19b14d99fed749d98ee6811cf..1f37435dae318219a381b115d450694ca34a81bc 100644 (file)
@@ -4,11 +4,7 @@
  */
 package net.sf.openrocket.gui.print;
 
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import java.util.*;
 
 /**
  * Instances of this class are meant to keep track of what the user has selected to be printed.
@@ -25,9 +21,14 @@ public class PrintableContext implements Comparable<PrintableContext>, Iterable<
      */
     private OpenRocketPrintable printable;
 
+    /**
+     * Sort of a reverse map that tracks each type of printable item and the stages for which that item is to be printed.
+     */
     private final Map<OpenRocketPrintable, Set<Integer>> previous = new TreeMap<OpenRocketPrintable, Set<Integer>>();
 
-    
+    /**
+     * Constructor.
+     */
     public PrintableContext () {
     }
 
@@ -48,8 +49,13 @@ public class PrintableContext implements Comparable<PrintableContext>, Iterable<
         printable = thePrintable;
     }
 
-    public void add (final Integer theStageNumber, final OpenRocketPrintable thePrintable)
-            throws IllegalArgumentException {
+    /**
+     * Add a type of printable to a stage (number).
+     *
+     * @param theStageNumber  the stage number
+     * @param thePrintable    the printable to associate with the stage
+     */
+    public void add (final Integer theStageNumber, final OpenRocketPrintable thePrintable) {
         Set<Integer> stages = previous.get(thePrintable);
         if (stages == null) {
             stages = new TreeSet<Integer>();
@@ -60,7 +66,7 @@ public class PrintableContext implements Comparable<PrintableContext>, Iterable<
         }
     }
 
-
+    /** PrintableContext iterator. */
     public Iterator<PrintableContext> iterator () {
         return new Iterator<PrintableContext>() {
 
diff --git a/src/net/sf/openrocket/gui/print/visitor/BaseVisitorStrategy.java b/src/net/sf/openrocket/gui/print/visitor/BaseVisitorStrategy.java
deleted file mode 100644 (file)
index 8998a83..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * BaseVisitorStrategy.java
- */
-package net.sf.openrocket.gui.print.visitor;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import net.sf.openrocket.rocketcomponent.BodyComponent;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.ComponentVisitor;
-import net.sf.openrocket.rocketcomponent.ComponentVisitorStrategy;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.MassObject;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
-
-import com.itextpdf.text.Document;
-import com.itextpdf.text.pdf.PdfWriter;
-
-/**
- * This abstract class contains boilerplate functionality to support visiting the components of a rocket. It is a
- * visitor strategy, not a visitor per se.
- */
-public abstract class BaseVisitorStrategy implements ComponentVisitorStrategy {
-       
-       /**
-        * The owning visitor.
-        */
-       protected ComponentVisitor parent;
-       
-       /**
-        * The iText document.
-        */
-       protected Document document;
-       
-       /**
-        * The direct iText writer.
-        */
-       protected PdfWriter writer;
-       
-       /**
-        * The stages selected.
-        */
-       protected Set<Integer> stages;
-       
-       /**
-        * State variable to track the level of hierarchy.
-        */
-       protected int level = 0;
-       
-       /**
-        * Default no-arg constructor.
-        */
-       public BaseVisitorStrategy() {
-       }
-       
-       /**
-        * Constructor.
-        *
-        * @param doc the iText document
-        */
-       public BaseVisitorStrategy(Document doc) {
-               this(doc, null);
-       }
-       
-       /**
-        * Constructor.
-        *
-        * @param doc       the iText document
-        * @param theWriter an iText byte writer
-        */
-       public BaseVisitorStrategy(Document doc, PdfWriter theWriter) {
-               this(doc, theWriter, new HashSet<Integer>());
-       }
-       
-       /**
-        * Constructor.
-        *
-        * @param doc       the iText document
-        * @param theWriter an iText byte writer
-        * @param theStages a set of stage numbers
-        */
-       public BaseVisitorStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStages) {
-               document = doc;
-               writer = theWriter;
-               stages = theStages;
-       }
-       
-       /**
-        * Determine if the visitor strategy's set of stage numbers (to print) contains the specified stage.
-        *
-        * @param stageNumber a stage number
-        *
-        * @return true if the visitor strategy contains the stage number provided
-        */
-       public boolean shouldVisitStage(int stageNumber) {
-               if (stages == null || stages.isEmpty()) {
-                       return false;
-               }
-               
-               for (final Integer stage : stages) {
-                       if (stage == stageNumber) {
-                               return true;
-                       }
-               }
-               
-               return false;
-       }
-       
-       /**
-        * Recurse through the given rocket component.
-        *
-        * @param root the root component; all children will be visited recursively
-        */
-       protected void goDeep(final RocketComponent root) {
-               List<RocketComponent> rc = root.getChildren();
-               goDeep(rc);
-       }
-       
-       
-       /**
-        * Recurse through the given rocket component.
-        *
-        * @param theRc an array of rocket components; all children will be visited recursively
-        */
-       protected void goDeep(final List<RocketComponent> theRc) {
-               level++;
-               for (RocketComponent rocketComponent : theRc) {
-                       rocketComponent.accept(parent);
-               }
-               level--;
-       }
-       
-       /**
-        * Get the dimensions of the paper page.
-        *
-        * @return an internal Dimension
-        */
-       protected Dimension getPageSize() {
-               return new Dimension(document.getPageSize().getWidth(),
-                                                               document.getPageSize().getHeight());
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Rocket visitable) {
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RocketComponent visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Stage visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final ExternalComponent visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyComponent visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RingComponent visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final InnerTube visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final LaunchLug visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Transition visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RadiusRingComponent visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final MassObject visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final NoseCone visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyTube visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final TrapezoidFinSet visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final EllipticalFinSet visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final FreeformFinSet visitable) {
-               if (shouldVisitStage(visitable.getStageNumber())) {
-                       goDeep(visitable);
-               }
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void setParent(final ComponentVisitor theParent) {
-               parent = theParent;
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void close() {
-       }
-}
-
-class Dimension {
-       public float width;
-       public float height;
-       
-       public Dimension(float w, float h) {
-               width = w;
-               height = h;
-       }
-       
-       public float getWidth() {
-               return width;
-       }
-       
-       public float getHeight() {
-               return height;
-       }
-}
\ No newline at end of file
index 112ddb86c9643e26ca261864a8652a89cdb249d6..a079bb80ae65e90e80d31a48f6e1a0994c073fa8 100644 (file)
@@ -10,19 +10,40 @@ import com.itextpdf.text.pdf.PdfContentByte;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.gui.print.ITextHelper;
 import net.sf.openrocket.gui.print.PrintableFinSet;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
 
-import java.awt.Graphics2D;
+import java.awt.*;
 import java.awt.image.BufferedImage;
+import java.util.List;
 import java.util.Set;
 
 /**
- * A visitor strategy for drawing fin templates.
+ * A strategy for drawing fin templates.
  */
-public class FinSetVisitorStrategy extends BaseVisitorStrategy {
+public class FinSetVisitorStrategy {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
+    /**
+     * The iText document.
+     */
+    protected Document document;
+
+    /**
+     * The direct iText writer.
+     */
+    protected PdfWriter writer;
+
+    /**
+     * The stages selected.
+     */
+    protected Set<Integer> stages;
 
     /**
      * Constructor.
@@ -32,31 +53,36 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy {
      * @param theStagesToVisit The stages to be visited by this strategy
      */
     public FinSetVisitorStrategy (Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
-        super(doc, theWriter, theStagesToVisit);
+        document = doc;
+        writer = theWriter;
+        stages = theStagesToVisit;
     }
 
     /**
-     * {@inheritDoc}
+     * Recurse through the given rocket component.
+     *
+     * @param root the root component; all children will be visited recursively
      */
-    @Override
-    public void visit (final TrapezoidFinSet visitable) {
-        doVisit(visitable);
+    public void writeToDocument (final RocketComponent root) {
+        List<RocketComponent> rc = root.getChildren();
+        goDeep(rc);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void visit (final EllipticalFinSet visitable) {
-        doVisit(visitable);
-    }
 
     /**
-     * {@inheritDoc}
+     * Recurse through the given rocket component.
+     *
+     * @param theRc an array of rocket components; all children will be visited recursively
      */
-    @Override
-    public void visit (final FreeformFinSet visitable) {
-        doVisit(visitable);
+    protected void goDeep (final List<RocketComponent> theRc) {
+        for (RocketComponent rocketComponent : theRc) {
+            if (rocketComponent instanceof FinSet) {
+                doVisit((FinSet)rocketComponent);
+            }
+            else if (rocketComponent.getChildCount() > 0) {
+                goDeep(rocketComponent.getChildren());
+            }
+        }
     }
 
     /**
@@ -81,11 +107,32 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy {
                 }
             }
             catch (DocumentException e) {
-                e.printStackTrace();
+                log.error("Could not render fin.", e);
             }
         }
     }
 
+    /**
+     * Determine if the visitor strategy's set of stage numbers (to print) contains the specified stage.
+     *
+     * @param stageNumber a stage number
+     *
+     * @return true if the visitor strategy contains the stage number provided
+     */
+    public boolean shouldVisitStage (int stageNumber) {
+        if (stages == null || stages.isEmpty()) {
+            return false;
+        }
+
+        for (final Integer stage : stages) {
+            if (stage == stageNumber) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Determine if the image will fit on the given page.
      *
@@ -118,5 +165,52 @@ public class FinSetVisitorStrategy extends BaseVisitorStrategy {
         g2.dispose();
         document.newPage();
     }
-}
 
+    /**
+     * Get the dimensions of the paper page.
+     *
+     * @return an internal Dimension
+     */
+    protected Dimension getPageSize () {
+        return new Dimension(document.getPageSize().getWidth(),
+                             document.getPageSize().getHeight());
+    }
+
+    /**
+     * Convenience class to model a dimension.
+     */
+    class Dimension {
+        /** Width, in points. */
+        public float width;
+        /** Height, in points. */
+        public float height;
+
+        /**
+         * Constructor.
+         * @param w width
+         * @param h height
+         */
+        public Dimension (float w, float h) {
+            width = w;
+            height = h;
+        }
+
+        /**
+         * Get the width.
+         *
+         * @return  the width
+         */
+        public float getWidth () {
+            return width;
+        }
+
+        /**
+         * Get the height.
+         *
+         * @return the height
+         */
+        public float getHeight () {
+            return height;
+        }
+    }
+}
diff --git a/src/net/sf/openrocket/gui/print/visitor/MotorMountVisitorStrategy.java b/src/net/sf/openrocket/gui/print/visitor/MotorMountVisitorStrategy.java
deleted file mode 100644 (file)
index 579cb2d..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * MotorMountVisitor.java
- */
-package net.sf.openrocket.gui.print.visitor;
-
-import com.itextpdf.text.Document;
-import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.MotorMount;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A visitor strategy for finding data about motor configurations.  This visitor accumulates information about the
- * motors currently 'installed' into each motor mount in the rocket.  When the visitor is complete, invoke {@link
- * #getMotors()} to obtain the list of Motor instances that correspond to the motor configuration.
- */
-public class MotorMountVisitorStrategy extends BaseVisitorStrategy {
-
-    /**
-     * The motor configuration identifier.
-     */
-    private String mid;
-
-    /** The accumulating list of motors. */
-    private List<Motor> motors = new ArrayList<Motor>();
-
-    /**
-     * Constructor.
-     *
-     * @param doc           the iText document
-     * @param motorConfigID the motor configuration ID
-     */
-    public MotorMountVisitorStrategy (Document doc,
-                                      String motorConfigID) {
-        super(doc);
-        mid = motorConfigID;
-    }
-
-    /**
-     * Override the method that determines if the visiting should be going deep.
-     *
-     * @param stageNumber a stage number
-     *
-     * @return true, always
-     */
-    public boolean shouldVisitStage (int stageNumber) {
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void visit (final BodyTube visitable) {
-        if (visitable.isMotorMount()) {
-            doVisit(visitable);
-        }
-        else {
-            goDeep(visitable);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void visit (final InnerTube visitable) {
-        if (visitable.isMotorMount()) {
-            doVisit(visitable);
-        }
-    }
-
-    /**
-     * The core behavior of this visitor.
-     *
-     * @param visitable the object to extract info about; a graphical image of the fin shape is drawn to the document
-     */
-    private void doVisit (final MotorMount visitable) {
-        final Motor motor = visitable.getMotor(mid);
-        if (motor != null) {
-            motors.add(motor);
-        }
-    }
-
-    /**
-     * Answer with the list of motors that have been accumulated from visiting all of the motor mount components in the
-     * rocket component hierarchy.
-     *
-     * @return a list of motors
-     */
-    public List<Motor> getMotors () {
-        return motors;
-    }
-
-}
-
-
index 6151149cfd187bfa96eee46ffa2d95f9aa754965..cdeb9247c17742590137596438842d2892884c3f 100644 (file)
  */
 package net.sf.openrocket.gui.print.visitor;
 
-import java.io.IOException;
-import java.text.NumberFormat;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-import javax.swing.ImageIcon;
-
+import com.itextpdf.text.*;
+import com.itextpdf.text.pdf.PdfPCell;
+import com.itextpdf.text.pdf.PdfPTable;
+import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.gui.main.ComponentIcons;
 import net.sf.openrocket.gui.print.ITextHelper;
 import net.sf.openrocket.gui.print.PrintUtilities;
 import net.sf.openrocket.gui.print.PrintableFinSet;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyComponent;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.Coaxial;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.MassObject;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
+import net.sf.openrocket.rocketcomponent.*;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.Coordinate;
 
-import com.itextpdf.text.BadElementException;
-import com.itextpdf.text.Chunk;
-import com.itextpdf.text.Document;
-import com.itextpdf.text.DocumentException;
-import com.itextpdf.text.Element;
-import com.itextpdf.text.Font;
-import com.itextpdf.text.Image;
-import com.itextpdf.text.Phrase;
-import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.pdf.PdfPCell;
-import com.itextpdf.text.pdf.PdfPTable;
-import com.itextpdf.text.pdf.PdfWriter;
+import javax.swing.*;
+import java.text.NumberFormat;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
 
 /**
  * A visitor strategy for creating documentation about parts details.
  */
-public class PartsDetailVisitorStrategy extends BaseVisitorStrategy {
-       
-       /**
-        * The number of columns in the table.
-        */
-       private static final int TABLE_COLUMNS = 7;
-       
-       /**
-        * The parts detail is represented as an iText table.
-        */
-       PdfPTable grid;
-       
-       /**
-        * Construct a strategy for visiting a parts hierarchy for the purposes of collecting details on those parts.
-        *
-        * @param doc              The iText document
-        * @param theWriter        The direct iText writer
-        * @param theStagesToVisit The stages to be visited by this strategy
-        */
-       public PartsDetailVisitorStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
-               super(doc, theWriter, theStagesToVisit);
-               PrintUtilities.addText(doc, PrintUtilities.BIG_BOLD, "Parts Detail");
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Stage visitable) {
-               try {
-                       if (grid != null) {
-                               document.add(grid);
-                       }
-                       document.add(ITextHelper.createPhrase(visitable.getName()));
-                       grid = new PdfPTable(TABLE_COLUMNS);
-                       grid.setWidthPercentage(100);
-                       grid.setHorizontalAlignment(Element.ALIGN_LEFT);
-               } catch (DocumentException e) {
-               }
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final ExternalComponent visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(ITextHelper.createCell());
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyComponent visitable) {
-               grid.addCell(visitable.getName());
-               grid.completeRow();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RingComponent visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(createOuterDiaCell(visitable));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final InnerTube visitable) {
-               grid.addCell(iconToImage(visitable));
-               final PdfPCell pCell = createNameCell(visitable.getName(), true);
-               grid.addCell(pCell);
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(createOuterDiaCell(visitable));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final LaunchLug visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(createOuterDiaCell(visitable));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Transition visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               
-               Chunk fore = new Chunk("Fore Dia: " + appendLength(visitable.getForeRadius() * 2));
-               fore.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               Chunk aft = new Chunk("Aft Dia: " + appendLength(visitable.getAftRadius() * 2));
-               aft.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               final PdfPCell cell = ITextHelper.createCell();
-               cell.addElement(fore);
-               cell.addElement(aft);
-               grid.addCell(cell);
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RadiusRingComponent visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(createOuterDiaCell(visitable));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final MassObject visitable) {
-               PdfPCell cell = ITextHelper.createCell();
-               cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
-               cell.setPaddingBottom(12f);
-               
-               grid.addCell(iconToImage(visitable));
-               final PdfPCell nameCell = createNameCell(visitable.getName(), true);
-               nameCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
-               nameCell.setPaddingBottom(12f);
-               grid.addCell(nameCell);
-               grid.addCell(cell);
-               grid.addCell(cell);
-               grid.addCell(cell);
-               grid.addCell(createMassCell(visitable.getMass()));
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final NoseCone visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(ITextHelper.createCell(visitable.getType().getName(), PdfPCell.BOTTOM));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyTube visitable) {
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName(), true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(createOuterDiaCell(visitable));
-               grid.addCell(createLengthCell(visitable.getLength()));
-               grid.addCell(createMassCell(visitable.getMass()));
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final TrapezoidFinSet visitable) {
-               visitFins(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final EllipticalFinSet visitable) {
-               visitFins(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final FreeformFinSet visitable) {
-               visitFins(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void close() {
-               try {
-                       if (grid != null) {
-                               document.add(grid);
-                       }
-               } catch (DocumentException e) {
-                       e.printStackTrace();
-               }
-       }
-       
-       private PdfPCell createOuterDiaCell(final Coaxial visitable) {
-               PdfPCell result = new PdfPCell();
-               Phrase p = new Phrase();
-               p.setLeading(12f);
-               result.setVerticalAlignment(Element.ALIGN_TOP);
-               result.setBorder(Rectangle.BOTTOM);
-               Chunk c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               c.append("Dia");
-               p.add(c);
-               
-               c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
-               c.append("out");
-               p.add(c);
-               
-               c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               c.append(" " + appendLength(visitable.getOuterRadius() * 2));
-               p.add(c);
-               createInnerDiaCell(visitable, result);
-               result.addElement(p);
-               return result;
-       }
-       
-       private void createInnerDiaCell(final Coaxial visitable, PdfPCell cell) {
-               Phrase p = new Phrase();
-               p.setLeading(14f);
-               Chunk c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               c.append("Dia");
-               p.add(c);
-               
-               c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
-               c.append("in ");
-               p.add(c);
-               
-               c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               c.append("  " + appendLength(visitable.getInnerRadius() * 2));
-               p.add(c);
-               cell.addElement(p);
-       }
-       
-       private void visitFins(FinSet visitable) {
-               
-               Image img = null;
-               java.awt.Image awtImage = new PrintableFinSet(visitable).createImage();
-               
-               Collection<Coordinate> x = visitable.getComponentBounds();
-               
-               try {
-                       img = Image.getInstance(writer, awtImage, 0.25f);
-               } catch (BadElementException e) {
-                       e.printStackTrace();
-               } catch (IOException e) {
-                       e.printStackTrace();
-               }
-               
-               grid.addCell(iconToImage(visitable));
-               grid.addCell(createNameCell(visitable.getName() + " (" + visitable.getFinCount() + ")", true));
-               grid.addCell(createMaterialCell(visitable.getMaterial()));
-               grid.addCell(ITextHelper.createCell("Thick: " + appendLength(visitable.getThickness()), PdfPCell.BOTTOM));
-               final PdfPCell pCell = new PdfPCell();
-               pCell.setBorder(Rectangle.BOTTOM);
-               pCell.addElement(img);
-               
-               grid.addCell(ITextHelper.createCell());
-               grid.addCell(createMassCell(visitable.getMass()));
-               
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       protected PdfPCell createLengthCell(double length) {
-               return ITextHelper.createCell("Len: " + appendLength(length), PdfPCell.BOTTOM);
-       }
-       
-       protected PdfPCell createMassCell(double mass) {
-               return ITextHelper.createCell("Mass: " + appendMass(mass), PdfPCell.BOTTOM);
-       }
-       
-       protected PdfPCell createNameCell(String v, boolean withIndent) {
-               PdfPCell result = new PdfPCell();
-               result.setBorder(Rectangle.BOTTOM);
-               Chunk c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               if (withIndent) {
-                       for (int x = 0; x < (level - 2) * 10; x++) {
-                               c.append(" ");
-                       }
-               }
-               c.append(v);
-               result.setColspan(2);
-               result.addElement(c);
-               return result;
-       }
-       
-       protected PdfPCell createMaterialCell(Material material) {
-               PdfPCell cell = ITextHelper.createCell();
-               cell.setLeading(13f, 0);
-               
-               Chunk c = new Chunk();
-               c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-               c.append(appendMaterial(material));
-               cell.addElement(c);
-               Chunk density = new Chunk();
-               density.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
-               density.append(appendMaterialDensity(material));
-               cell.addElement(density);
-               return cell;
-       }
-       
-       protected PdfPCell iconToImage(final RocketComponent visitable) {
-               final ImageIcon icon = (ImageIcon) ComponentIcons.getLargeIcon(visitable.getClass());
-               try {
-                       Image im = Image.getInstance(icon.getImage(), null);
-                       im.scaleToFit(icon.getIconWidth() * 0.6f, icon.getIconHeight() * 0.6f);
-                       PdfPCell cell = new PdfPCell(im);
-                       cell.setFixedHeight(icon.getIconHeight() * 0.6f);
-                       cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
-                       cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
-                       cell.setBorder(PdfPCell.NO_BORDER);
-                       return cell;
-               } catch (BadElementException e) {
-               } catch (IOException e) {
-               }
-               return null;
-       }
-       
-       protected String appendLength(double length) {
-               final Unit defaultUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
-               return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(length)) + defaultUnit.toString();
-       }
-       
-       protected String appendMass(double mass) {
-               final Unit defaultUnit = UnitGroup.UNITS_MASS.getDefaultUnit();
-               return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(mass)) + defaultUnit.toString();
-       }
-       
-       protected String appendMaterial(Material material) {
-               return material.getName();
-       }
-       
-       protected String appendMaterialDensity(Material material) {
-               return " (" + material.getType().getUnitGroup().getDefaultUnit().toStringUnit(material.getDensity()) + ")";
-       }
-       
+public class PartsDetailVisitorStrategy {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
+    /**
+     * The number of columns in the table.
+     */
+    private static final int TABLE_COLUMNS = 7;
+
+    /**
+     * The parts detail is represented as an iText table.
+     */
+    PdfPTable grid;
+
+    /**
+     * The iText document.
+     */
+    protected Document document;
+
+    /**
+     * The direct iText writer.
+     */
+    protected PdfWriter writer;
+
+    /**
+     * The stages selected.
+     */
+    protected Set<Integer> stages;
+
+    /**
+     * State variable to track the level of hierarchy.
+     */
+    protected int level = 0;
+
+    private static final String LINES = "Lines: ";
+    private static final String MASS = "Mass: ";
+    private static final String LEN = "Len: ";
+    private static final String THICK = "Thick: ";
+    private static final String INNER = "in ";
+    private static final String DIAMETER = "Dia";
+    private static final String OUTER = "out";
+    private static final String WIDTH = "Width";
+    private static final String LENGTH = "Length";
+    private static final String SHROUD_LINES = "Shroud Lines";
+    private static final String AFT_DIAMETER = "Aft Dia: ";
+    private static final String FORE_DIAMETER = "Fore Dia: ";
+    private static final String PARTS_DETAIL = "Parts Detail";
+
+    /**
+     * Construct a strategy for visiting a parts hierarchy for the purposes of collecting details on those parts.
+     *
+     * @param doc              The iText document
+     * @param theWriter        The direct iText writer
+     * @param theStagesToVisit The stages to be visited by this strategy
+     */
+    public PartsDetailVisitorStrategy (Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
+        document = doc;
+        writer = theWriter;
+        stages = theStagesToVisit;
+        PrintUtilities.addText(doc, PrintUtilities.BIG_BOLD, PARTS_DETAIL);
+    }
+
+    /**
+     * Print the parts detail.
+     *
+     * @param root  the root component
+     */
+    public void writeToDocument (final RocketComponent root) {
+        goDeep(root.getChildren());
+    }
+
+    /**
+     * Recurse through the given rocket component.
+     *
+     * @param theRc an array of rocket components; all children will be visited recursively
+     */
+    protected void goDeep (final List<RocketComponent> theRc) {
+        level++;
+        for (RocketComponent rocketComponent : theRc) {
+            handle(rocketComponent);
+        }
+        level--;
+    }
+
+    /**
+     * Add a line to the detail report based upon the type of the component.
+     *
+     * @param component  the component to print the detail for
+     */
+    private void handle (RocketComponent component) {
+        //This ugly if-then-else construct is not object oriented.  Originally it was an elegant, and very OO savy, design
+        //using the Visitor pattern.  Unfortunately, it was misunderstood and was removed.
+        if (component instanceof Stage) {
+            try {
+                if (grid != null) {
+                    document.add(grid);
+                }
+                document.add(ITextHelper.createPhrase(component.getName()));
+                grid = new PdfPTable(TABLE_COLUMNS);
+                grid.setWidthPercentage(100);
+                grid.setHorizontalAlignment(Element.ALIGN_LEFT);
+            }
+            catch (DocumentException e) {
+            }
+
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof LaunchLug) {
+            LaunchLug ll = (LaunchLug) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+
+            grid.addCell(createMaterialCell(ll.getMaterial()));
+            grid.addCell(createOuterInnerDiaCell(ll));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+        }
+        else if (component instanceof NoseCone) {
+            NoseCone nc = (NoseCone) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(nc.getMaterial()));
+            grid.addCell(ITextHelper.createCell(nc.getType().getName(), PdfPCell.BOTTOM));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof Transition) {
+            Transition tran = (Transition) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(tran.getMaterial()));
+
+            Chunk fore = new Chunk(FORE_DIAMETER + toLength(tran.getForeRadius() * 2));
+            fore.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+            Chunk aft = new Chunk(AFT_DIAMETER + toLength(tran.getAftRadius() * 2));
+            aft.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+            final PdfPCell cell = ITextHelper.createCell();
+            cell.addElement(fore);
+            cell.addElement(aft);
+            grid.addCell(cell);
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof BodyTube) {
+            BodyTube bt = (BodyTube) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(bt.getMaterial()));
+            grid.addCell(createOuterInnerDiaCell(bt));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof FinSet) {
+            handleFins((FinSet) component);
+        }
+        else if (component instanceof BodyComponent) {
+            grid.addCell(component.getName());
+            grid.completeRow();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof ExternalComponent) {
+            ExternalComponent ext = (ExternalComponent) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+
+            grid.addCell(createMaterialCell(ext.getMaterial()));
+            grid.addCell(ITextHelper.createCell());
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof InnerTube) {
+            InnerTube it = (InnerTube) component;
+            grid.addCell(iconToImage(component));
+            final PdfPCell pCell = createNameCell(component.getName(), true);
+            grid.addCell(pCell);
+            grid.addCell(createMaterialCell(it.getMaterial()));
+            grid.addCell(createOuterInnerDiaCell(it));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof RadiusRingComponent) {
+            RadiusRingComponent rrc = (RadiusRingComponent) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(rrc.getMaterial()));
+            if (component instanceof Bulkhead) {
+                grid.addCell(createDiaCell(rrc.getOuterRadius()*2));
+            }
+            else {
+                grid.addCell(createOuterInnerDiaCell(rrc));
+            }
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof RingComponent) {
+            RingComponent ring = (RingComponent) component;
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(ring.getMaterial()));
+            grid.addCell(createOuterInnerDiaCell(ring));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof ShockCord) {
+            ShockCord ring = (ShockCord) component;
+            PdfPCell cell = ITextHelper.createCell();
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            cell.setPaddingBottom(12f);
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(ring.getMaterial()));
+            grid.addCell(cell);
+            grid.addCell(createLengthCell(ring.getCordLength()));
+            grid.addCell(createMassCell(component.getMass()));
+        }
+        else if (component instanceof Parachute) {
+            Parachute chute = (Parachute) component;
+            PdfPCell cell = ITextHelper.createCell();
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            cell.setPaddingBottom(12f);
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(chute.getMaterial()));
+            grid.addCell(createDiaCell(chute.getDiameter()));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+
+            grid.addCell(iconToImage(null));
+            grid.addCell(createNameCell(SHROUD_LINES, true));
+            grid.addCell(createMaterialCell(chute.getLineMaterial()));
+            grid.addCell(createLinesCell(chute.getLineCount()));
+            grid.addCell(createLengthCell(chute.getLineLength()));
+            grid.addCell(cell);
+        }
+        else if (component instanceof Streamer) {
+            Streamer ring = (Streamer) component;
+            PdfPCell cell = ITextHelper.createCell();
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            cell.setPaddingBottom(12f);
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(ring.getMaterial()));
+            grid.addCell(createStrip(ring));
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+        }
+        else if (component instanceof RecoveryDevice) {
+            RecoveryDevice device = (RecoveryDevice) component;
+            PdfPCell cell = ITextHelper.createCell();
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            cell.setPaddingBottom(12f);
+            grid.addCell(iconToImage(component));
+            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createMaterialCell(device.getMaterial()));
+            grid.addCell(cell);
+            grid.addCell(createLengthCell(component.getLength()));
+            grid.addCell(createMassCell(component.getMass()));
+        }
+        else if (component instanceof MassObject) {
+            PdfPCell cell = ITextHelper.createCell();
+            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            cell.setPaddingBottom(12f);
+
+            grid.addCell(iconToImage(component));
+            final PdfPCell nameCell = createNameCell(component.getName(), true);
+            nameCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+            nameCell.setPaddingBottom(12f);
+            grid.addCell(nameCell);
+            grid.addCell(cell);
+            grid.addCell(createDiaCell(((MassObject) component).getRadius() * 2));
+            grid.addCell(cell);
+            grid.addCell(createMassCell(component.getMass()));
+        }
+    }
+
+    /**
+     * Close the strategy by adding the last grid to the document.
+     */
+    public void close () {
+        try {
+            if (grid != null) {
+                document.add(grid);
+            }
+        }
+        catch (DocumentException e) {
+            log.error("Could not write last cell to document.", e);
+        }
+    }
+
+    /**
+     * Create a cell to document an outer 'diameter'.  This is used for components that have no inner diameter, such as
+     * a solid parachute or bulkhead.
+     *
+     * @param diameter  the diameter in default length units
+     *
+     * @return a formatted cell containing the diameter
+     */
+    private PdfPCell createDiaCell (final double diameter) {
+        PdfPCell result = new PdfPCell();
+        Phrase p = new Phrase();
+        p.setLeading(12f);
+        result.setVerticalAlignment(Element.ALIGN_TOP);
+        result.setBorder(Rectangle.BOTTOM);
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(DIAMETER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        c.append(OUTER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(" " + toLength(diameter));
+        p.add(c);
+        result.addElement(p);
+        return result;
+    }
+
+    /**
+     * Create a PDF cell for a streamer.
+     *
+     * @param component  a component that is a Coaxial
+     * @return  the PDF cell that has the streamer documented
+     */
+    private PdfPCell createStrip (final Streamer component) {
+        PdfPCell result = new PdfPCell();
+        Phrase p = new Phrase();
+        p.setLeading(12f);
+        result.setVerticalAlignment(Element.ALIGN_TOP);
+        result.setBorder(Rectangle.BOTTOM);
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(LENGTH);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(" " + toLength(component.getStripLength()));
+        p.add(c);
+        result.addElement(p);
+
+        Phrase pw = new Phrase();
+        pw.setLeading(14f);
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(WIDTH);
+        pw.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append("  " + toLength(component.getStripWidth()));
+        pw.add(c);
+        result.addElement(pw);
+
+        return result;
+    }
+
+    /**
+     * Create a PDF cell that documents both an outer and an inner diameter of a component.
+     *
+     * @param component  a component that is a Coaxial
+     * @return  the PDF cell that has the outer and inner diameters documented
+     */
+    private PdfPCell createOuterInnerDiaCell (final Coaxial component) {
+        PdfPCell result = new PdfPCell();
+        Phrase p = new Phrase();
+        p.setLeading(12f);
+        result.setVerticalAlignment(Element.ALIGN_TOP);
+        result.setBorder(Rectangle.BOTTOM);
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(DIAMETER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        c.append(OUTER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(" " + toLength(component.getOuterRadius() * 2));
+        p.add(c);
+        createInnerDiaCell(component, result);
+        result.addElement(p);
+        return result;
+    }
+
+    /**
+     * Add inner diameter data to a cell.
+     *
+     * @param component  a component that is a Coaxial
+     * @param cell       the PDF cell to add the inner diameter data to
+     */
+    private void createInnerDiaCell (final Coaxial component, PdfPCell cell) {
+        Phrase p = new Phrase();
+        p.setLeading(14f);
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(DIAMETER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        c.append(INNER);
+        p.add(c);
+
+        c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append("  " + toLength(component.getInnerRadius() * 2));
+        p.add(c);
+        cell.addElement(p);
+    }
+
+    /**
+     * Add PDF cells for a fin set.
+     *
+     * @param theFinSet  the fin set
+     */
+    private void handleFins (FinSet theFinSet) {
+
+        Image img = null;
+        java.awt.Image awtImage = new PrintableFinSet(theFinSet).createImage();
+
+        Collection<Coordinate> x = theFinSet.getComponentBounds();
+
+        try {
+            img = Image.getInstance(writer, awtImage, 0.25f);
+        }
+        catch (Exception e) {
+            log.error("Could not write image to document.", e);
+        }
+
+        grid.addCell(iconToImage(theFinSet));
+        grid.addCell(createNameCell(theFinSet.getName() + " (" + theFinSet.getFinCount() + ")", true));
+        grid.addCell(createMaterialCell(theFinSet.getMaterial()));
+        grid.addCell(ITextHelper.createCell(THICK + toLength(theFinSet.getThickness()), PdfPCell.BOTTOM));
+        final PdfPCell pCell = new PdfPCell();
+        pCell.setBorder(Rectangle.BOTTOM);
+        pCell.addElement(img);
+
+        grid.addCell(ITextHelper.createCell());
+        grid.addCell(createMassCell(theFinSet.getMass()));
+
+        List<RocketComponent> rc = theFinSet.getChildren();
+        goDeep(rc);
+    }
+
+    /**
+     * Create a length formatted cell.
+     *
+     * @param length  the length, in default length units
+     *
+     * @return a PdfPCell that is formatted with the length
+     */
+    protected PdfPCell createLengthCell (double length) {
+        return ITextHelper.createCell(LEN + toLength(length), PdfPCell.BOTTOM);
+    }
+
+    /**
+     * Create a mass formatted cell.
+     *
+     * @param mass  the mass, in default mass units
+     *
+     * @return a PdfPCell that is formatted with the mass
+     */
+    protected PdfPCell createMassCell (double mass) {
+        return ITextHelper.createCell(MASS + toMass(mass), PdfPCell.BOTTOM);
+    }
+
+    /**
+     * Create a (shroud) line count formatted cell.
+     *
+     * @param count  the number of shroud lines
+     *
+     * @return a PdfPCell that is formatted with the line count
+     */
+    protected PdfPCell createLinesCell (int count) {
+        return ITextHelper.createCell(LINES + count, PdfPCell.BOTTOM);
+    }
+
+    /**
+     * Create a cell formatted for a name (or any string for that matter).
+     *
+     * @param v  the string to format into a PDF cell
+     * @param withIndent  if true, then an indention is made scaled to the level of the part in the parent hierarchy
+     *
+     * @return a PdfPCell that is formatted with the string <code>v</code>
+     */
+    protected PdfPCell createNameCell (String v, boolean withIndent) {
+        PdfPCell result = new PdfPCell();
+        result.setBorder(Rectangle.BOTTOM);
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        if (withIndent) {
+            for (int x = 0; x < (level - 2) * 10; x++) {
+                c.append(" ");
+            }
+        }
+        c.append(v);
+        result.setColspan(2);
+        result.addElement(c);
+        return result;
+    }
+
+    /**
+     * Create a cell that describes a material.
+     *
+     * @param material  the material
+     *
+     * @return a PdfPCell that is formatted with a description of the material
+     */
+    protected PdfPCell createMaterialCell (Material material) {
+        PdfPCell cell = ITextHelper.createCell();
+        cell.setLeading(13f, 0);
+
+        Chunk c = new Chunk();
+        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.append(toMaterialName(material));
+        cell.addElement(c);
+        Chunk density = new Chunk();
+        density.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        density.append(toMaterialDensity(material));
+        cell.addElement(density);
+        return cell;
+    }
+
+    /**
+     * Get the icon of the particular type of rocket component and conver it to an image in a PDF cell.
+     *
+     * @param visitable  the rocket component to create a cell with it's image
+     *
+     * @return a PdfPCell that is just an image that can be put into a PDF
+     */
+    protected PdfPCell iconToImage (final RocketComponent visitable) {
+        if (visitable != null) {
+            final ImageIcon icon = (ImageIcon) ComponentIcons.getLargeIcon(visitable.getClass());
+            try {
+                if (icon != null) {
+                    Image im = Image.getInstance(icon.getImage(), null);
+                    if (im != null) {
+                        im.scaleToFit(icon.getIconWidth() * 0.6f, icon.getIconHeight() * 0.6f);
+                        PdfPCell cell = new PdfPCell(im);
+                        cell.setFixedHeight(icon.getIconHeight() * 0.6f);
+                        cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
+                        cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+                        cell.setBorder(PdfPCell.NO_BORDER);
+                        return cell;
+                    }
+                }
+            }
+            catch (Exception e) {
+            }
+        }
+        PdfPCell cell = new PdfPCell();
+        cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
+        cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
+        cell.setBorder(PdfPCell.NO_BORDER);
+        return cell;
+    }
+
+    /**
+     * Format the length as a displayable string.
+     *
+     * @param length the length (assumed to be in default length units)
+     *
+     * @return a string representation of the length with unit abbreviation
+     */
+    protected String toLength (double length) {
+        final Unit defaultUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
+        return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(length)) + defaultUnit.toString();
+    }
+
+    /**
+     * Format the mass as a displayable string.
+     *
+     * @param mass  the mass (assumed to be in default mass units)
+     *
+     * @return a string representation of the mass with mass abbreviation
+     */
+    protected String toMass (double mass) {
+        final Unit defaultUnit = UnitGroup.UNITS_MASS.getDefaultUnit();
+        return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(mass)) + defaultUnit.toString();
+    }
+
+    /**
+     * Get a displayable string of the material's name.
+     *
+     * @param material  the material to output
+     *
+     * @return the material name
+     */
+    protected String toMaterialName (Material material) {
+        return material.getName();
+    }
+
+    /**
+     * Format the material density as a displayable string.
+     *
+     * @param material  the material to output
+     *
+     * @return a string representation of the material density
+     */
+    protected String toMaterialDensity (Material material) {
+        return " (" + material.getType().getUnitGroup().getDefaultUnit().toStringUnit(material.getDensity()) + ")";
+    }
+
 }
index 699a4263fd8a66cad3183cde5434925aad63865b..e8ecc0baf7238261fb296f5b5d31871fc00eedfe 100644 (file)
  */
 package net.sf.openrocket.gui.print.visitor;
 
+import com.itextpdf.text.Document;
+import com.itextpdf.text.pdf.PdfWriter;
+import net.sf.openrocket.rocketcomponent.*;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.Coaxial;
-import net.sf.openrocket.rocketcomponent.ComponentVisitor;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
-
-import com.itextpdf.text.Document;
-import com.itextpdf.text.pdf.PdfWriter;
-
 /**
  * A visitor strategy for creating documentation about a parts list.
  */
-public class PartsListVisitorStrategy extends BaseVisitorStrategy {
-       
-       /**
-        * Accumulator for parts data.
-        */
-       private Map<PartsAccumulator, PartsAccumulator> crap = new HashMap<PartsAccumulator, PartsAccumulator>();
-       
-       /**
-        * Construct a strategy for visiting a parts hierarchy for the purposes of collecting details on those parts.
-        *
-        * @param doc              The iText document
-        * @param theWriter        The direct iText writer
-        * @param theStagesToVisit The stages to be visited by this strategy
-        */
-       public PartsListVisitorStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
-               super(doc, theWriter, theStagesToVisit);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RingComponent visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final InnerTube visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final LaunchLug visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Transition visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RadiusRingComponent visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final NoseCone visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyTube visitable) {
-               final PartsAccumulator key = new PartsAccumulator(visitable);
-               PartsAccumulator pa = crap.get(key);
-               if (pa == null) {
-                       pa = key;
-                       crap.put(pa, pa);
-               }
-               pa.increment();
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final TrapezoidFinSet visitable) {
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final EllipticalFinSet visitable) {
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final FreeformFinSet visitable) {
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void setParent(final ComponentVisitor theParent) {
-               parent = theParent;
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void close() {
-               for (PartsAccumulator partsAccumulator : crap.keySet()) {
-                       System.err.println(partsAccumulator.component.getComponentName() + " " + partsAccumulator.quantity);
-               }
-       }
-       
+public class PartsListVisitorStrategy {
+
+    /**
+     * Accumulator for parts data.
+     */
+    private Map<PartsAccumulator, PartsAccumulator> crap = new HashMap<PartsAccumulator, PartsAccumulator>();
+
+    /**
+     * The iText document.
+     */
+    protected Document document;
+
+    /**
+     * The direct iText writer.
+     */
+    protected PdfWriter writer;
+
+    /**
+     * The stages selected.
+     */
+    protected Set<Integer> stages;
+
+
+    /**
+     * Construct a strategy for visiting a parts hierarchy for the purposes of collecting details on those parts.
+     *
+     * @param doc              The iText document
+     * @param theWriter        The direct iText writer
+     * @param theStagesToVisit The stages to be visited by this strategy
+     */
+    public PartsListVisitorStrategy (Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
+        document = doc;
+        writer = theWriter;
+        stages = theStagesToVisit;
+    }
+
+
+    /**
+     * Print the parts detail.
+     *
+     * @param root the root component
+     */
+    public void doVisit (final RocketComponent root) {
+        goDeep(root.getChildren());
+    }
+
+    /**
+     * Recurse through the given rocket component.
+     *
+     * @param theRc an array of rocket components; all children will be visited recursively
+     */
+    protected void goDeep (final List<RocketComponent> theRc) {
+        for (RocketComponent rocketComponent : theRc) {
+            doIt(rocketComponent);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    private void doIt (final RocketComponent component) {
+        if (component instanceof InnerTube) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof LaunchLug) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+        }
+
+        else if (component instanceof NoseCone) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof Transition) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof RadiusRingComponent) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof RingComponent) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof BodyTube) {
+            final PartsAccumulator key = new PartsAccumulator(component);
+            PartsAccumulator pa = crap.get(key);
+            if (pa == null) {
+                pa = key;
+                crap.put(pa, pa);
+            }
+            pa.increment();
+            List<RocketComponent> rc = component.getChildren();
+            goDeep(rc);
+        }
+        else if (component instanceof TrapezoidFinSet) {
+        }
+        else if (component instanceof EllipticalFinSet) {
+        }
+        else if (component instanceof FreeformFinSet) {
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close () {
+        for (PartsAccumulator partsAccumulator : crap.keySet()) {
+            System.err.println(partsAccumulator.component.getComponentName() + " " + partsAccumulator.quantity);
+        }
+    }
+
 }
 
 class PartsAccumulator {
-       
-       int quantity = 0;
-       
-       RocketComponent component;
-       
-       PartsAccumulator(RocketComponent theComponent) {
-               component = theComponent;
-       }
-       
-       void increment() {
-               quantity++;
-       }
-       
-       int quantity() {
-               return quantity;
-       }
-       
-       @Override
-       public boolean equals(final Object o1) {
-               if (this == o1) {
-                       return true;
-               }
-               
-               RocketComponent that;
-               if (o1 instanceof net.sf.openrocket.gui.print.visitor.PartsAccumulator) {
-                       that = ((net.sf.openrocket.gui.print.visitor.PartsAccumulator) o1).component;
-               } else if (o1 instanceof RocketComponent) {
-                       that = (RocketComponent) o1;
-               } else {
-                       return false;
-               }
-               
-               if (this.component.getClass().equals(that.getClass())) {
-                       //If 
-                       if (that.getLength() == this.component.getLength()) {
-                               if (that.getMass() == this.component.getMass()) {
-                                       return true;
-                               }
-                       }
-                       if (this.component instanceof Coaxial &&
-                                       that instanceof Coaxial) {
-                               Coaxial cThis = (Coaxial) this.component;
-                               Coaxial cThat = (Coaxial) that;
-                               if (cThis.getInnerRadius() == cThat.getInnerRadius() &&
-                                               cThis.getOuterRadius() == cThat.getOuterRadius()) {
-                                       return true;
-                               }
-                       }
-                       return false;
-               }
-               return false;
-       }
-       
-       @Override
-       public int hashCode() {
-               return component.getComponentName().hashCode();
-       }
+
+    int quantity = 0;
+
+    RocketComponent component;
+
+    PartsAccumulator (RocketComponent theComponent) {
+        component = theComponent;
+    }
+
+    void increment () {
+        quantity++;
+    }
+
+    int quantity () {
+        return quantity;
+    }
+
+    @Override
+    public boolean equals (final Object o1) {
+        if (this == o1) {
+            return true;
+        }
+
+        RocketComponent that;
+        if (o1 instanceof net.sf.openrocket.gui.print.visitor.PartsAccumulator) {
+            that = ((net.sf.openrocket.gui.print.visitor.PartsAccumulator) o1).component;
+        }
+        else if (o1 instanceof RocketComponent) {
+            that = (RocketComponent) o1;
+        }
+        else {
+            return false;
+        }
+
+        if (this.component.getClass().equals(that.getClass())) {
+            //If
+            if (that.getLength() == this.component.getLength()) {
+                if (that.getMass() == this.component.getMass()) {
+                    return true;
+                }
+            }
+            if (this.component instanceof Coaxial &&
+                that instanceof Coaxial) {
+                Coaxial cThis = (Coaxial) this.component;
+                Coaxial cThat = (Coaxial) that;
+                if (cThis.getInnerRadius() == cThat.getInnerRadius() &&
+                    cThis.getOuterRadius() == cThat.getOuterRadius()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode () {
+        return component.getComponentName().hashCode();
+    }
 }
\ No newline at end of file
diff --git a/src/net/sf/openrocket/gui/print/visitor/StageVisitorStrategy.java b/src/net/sf/openrocket/gui/print/visitor/StageVisitorStrategy.java
deleted file mode 100644 (file)
index 00931b1..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * StageVisitor.java
- */
-package net.sf.openrocket.gui.print.visitor;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import net.sf.openrocket.rocketcomponent.BodyComponent;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.ComponentVisitor;
-import net.sf.openrocket.rocketcomponent.ComponentVisitorStrategy;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.MassObject;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
-
-/**
- * This visitor strategy accumulates Stage references in a Rocket hierarchy.
- */
-public class StageVisitorStrategy implements ComponentVisitorStrategy {
-       
-       /**
-        * The collection of stages, accumulated during a visitation.
-        */
-       private List<Double> stageComponents = new ArrayList<Double>();
-       
-       private Double mass = 0d;
-       
-       /**
-        * The owning visitor.
-        */
-       protected ComponentVisitor parent;
-       
-       /**
-        * Constructor.
-        */
-       public StageVisitorStrategy() {
-       }
-       
-       /**
-        * Override the method that determines if the visiting should be going deep.
-        *
-        * @param stageNumber a stage number
-        *
-        * @return true, always
-        */
-       public boolean shouldVisitStage(int stageNumber) {
-               return true;
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void setParent(final ComponentVisitor theParent) {
-               parent = theParent;
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Rocket visitable) {
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Stage visitable) {
-               
-               if (mass > 0d) {
-                       stageComponents.add(mass);
-               }
-               mass = 0d;
-               List<RocketComponent> rc = visitable.getChildren();
-               goDeep(rc);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RocketComponent visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * Recurse through the given rocket component.
-        *
-        * @param root the root component; all children will be visited recursively
-        */
-       protected void goDeep(final RocketComponent root) {
-               List<RocketComponent> rc = root.getChildren();
-               goDeep(rc);
-       }
-       
-       
-       /**
-        * Recurse through the given rocket component.
-        *
-        * @param theRc an array of rocket components; all children will be visited recursively
-        */
-       protected void goDeep(final List<RocketComponent> theRc) {
-               for (RocketComponent rocketComponent : theRc) {
-                       rocketComponent.accept(parent);
-               }
-       }
-       
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final ExternalComponent visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyComponent visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RingComponent visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final InnerTube visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final LaunchLug visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final Transition visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final RadiusRingComponent visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final MassObject visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final NoseCone visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final BodyTube visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final TrapezoidFinSet visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final EllipticalFinSet visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       public void visit(final FreeformFinSet visitable) {
-               mass += visitable.getMass();
-               goDeep(visitable);
-       }
-       
-       /**
-        * Get the list of stages, sort from Stage 1 .. Stage N.
-        *
-        * @return a sorted list of stages
-        */
-       public List<Double> getStages() {
-               return stageComponents;
-       }
-       
-       /**
-        * Close by setting the last stage.
-        */
-       @Override
-       public void close() {
-               if (mass > 0d) {
-                       stageComponents.add(mass);
-               }
-       }
-       
-}
index 97a12406f4e764d00cce6abf580b796f14d56b0e..2bc112fbb11624924fcd699307157bde8764c3b1 100644 (file)
@@ -3,17 +3,17 @@ package net.sf.openrocket.rocketcomponent;
 
 /**
  * Class to represent a body object.  The object can be described as a function of
- * the cylindrical coordinates x and angle theta as  r = f(x,theta).  The component 
+ * the cylindrical coordinates x and angle theta as  r = f(x,theta).  The component
  * need not be symmetrical in any way (e.g. square tube, slanted cone etc).
- * 
+ *
  * It defines the methods getRadius(x,theta) and getInnerRadius(x,theta), as well
  * as get/setLength().
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
 public abstract class BodyComponent extends ExternalComponent {
-       
+
        /**
         * Default constructor.  Sets the relative position to POSITION_RELATIVE_AFTER,
         * i.e. body components come after one another.
@@ -21,32 +21,32 @@ public abstract class BodyComponent extends ExternalComponent {
        public BodyComponent() {
                super(RocketComponent.Position.AFTER);
        }
-       
-       
+
+
        /**
         * Get the outer radius of the component at cylindrical coordinate (x,theta).
-        * 
+        *
         * Note that the return value may be negative for a slanted object.
-        * 
+        *
         * @param x  Distance in x direction
         * @param theta  Angle about the x-axis
         * @return  Distance to the outer edge of the object
         */
        public abstract double getRadius(double x, double theta);
-       
-       
+
+
        /**
         * Get the inner radius of the component at cylindrical coordinate (x,theta).
-        * 
+        *
         * Note that the return value may be negative for a slanted object.
-        * 
+        *
         * @param x  Distance in x direction
         * @param theta  Angle about the x-axis
         * @return  Distance to the inner edge of the object
         */
        public abstract double getInnerRadius(double x, double theta);
-       
-       
+
+
 
        /**
         * Sets the length of the body component.
@@ -57,21 +57,10 @@ public abstract class BodyComponent extends ExternalComponent {
                this.length = Math.max(length, 0);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        @Override
        public boolean allowsChildren() {
                return true;
        }
-    
-    /**
-     * Accept a visitor to this BodyComponent in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this BodyComponent
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-    
-    
+
 }
index f45f352653f3cdc8d871d5f1dfbd1dd339354a5f..adf0aa190134682296f72818f1dbf2aac297b30d 100644 (file)
@@ -11,25 +11,25 @@ import java.util.HashMap;
 
 /**
  * Rocket body tube component.  Has only two parameters, a radius and length.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
 public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial {
-       
+
        private double radius = 0;
        private boolean autoRadius = false; // Radius chosen automatically based on parent component
-       
+
        // When changing the inner radius, thickness is modified
-       
+
        private boolean motorMount = false;
        private HashMap<String, Double> ejectionDelays = new HashMap<String, Double>();
        private HashMap<String, Motor> motors = new HashMap<String, Motor>();
        private IgnitionEvent ignitionEvent = IgnitionEvent.AUTOMATIC;
        private double ignitionDelay = 0;
        private double overhang = 0;
-       
-       
+
+
 
        public BodyTube() {
                super();
@@ -37,31 +37,31 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                this.radius = DEFAULT_RADIUS;
                this.autoRadius = true;
        }
-       
+
        public BodyTube(double length, double radius) {
                super();
                this.radius = Math.max(radius, 0);
                this.length = Math.max(length, 0);
        }
-       
-       
+
+
        public BodyTube(double length, double radius, boolean filled) {
                this(length, radius);
                this.filled = filled;
        }
-       
+
        public BodyTube(double length, double radius, double thickness) {
                this(length, radius);
                this.filled = false;
                this.thickness = thickness;
        }
-       
-       
+
+
        /************  Get/set component parameter methods ************/
-       
+
        /**
         * Return the outer radius of the body tube.
-     * 
+     *
      * @return  the outside radius of the tube
         */
     @Override
@@ -85,29 +85,29 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                }
                return radius;
        }
-       
-       
+
+
        /**
         * Set the outer radius of the body tube.  If the radius is less than the wall thickness,
         * the wall thickness is decreased accordingly of the value of the radius.
         * This method sets the automatic radius off.
-     * 
+     *
      * @param radius  the outside radius in standard units
         */
     @Override
        public void setOuterRadius (double radius) {
                if ((this.radius == radius) && (autoRadius == false))
                        return;
-               
+
                this.autoRadius = false;
                this.radius = Math.max(radius, 0);
-               
+
                if (this.thickness > this.radius)
                        this.thickness = this.radius;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        /**
         * Returns whether the radius is selected automatically or not.
         * Returns false also in case automatic radius selection is not possible.
@@ -115,19 +115,19 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        public boolean isRadiusAutomatic() {
                return autoRadius;
        }
-       
+
        /**
-        * Sets whether the radius is selected automatically or not.  
+        * Sets whether the radius is selected automatically or not.
         */
        public void setRadiusAutomatic(boolean auto) {
                if (autoRadius == auto)
                        return;
-               
+
                autoRadius = auto;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getAftRadius() {  return getOuterRadius(); }
        @Override
@@ -136,13 +136,13 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        public boolean isAftRadiusAutomatic() {
                return isRadiusAutomatic();
        }
-       
+
        @Override
        public boolean isForeRadiusAutomatic() {
                return isRadiusAutomatic();
        }
-       
-       
+
+
 
        @Override
        protected double getFrontAutoRadius() {
@@ -157,7 +157,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                }
                return getOuterRadius();
        }
-       
+
        @Override
        protected double getRearAutoRadius() {
                if (isRadiusAutomatic()) {
@@ -171,27 +171,27 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                }
                return getOuterRadius();
        }
-       
-       
 
 
-       
-       
-       
-       
-    @Override  
+
+
+
+
+
+
+    @Override
        public double getInnerRadius() {
                if (filled)
                        return 0;
                return Math.max(getOuterRadius()-thickness, 0);
        }
-       
+
     @Override
        public void setInnerRadius(double r) {
                setThickness(getOuterRadius()-r);
        }
-       
-       
+
+
 
 
        /**
@@ -202,19 +202,9 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                return "Body tube";
        }
 
-    /**
-     * Accept a visitor to this BodyTube in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this BodyTube
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-
 
        /************ Component calculations ***********/
-       
+
        // From SymmetricComponent
        /**
         * Returns the outer radius at the position x.  This returns the same value as getOuterRadius().
@@ -223,7 +213,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        public double getRadius(double x) {
                return getOuterRadius();
        }
-       
+
        /**
         * Returns the inner radius at the position x.  If the tube is filled, returns always zero.
         */
@@ -234,8 +224,8 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                else
                        return Math.max(getOuterRadius()-thickness,0);
        }
-       
-       
+
+
        /**
         * Returns the body tube's center of gravity.
         */
@@ -243,7 +233,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        public Coordinate getComponentCG() {
                return new Coordinate(length / 2, 0, 0, getComponentMass());
        }
-       
+
        /**
         * Returns the body tube's volume.
         */
@@ -255,22 +245,22 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                else
                        return getFilledVolume(r, length) - getFilledVolume(getInnerRadius(0), length);
        }
-       
-       
+
+
        @Override
        public double getLongitudinalUnitInertia() {
                // 1/12 * (3 * (r1^2 + r2^2) + h^2)
                return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getOuterRadius()) +
                                MathUtil.pow2(getLength())) / 12;
        }
-       
+
        @Override
        public double getRotationalUnitInertia() {
                // 1/2 * (r1^2 + r2^2)
                return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius()))/2;
        }
-       
-       
+
+
 
 
        /**
@@ -279,12 +269,12 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        private static double getFilledVolume(double r, double l) {
                return Math.PI * r * r * l;
        }
-       
-       
+
+
        /**
         * Adds bounding coordinates to the given set.  The body tube will fit within the
         * convex hull of the points.
-        * 
+        *
         * Currently the points are simply a rectangular box around the body tube.
         */
        @Override
@@ -295,13 +285,13 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                addBound(bounds, length, r);
                return bounds;
        }
-       
-       
+
+
 
        /**
         * Check whether the given type can be added to this component.  BodyTubes allow any
         * InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
-        * 
+        *
         * @param type  The RocketComponent class type to add.
         * @return      Whether such a component can be added.
         */
@@ -314,14 +304,14 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                        return true;
                return false;
        }
-       
+
        ////////////////  Motor mount  /////////////////
-       
+
        @Override
        public boolean isMotorMount() {
                return motorMount;
        }
-       
+
        @Override
        public void setMotorMount(boolean mount) {
                if (motorMount == mount)
@@ -329,22 +319,22 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                motorMount = mount;
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Override
        public Motor getMotor(String id) {
                if (id == null)
                        return null;
-               
+
                // Check whether the id is valid for the current rocket
                RocketComponent root = this.getRoot();
                if (!(root instanceof Rocket))
                        return null;
                if (!((Rocket) root).isMotorConfigurationID(id))
                        return null;
-               
+
                return motors.get(id);
        }
-       
+
        @Override
        public void setMotor(String id, Motor motor) {
                if (id == null) {
@@ -359,7 +349,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                motors.put(id, motor);
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Override
        public double getMotorDelay(String id) {
                Double delay = ejectionDelays.get(id);
@@ -367,28 +357,28 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                        return Motor.PLUGGED;
                return delay;
        }
-       
+
        @Override
        public void setMotorDelay(String id, double delay) {
                ejectionDelays.put(id, delay);
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Override
        public int getMotorCount() {
                return 1;
        }
-       
+
        @Override
        public double getMotorMountDiameter() {
                return getInnerRadius() * 2;
        }
-       
+
        @Override
        public IgnitionEvent getIgnitionEvent() {
                return ignitionEvent;
        }
-       
+
        @Override
        public void setIgnitionEvent(IgnitionEvent event) {
                if (ignitionEvent == event)
@@ -396,13 +386,13 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                ignitionEvent = event;
                fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getIgnitionDelay() {
                return ignitionDelay;
        }
-       
+
        @Override
        public void setIgnitionDelay(double delay) {
                if (MathUtil.equals(delay, ignitionDelay))
@@ -410,13 +400,13 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                ignitionDelay = delay;
                fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getMotorOverhang() {
                return overhang;
        }
-       
+
        @Override
        public void setMotorOverhang(double overhang) {
                if (MathUtil.equals(this.overhang, overhang))
@@ -424,25 +414,25 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
                this.overhang = overhang;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        @Override
        public Coordinate getMotorPosition(String id) {
                Motor motor = motors.get(id);
                if (motor == null) {
                        throw new IllegalArgumentException("No motor with id " + id + " defined.");
                }
-               
+
                return new Coordinate(this.getLength() - motor.getLength() + this.getMotorOverhang());
        }
-       
-       
+
+
 
 
        /*
         * (non-Javadoc)
         * Copy the motor and ejection delay HashMaps.
-        * 
+        *
         * @see rocketcomponent.RocketComponent#copy()
         */
        @SuppressWarnings("unchecked")
index 3abcd44a213c0c28a648202c3f3875010b88cf99..21b73e2af1daa65d70611b0f1400e7bf938153d5 100644 (file)
@@ -4,14 +4,14 @@ import net.sf.openrocket.util.Coordinate;
 
 
 public class CenteringRing extends RadiusRingComponent {
-       
+
        public CenteringRing() {
                setOuterRadiusAutomatic(true);
                setInnerRadiusAutomatic(true);
                setLength(0.002);
        }
-       
-       
+
+
        @Override
        public double getInnerRadius() {
                // Implement sibling inner radius automation
@@ -26,55 +26,45 @@ public class CenteringRing extends RadiusRingComponent {
                                         */
                                        if (!(sibling instanceof InnerTube)) // Excludes itself
                                                continue;
-                                       
+
                                        double pos1 = this.toRelative(Coordinate.NUL, sibling)[0].x;
                                        double pos2 = this.toRelative(new Coordinate(getLength()), sibling)[0].x;
                                        if (pos2 < 0 || pos1 > sibling.getLength())
                                                continue;
-                                       
+
                                        innerRadius = Math.max(innerRadius, ((InnerTube) sibling).getOuterRadius());
                                }
                                innerRadius = Math.min(innerRadius, getOuterRadius());
                        }
                }
-               
+
                return super.getInnerRadius();
        }
-       
-       
+
+
        @Override
        public void setOuterRadiusAutomatic(boolean auto) {
                super.setOuterRadiusAutomatic(auto);
        }
-       
+
        @Override
        public void setInnerRadiusAutomatic(boolean auto) {
                super.setInnerRadiusAutomatic(auto);
        }
-       
+
        @Override
        public String getComponentName() {
                return "Centering ring";
        }
-       
+
        @Override
        public boolean allowsChildren() {
                return false;
        }
-       
+
        @Override
        public boolean isCompatible(Class<? extends RocketComponent> type) {
                return false;
        }
-    
-    /**
-     * Accept a visitor to this CenteringRing in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this CenteringRing
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
 
 }
diff --git a/src/net/sf/openrocket/rocketcomponent/ComponentVisitor.java b/src/net/sf/openrocket/rocketcomponent/ComponentVisitor.java
deleted file mode 100644 (file)
index 5a69f75..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * ComponentVisitor.java
- */
-package net.sf.openrocket.rocketcomponent;
-
-/**
- * This class implements a Visitor pattern to visit any/all components of a Rocket.
- */
-public class ComponentVisitor implements Visitor<ComponentVisitor, RocketComponent> {
-
-    /**
-     * The delegate.
-     */
-    private ComponentVisitorStrategy strategy;
-
-    /**
-     * Constructor.
-     *
-     * @param aStrategy the object to delegate the visiting to
-     */
-    public ComponentVisitor (ComponentVisitorStrategy aStrategy) {
-        strategy = aStrategy;
-        strategy.setParent(this);
-    }
-
-    /**
-     * Visit a Rocket object.
-     *
-     * @param visitable the Rocket to visit
-     */
-    public void visit (final Rocket visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a RocketComponent object.  This is used to catch any RocketComponent subclass not explicity defined by a
-     * visit method in this strategy.
-     *
-     * @param visitable the RocketComponent to visit
-     */
-    public void visit (final RocketComponent visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a Stage object.
-     *
-     * @param visitable the Stage to visit
-     */
-    public void visit (final Stage visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit an ExternalComponent object.
-     *
-     * @param visitable the ExternalComponent to visit
-     */
-    public void visit (final ExternalComponent visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a BodyComponent object.
-     *
-     * @param visitable the BodyComponent to visit
-     */
-    public void visit (final BodyComponent visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a RingComponent object.
-     *
-     * @param visitable the RingComponent to visit
-     */
-    public void visit (final RingComponent visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit an InnerTube object.
-     *
-     * @param visitable the InnerTube to visit
-     */
-    public void visit (final InnerTube visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a LaunchLug object.
-     *
-     * @param visitable the LaunchLug to visit
-     */
-    public void visit (final LaunchLug visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a Transition object.
-     *
-     * @param visitable the Transition to visit
-     */
-    public void visit (final Transition visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a RadiusRingComponent object.
-     *
-     * @param visitable the RadiusRingComponent to visit
-     */
-    public void visit (final RadiusRingComponent visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a MassObject object.
-     *
-     * @param visitable the MassObject to visit
-     */
-    public void visit (final MassObject visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a NoseCone object.
-     *
-     * @param visitable the NoseCone to visit
-     */
-    public void visit (final NoseCone visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a BodyTube object.
-     *
-     * @param visitable the BodyTube to visit
-     */
-    public void visit (final BodyTube visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a Rocket object.
-     *
-     * @param visitable the Rocket to visit
-     */
-    public void visit (final TrapezoidFinSet visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a Rocket object.
-     *
-     * @param visitable the Rocket to visit
-     */
-    public void visit (final EllipticalFinSet visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Visit a FreeformFinSet object.
-     *
-     * @param visitable the FreeformFinSet to visit
-     */
-    public void visit (final FreeformFinSet visitable) {
-        strategy.visit(visitable);
-    }
-
-    /**
-     * Perform any cleanup or finishing operations.
-     */
-    public void close () {
-        strategy.close();
-    }
-
-}
diff --git a/src/net/sf/openrocket/rocketcomponent/ComponentVisitorStrategy.java b/src/net/sf/openrocket/rocketcomponent/ComponentVisitorStrategy.java
deleted file mode 100644 (file)
index a4cc334..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ComponentVisitorStrategy.java
- */
-package net.sf.openrocket.rocketcomponent;
-
-/**
- * This interface defines the methods used in a Rocket component visitor.  By using a strategy, we can reuse one visitor
- * definition and just instrument it with different strategies.
- */
-public interface ComponentVisitorStrategy {
-
-    /**
-     * Visit a Rocket object.
-     *
-     * @param visitable the Rocket to visit
-     */
-    void visit (final Rocket visitable);
-
-    /**
-     * Visit a RocketComponent object.  This is used to catch any RocketComponent subclass not explicity defined by a
-     * visit method in this strategy.
-     *
-     * @param visitable the RocketComponent to visit
-     */
-    void visit (final RocketComponent visitable);
-
-    /**
-     * Visit a Stage object.
-     *
-     * @param visitable the Stage to visit
-     */
-    void visit (final Stage visitable);
-
-    /**
-     * Visit an ExternalComponent object.
-     *
-     * @param visitable the ExternalComponent to visit
-     */
-    void visit (final ExternalComponent visitable);
-
-    /**
-     * Visit a BodyComponent object.
-     *
-     * @param visitable the BodyComponent to visit
-     */
-    void visit (final BodyComponent visitable);
-
-    /**
-     * Visit a RingComponent object.
-     *
-     * @param visitable the RingComponent to visit
-     */
-    void visit (final RingComponent visitable);
-
-    /**
-     * Visit an InnerTube object.
-     *
-     * @param visitable the InnerTube to visit
-     */
-    void visit (final InnerTube visitable);
-
-    /**
-     * Visit a LaunchLug object.
-     *
-     * @param visitable the LaunchLug to visit
-     */
-    void visit (final LaunchLug visitable);
-
-    /**
-     * Visit a Transition object.
-     *
-     * @param visitable the Transition to visit
-     */
-    void visit (final Transition visitable);
-
-    /**
-     * Visit a RadiusRingComponent object.
-     *
-     * @param visitable the RadiusRingComponent to visit
-     */
-    void visit (final RadiusRingComponent visitable);
-
-    /**
-     * Visit a MassComponent object.
-     *
-     * @param visitable the MassComponent to visit
-     */
-    void visit (final MassObject visitable);
-
-    /**
-     * Visit a NoseCone object.
-     *
-     * @param visitable the NoseCone to visit
-     */
-    void visit (final NoseCone visitable);
-
-    /**
-     * Visit a BodyTube object.
-     *
-     * @param visitable the BodyTube to visit
-     */
-    void visit (final BodyTube visitable);
-
-    /**
-     * Visit a TrapezoidFinSet object.
-     *
-     * @param visitable the TrapezoidFinSet to visit
-     */
-    void visit (final TrapezoidFinSet visitable);
-
-    /**
-     * Visit an EllipticalFinSet object.
-     *
-     * @param visitable the EllipticalFinSet to visit
-     */
-    void visit (final EllipticalFinSet visitable);
-
-    /**
-     * Visit a FreeformFinSet object.
-     *
-     * @param visitable the FreeformFinSet to visit
-     */
-    void visit (final FreeformFinSet visitable);
-
-    /**
-     * Set the visitor that is using this strategy.
-     *
-     * @param parent the visitor
-     */
-    void setParent (ComponentVisitor parent);
-
-    /**
-     * Perform any cleanup or finishing operations.
-     */
-    void close ();
-}
index 22d49bea65f2850b38d68d52953c9218ec17afd3..aaaf92845ccb033545159d118f72194cb9e33787 100644 (file)
@@ -5,7 +5,7 @@ import net.sf.openrocket.util.MathUtil;
 
 public class EllipticalFinSet extends FinSet {
        public static final int POINTS = 21;
-       
+
        private static final double[] POINT_X = new double[POINTS];
        private static final double[] POINT_Y = new double[POINTS];
        static {
@@ -19,15 +19,15 @@ public class EllipticalFinSet extends FinSet {
                POINT_X[POINTS-1] = 1;
                POINT_Y[POINTS-1] = 0;
        }
-       
-       
+
+
        private double height = 0.05;
-       
+
        public EllipticalFinSet() {
                this.length = 0.05;
        }
 
-       
+
        @Override
        public Coordinate[] getFinPoints() {
                Coordinate[] points = new Coordinate[POINTS];
@@ -46,20 +46,20 @@ public class EllipticalFinSet extends FinSet {
        public String getComponentName() {
                return "Elliptical fin set";
        }
-       
-       
+
+
        public double getHeight() {
                return height;
        }
-       
+
        public void setHeight(double height) {
                if (MathUtil.equals(this.height, height))
                        return;
                this.height = height;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        public void setLength(double length) {
                if (MathUtil.equals(this.length, length))
                        return;
@@ -67,15 +67,5 @@ public class EllipticalFinSet extends FinSet {
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
 
-    
-    /**
-     * Accept a visitor to this EllipticalFinSet in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this EllipticalFinSet
-     */
-    @Override
-    public void accept(ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-    
+
 }
index 6fa4a4c2df903893b898e4b4fc5b26090924be31..a7fdbcecb310a6adf5d72399e5399845f09ee466 100644 (file)
@@ -1,55 +1,55 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.util.List;
-
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.Prefs;
 
+import java.util.List;
+
 /**
  * Class of components with well-defined physical appearance and which have an effect on
- * aerodynamic simulation.  They have material defined for them, and the mass of the component 
+ * aerodynamic simulation.  They have material defined for them, and the mass of the component
  * is calculated using the component's volume.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
 public abstract class ExternalComponent extends RocketComponent {
-       
+
        public enum Finish {
                ROUGH("Rough", 500e-6),
                UNFINISHED("Unfinished", 150e-6),
                NORMAL("Regular paint", 60e-6),
                SMOOTH("Smooth paint", 20e-6),
                POLISHED("Polished", 2e-6);
-               
+
                private final String name;
                private final double roughnessSize;
-               
+
                Finish(String name, double roughness) {
                        this.name = name;
                        this.roughnessSize = roughness;
                }
-               
+
                public double getRoughnessSize() {
                        return roughnessSize;
                }
-               
+
                @Override
                public String toString() {
                        return name + " (" + UnitGroup.UNITS_ROUGHNESS.toStringUnit(roughnessSize) + ")";
                }
        }
-       
-       
+
+
        /**
         * The material of the component.
         */
        protected Material material = null;
-       
+
        protected Finish finish = Finish.NORMAL;
-       
-       
+
+
 
        /**
         * Constructor that sets the relative position of the component.
@@ -58,13 +58,13 @@ public abstract class ExternalComponent extends RocketComponent {
                super(relativePosition);
                this.material = Prefs.getDefaultComponentMaterial(this.getClass(), Material.Type.BULK);
        }
-       
+
        /**
         * Returns the volume of the component.  This value is used in calculating the mass
         * of the object.
         */
        public abstract double getComponentVolume();
-       
+
        /**
         * Calculates the mass of the component as the product of the volume and interior density.
         */
@@ -72,7 +72,7 @@ public abstract class ExternalComponent extends RocketComponent {
        public double getComponentMass() {
                return material.getDensity() * getComponentVolume();
        }
-       
+
        /**
         * ExternalComponent has aerodynamic effect, so return true.
         */
@@ -80,7 +80,7 @@ public abstract class ExternalComponent extends RocketComponent {
        public boolean isAerodynamic() {
                return true;
        }
-       
+
        /**
         * ExternalComponent has effect on the mass, so return true.
         */
@@ -88,36 +88,35 @@ public abstract class ExternalComponent extends RocketComponent {
        public boolean isMassive() {
                return true;
        }
-       
-       
+
+
        public Material getMaterial() {
                return material;
        }
-       
+
        public void setMaterial(Material mat) {
                if (mat.getType() != Material.Type.BULK) {
                        throw new IllegalArgumentException("ExternalComponent requires a bulk material" +
                                        " type=" + mat.getType());
                }
-               
+
                if (material.equals(mat))
                        return;
                material = mat;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public Finish getFinish() {
                return finish;
        }
-       
+
        public void setFinish(Finish finish) {
                if (this.finish == finish)
                        return;
                this.finish = finish;
                fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
        }
-       
-       
+
 
        @Override
        protected List<RocketComponent> copyFrom(RocketComponent c) {
@@ -126,15 +125,5 @@ public abstract class ExternalComponent extends RocketComponent {
                this.material = src.material;
                return super.copyFrom(c);
        }
-       
-    /**
-     * Accept a visitor to this ExternalComponent in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this ExternalComponent
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-    
+
 }
index 24ca9811e81aebd41bdc8b90b2d5e164754976bb..792483d2618aa4cbd03c61e53b5cc2e7d0457728 100644 (file)
@@ -1,40 +1,40 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 
 public class FreeformFinSet extends FinSet {
        private static final LogHelper log = Application.getLogger();
-       
+
        private ArrayList<Coordinate> points = new ArrayList<Coordinate>();
-       
+
        public FreeformFinSet() {
                points.add(Coordinate.NUL);
                points.add(new Coordinate(0.025, 0.05));
                points.add(new Coordinate(0.075, 0.05));
                points.add(new Coordinate(0.05, 0));
-               
+
                this.length = 0.05;
        }
-       
-       
+
+
        public FreeformFinSet(Coordinate[] finpoints) throws IllegalFinPointException {
                setPoints(finpoints);
        }
-       
+
        /*
        public FreeformFinSet(FinSet finset) {
                Coordinate[] finpoints = finset.getFinPoints();
                this.copyFrom(finset);
-               
+
                points.clear();
                for (Coordinate c: finpoints) {
                        points.add(c);
@@ -50,7 +50,7 @@ public class FreeformFinSet extends FinSet {
         * inserted in its stead.
         * <p>
         * The specified fin set should not be used after the call!
-        * 
+        *
         * @param finset        the fin set to convert.
         * @return                      the new freeform fin set.
         */
@@ -59,12 +59,12 @@ public class FreeformFinSet extends FinSet {
                final RocketComponent root = finset.getRoot();
                FreeformFinSet freeform;
                List<RocketComponent> toInvalidate = Collections.emptyList();
-               
+
                try {
                        if (root instanceof Rocket) {
                                ((Rocket) root).freeze();
                        }
-                       
+
                        // Get fin set position and remove fin set
                        final RocketComponent parent = finset.getParent();
                        final int position;
@@ -74,7 +74,7 @@ public class FreeformFinSet extends FinSet {
                        } else {
                                position = -1;
                        }
-                       
+
 
                        // Create the freeform fin set
                        Coordinate[] finpoints = finset.getFinPoints();
@@ -85,24 +85,24 @@ public class FreeformFinSet extends FinSet {
                                                "freeform fin, fin=" + finset + " points=" + Arrays.toString(finpoints),
                                                e);
                        }
-                       
+
                        // Copy component attributes
                        toInvalidate = freeform.copyFrom(finset);
-                       
+
                        // Set name
                        final String componentTypeName = finset.getComponentName();
                        final String name = freeform.getName();
-                       
+
                        if (name.startsWith(componentTypeName)) {
                                freeform.setName(freeform.getComponentName() +
                                                name.substring(componentTypeName.length()));
                        }
-                       
+
                        // Add freeform fin set to parent
                        if (parent != null) {
                                parent.addChild(freeform, position);
                        }
-                       
+
                } finally {
                        if (root instanceof Rocket) {
                                ((Rocket) root).thaw();
@@ -114,34 +114,34 @@ public class FreeformFinSet extends FinSet {
                }
                return freeform;
        }
-       
-       
+
+
 
        /**
         * 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.
-        * 
+        *
         * @param index   the fin point before which to add the new point.
         */
        public void addPoint(int index) {
                double x0, y0, x1, y1;
-               
+
                x0 = points.get(index - 1).x;
                y0 = points.get(index - 1).y;
                x1 = points.get(index).x;
                y1 = points.get(index).y;
-               
+
                points.add(index, new Coordinate((x0 + x1) / 2, (y0 + y1) / 2));
                // adding a point within the segment affects neither mass nor aerodynamics
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        /**
         * Remove the fin point with the given index.  The first and last fin points
         * cannot be removed, and will cause an <code>IllegalFinPointException</code>
         * if attempted.
-        * 
+        *
         * @param index   the fin point index to remove
         * @throws IllegalFinPointException if removing would result in invalid fin planform
         */
@@ -149,20 +149,20 @@ public class FreeformFinSet extends FinSet {
                if (index == 0 || index == points.size() - 1) {
                        throw new IllegalFinPointException("cannot remove first or last point");
                }
-               
+
                ArrayList<Coordinate> copy = this.points.clone();
                copy.remove(index);
                validate(copy);
                this.points = copy;
-               
+
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        public int getPointCount() {
                return points.size();
        }
-       
+
        public void setPoints(Coordinate[] points) throws IllegalFinPointException {
                ArrayList<Coordinate> list = new ArrayList<Coordinate>(points.length);
                for (Coordinate p : points) {
@@ -170,23 +170,23 @@ public class FreeformFinSet extends FinSet {
                }
                validate(list);
                this.points = list;
-               
+
                this.length = points[points.length - 1].x;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        /**
         * Set the point at position <code>i</code> to coordinates (x,y).
         * <p>
         * Note that this method enforces basic fin shape restrictions (non-negative y,
-        * first and last point locations) silently, but throws an 
+        * first and last point locations) silently, but throws an
         * <code>IllegalFinPointException</code> if the point causes fin segments to
         * intersect.
         * <p>
         * Moving of the first point in the X-axis is allowed, but this actually moves
         * all of the other points the corresponding distance back.
-        * 
+        *
         * @param index the point index to modify.
         * @param x             the x-coordinate.
         * @param y             the y-coordinate.
@@ -196,11 +196,11 @@ public class FreeformFinSet extends FinSet {
        public void setPoint(int index, double x, double y) throws IllegalFinPointException {
                if (y < 0)
                        y = 0;
-               
+
                double x0, y0, x1, y1;
-               
+
                if (index == 0) {
-                       
+
                        // Restrict point
                        x = Math.min(x, points.get(points.size() - 1).x);
                        y = 0;
@@ -208,9 +208,9 @@ public class FreeformFinSet extends FinSet {
                        y0 = Double.NaN;
                        x1 = points.get(1).x;
                        y1 = points.get(1).y;
-                       
+
                } else if (index == points.size() - 1) {
-                       
+
                        // Restrict point
                        x = Math.max(x, 0);
                        y = 0;
@@ -218,16 +218,16 @@ public class FreeformFinSet extends FinSet {
                        y0 = points.get(index - 1).y;
                        x1 = Double.NaN;
                        y1 = Double.NaN;
-                       
+
                } else {
-                       
+
                        x0 = points.get(index - 1).x;
                        y0 = points.get(index - 1).y;
                        x1 = points.get(index + 1).x;
                        y1 = points.get(index + 1).y;
-                       
+
                }
-               
+
 
 
                // Check for intersecting
@@ -237,7 +237,7 @@ public class FreeformFinSet extends FinSet {
                for (int i = 1; i < points.size(); i++) {
                        px1 = points.get(i).x;
                        py1 = points.get(i).y;
-                       
+
                        if (i != index - 1 && i != index && i != index + 1) {
                                if (intersects(x0, y0, x, y, px0, py0, px1, py1)) {
                                        throw new IllegalFinPointException("segments intersect");
@@ -248,49 +248,49 @@ public class FreeformFinSet extends FinSet {
                                        throw new IllegalFinPointException("segments intersect");
                                }
                        }
-                       
+
                        px0 = px1;
                        py0 = py1;
                }
-               
+
                if (index == 0) {
-                       
+
                        System.out.println("Set point zero to x:" + x);
                        for (int i = 1; i < points.size(); i++) {
                                Coordinate c = points.get(i);
                                points.set(i, c.setX(c.x - x));
                        }
-                       
+
                } else {
-                       
+
                        points.set(index, new Coordinate(x, y));
-                       
+
                }
                if (index == 0 || index == points.size() - 1) {
                        this.length = points.get(points.size() - 1).x;
                }
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
        private boolean intersects(double ax0, double ay0, double ax1, double ay1,
                        double bx0, double by0, double bx1, double by1) {
-               
+
                double d = ((by1 - by0) * (ax1 - ax0) - (bx1 - bx0) * (ay1 - ay0));
-               
+
                double ua = ((bx1 - bx0) * (ay0 - by0) - (by1 - by0) * (ax0 - bx0)) / d;
                double ub = ((ax1 - ax0) * (ay0 - by0) - (ay1 - ay0) * (ax0 - bx0)) / d;
-               
+
                return (ua >= 0) && (ua <= 1) && (ub >= 0) && (ub <= 1);
        }
-       
-       
+
+
        @Override
        public Coordinate[] getFinPoints() {
                return points.toArray(new Coordinate[0]);
        }
-       
+
        @Override
        public double getSpan() {
                double max = 0;
@@ -300,30 +300,20 @@ public class FreeformFinSet extends FinSet {
                }
                return max;
        }
-       
+
        @Override
        public String getComponentName() {
                return "Freeform fin set";
        }
-       
-       
+
+
        @Override
        protected RocketComponent copyWithOriginalID() {
                RocketComponent c = super.copyWithOriginalID();
                ((FreeformFinSet) c).points = this.points.clone();
                return c;
        }
-       
-       /**
-        * Accept a visitor to this FreeformFinSet in the component hierarchy.
-        * 
-        * @param theVisitor  the visitor that will be called back with a reference to this FreeformFinSet
-        */
-       @Override
-       public void accept(ComponentVisitor theVisitor) {
-               theVisitor.visit(this);
-       }
-       
+
        private void validate(ArrayList<Coordinate> points) throws IllegalFinPointException {
                final int n = points.size();
                if (points.get(0).x != 0 || points.get(0).y != 0 ||
@@ -342,5 +332,5 @@ public class FreeformFinSet extends FinSet {
                        }
                }
        }
-       
+
 }
index 036daef64add96280cf60ece88e1ac3bda41b2dd..a4d5af4defb039245bd6f16e7bc265f1a613b544 100644 (file)
@@ -13,16 +13,16 @@ import java.util.List;
 /**
  * This class defines an inner tube that can be used as a motor mount.  The component
  * may also be clustered.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class InnerTube extends ThicknessRingComponent
                implements Clusterable, RadialParent, MotorMount {
-       
+
        private ClusterConfiguration cluster = ClusterConfiguration.SINGLE;
        private double clusterScale = 1.0;
        private double clusterRotation = 0.0;
-       
+
 
        private boolean motorMount = false;
        private HashMap<String, Double> ejectionDelays = new HashMap<String, Double>();
@@ -30,8 +30,8 @@ public class InnerTube extends ThicknessRingComponent
        private IgnitionEvent ignitionEvent = IgnitionEvent.AUTOMATIC;
        private double ignitionDelay = 0;
        private double overhang = 0;
-       
-       
+
+
        /**
         * Main constructor.
         */
@@ -41,30 +41,30 @@ public class InnerTube extends ThicknessRingComponent
                this.setInnerRadius(0.018 / 2);
                this.setLength(0.070);
        }
-       
-       
+
+
        @Override
        public double getInnerRadius(double x) {
                return getInnerRadius();
        }
-       
-       
+
+
        @Override
        public double getOuterRadius(double x) {
                return getOuterRadius();
        }
-       
-       
+
+
        @Override
        public String getComponentName() {
                return "Inner Tube";
        }
-       
+
        @Override
        public boolean allowsChildren() {
                return true;
        }
-       
+
        /**
         * Allow all InternalComponents to be added to this component.
         */
@@ -72,11 +72,11 @@ public class InnerTube extends ThicknessRingComponent
        public boolean isCompatible(Class<? extends RocketComponent> type) {
                return InternalComponent.class.isAssignableFrom(type);
        }
-       
-       
+
+
 
        /////////////  Cluster methods  //////////////
-       
+
        /**
         * Get the current cluster configuration.
         * @return  The current cluster configuration.
@@ -84,7 +84,7 @@ public class InnerTube extends ThicknessRingComponent
        public ClusterConfiguration getClusterConfiguration() {
                return cluster;
        }
-       
+
        /**
         * Set the current cluster configuration.
         * @param cluster  The cluster configuration.
@@ -93,7 +93,7 @@ public class InnerTube extends ThicknessRingComponent
                this.cluster = cluster;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        /**
         * Return the number of tubes in the cluster.
         * @return Number of tubes in the current cluster.
@@ -102,7 +102,7 @@ public class InnerTube extends ThicknessRingComponent
        public int getClusterCount() {
                return cluster.getClusterCount();
        }
-       
+
        /**
         * Get the cluster scaling.  A value of 1.0 indicates that the tubes are packed
         * touching each other, larger values separate the tubes and smaller values
@@ -111,7 +111,7 @@ public class InnerTube extends ThicknessRingComponent
        public double getClusterScale() {
                return clusterScale;
        }
-       
+
        /**
         * Set the cluster scaling.
         * @see #getClusterScale()
@@ -123,8 +123,8 @@ public class InnerTube extends ThicknessRingComponent
                clusterScale = scale;
                fireComponentChangeEvent(new ComponentChangeEvent(this, ComponentChangeEvent.MASS_CHANGE));
        }
-       
-       
+
+
 
        /**
         * @return the clusterRotation
@@ -132,8 +132,8 @@ public class InnerTube extends ThicknessRingComponent
        public double getClusterRotation() {
                return clusterRotation;
        }
-       
-       
+
+
        /**
         * @param rotation the clusterRotation to set
         */
@@ -144,8 +144,8 @@ public class InnerTube extends ThicknessRingComponent
                this.clusterRotation = rotation;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        /**
         * Return the distance between the closest two cluster inner tube center points.
         * This is equivalent to the cluster scale multiplied by the tube diameter.
@@ -154,8 +154,8 @@ public class InnerTube extends ThicknessRingComponent
        public double getClusterSeparation() {
                return 2 * getOuterRadius() * clusterScale;
        }
-       
-       
+
+
        public List<Coordinate> getClusterPoints() {
                List<Coordinate> list = new ArrayList<Coordinate>(getClusterCount());
                List<Double> points = cluster.getPoints(clusterRotation - getRadialDirection());
@@ -165,16 +165,16 @@ public class InnerTube extends ThicknessRingComponent
                }
                return list;
        }
-       
-       
+
+
        @Override
        public Coordinate[] shiftCoordinates(Coordinate[] array) {
                array = super.shiftCoordinates(array);
-               
+
                int count = getClusterCount();
                if (count == 1)
                        return array;
-               
+
                List<Coordinate> points = getClusterPoints();
                if (points.size() != count) {
                        throw new BugException("Inconsistent cluster configuration, cluster count=" + count +
@@ -186,20 +186,20 @@ public class InnerTube extends ThicknessRingComponent
                                newArray[i * count + j] = array[i].add(points.get(j));
                        }
                }
-               
+
                return newArray;
        }
-       
-       
+
+
 
 
        ////////////////  Motor mount  /////////////////
-       
+
        @Override
        public boolean isMotorMount() {
                return motorMount;
        }
-       
+
        @Override
        public void setMotorMount(boolean mount) {
                if (motorMount == mount)
@@ -207,22 +207,22 @@ public class InnerTube extends ThicknessRingComponent
                motorMount = mount;
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Override
        public Motor getMotor(String id) {
                if (id == null)
                        return null;
-               
+
                // Check whether the id is valid for the current rocket
                RocketComponent root = this.getRoot();
                if (!(root instanceof Rocket))
                        return null;
                if (!((Rocket) root).isMotorConfigurationID(id))
                        return null;
-               
+
                return motors.get(id);
        }
-       
+
        @Override
        public void setMotor(String id, Motor motor) {
                if (id == null) {
@@ -237,7 +237,7 @@ public class InnerTube extends ThicknessRingComponent
                motors.put(id, motor);
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Override
        public double getMotorDelay(String id) {
                Double delay = ejectionDelays.get(id);
@@ -245,29 +245,29 @@ public class InnerTube extends ThicknessRingComponent
                        return Motor.PLUGGED;
                return delay;
        }
-       
+
        @Override
        public void setMotorDelay(String id, double delay) {
                ejectionDelays.put(id, delay);
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
+
        @Deprecated
        @Override
        public int getMotorCount() {
                return getClusterCount();
        }
-       
+
        @Override
        public double getMotorMountDiameter() {
                return getInnerRadius() * 2;
        }
-       
+
        @Override
        public IgnitionEvent getIgnitionEvent() {
                return ignitionEvent;
        }
-       
+
        @Override
        public void setIgnitionEvent(IgnitionEvent event) {
                if (ignitionEvent == event)
@@ -275,13 +275,13 @@ public class InnerTube extends ThicknessRingComponent
                ignitionEvent = event;
                fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getIgnitionDelay() {
                return ignitionDelay;
        }
-       
+
        @Override
        public void setIgnitionDelay(double delay) {
                if (MathUtil.equals(delay, ignitionDelay))
@@ -289,13 +289,13 @@ public class InnerTube extends ThicknessRingComponent
                ignitionDelay = delay;
                fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getMotorOverhang() {
                return overhang;
        }
-       
+
        @Override
        public void setMotorOverhang(double overhang) {
                if (MathUtil.equals(this.overhang, overhang))
@@ -303,34 +303,22 @@ public class InnerTube extends ThicknessRingComponent
                this.overhang = overhang;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        @Override
        public Coordinate getMotorPosition(String id) {
                Motor motor = motors.get(id);
                if (motor == null) {
                        throw new IllegalArgumentException("No motor with id " + id + " defined.");
                }
-               
+
                return new Coordinate(this.getLength() - motor.getLength() + this.getMotorOverhang());
        }
        
-    /**
-     * Accept a visitor to an InnerTube object in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this InnerTube
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-       
-
-
        /*
         * (non-Javadoc)
         * Copy the motor and ejection delay HashMaps.
-        * 
+        *
         * @see rocketcomponent.RocketComponent#copy()
         */
        @SuppressWarnings("unchecked")
@@ -341,5 +329,5 @@ public class InnerTube extends ThicknessRingComponent
                ((InnerTube) c).ejectionDelays = (HashMap<String, Double>) ejectionDelays.clone();
                return c;
        }
-       
+
 }
\ No newline at end of file
index a51629a3693b305279e711e9ed32de8a44602c0f..70f92a7f451df489fecc163ba5c905cd7c4ebb36 100644 (file)
@@ -12,13 +12,13 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
 
        private double radius;
        private double thickness;
-       
+
        private double radialDirection = 0;
-       
+
        /* These are calculated when the component is first attached to any Rocket */
        private double shiftY, shiftZ;
-       
-       
+
+
 
        public LaunchLug() {
                super(Position.MIDDLE);
@@ -26,12 +26,12 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                thickness = 0.001;
                length = 0.03;
        }
-       
-       
+
+
        public double getOuterRadius () {
                return radius;
        }
-       
+
        public void setOuterRadius (double radius) {
                if (MathUtil.equals(this.radius, radius))
                        return;
@@ -39,31 +39,31 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                this.thickness = Math.min(this.thickness, this.radius);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public double getInnerRadius() {
                return radius - thickness;
        }
-       
+
        public void setInnerRadius(double innerRadius) {
                setOuterRadius(innerRadius + thickness);
        }
-       
+
        public double getThickness() {
                return thickness;
        }
-       
+
        public void setThickness(double thickness) {
                if (MathUtil.equals(this.thickness, thickness))
                        return;
                this.thickness = MathUtil.clamp(thickness, 0, radius);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        public double getRadialDirection() {
                return radialDirection;
        }
-       
+
        public void setRadialDirection(double direction) {
                direction = MathUtil.reduce180(direction);
                if (MathUtil.equals(this.radialDirection, direction))
@@ -71,8 +71,8 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                this.radialDirection = direction;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
        public void setLength(double length) {
                if (MathUtil.equals(this.length, length))
@@ -80,8 +80,8 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                this.length = length;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
 
 
@@ -90,44 +90,44 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                super.setRelativePosition(position);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        @Override
        public void setPositionValue(double value) {
                super.setPositionValue(value);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
        @Override
        public Coordinate[] shiftCoordinates(Coordinate[] array) {
                array = super.shiftCoordinates(array);
-               
+
                for (int i = 0; i < array.length; i++) {
                        array[i] = array[i].add(0, shiftY, shiftZ);
                }
-               
+
                return array;
        }
-       
-       
+
+
        @Override
        public void componentChanged(ComponentChangeEvent e) {
                super.componentChanged(e);
-               
-               /* 
+
+               /*
                 * shiftY and shiftZ must be computed here since calculating them
                 * in shiftCoordinates() would cause an infinite loop due to .toRelative
                 */
                RocketComponent body;
                double parentRadius;
-               
+
                for (body = this.getParent(); body != null; body = body.getParent()) {
                        if (body instanceof SymmetricComponent)
                                break;
                }
-               
+
                if (body == null) {
                        parentRadius = 0;
                } else {
@@ -139,21 +139,21 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                        x2 = MathUtil.clamp(x2, 0, body.getLength());
                        parentRadius = Math.max(s.getRadius(x1), s.getRadius(x2));
                }
-               
+
                shiftY = Math.cos(radialDirection) * (parentRadius + radius);
                shiftZ = Math.sin(radialDirection) * (parentRadius + radius);
-               
+
                //              System.out.println("Computed shift: y="+shiftY+" z="+shiftZ);
        }
-       
-       
+
+
 
 
        @Override
        public double getComponentVolume() {
                return length * Math.PI * (MathUtil.pow2(radius) - MathUtil.pow2(radius - thickness));
        }
-       
+
        @Override
        public Collection<Coordinate> getComponentBounds() {
                ArrayList<Coordinate> set = new ArrayList<Coordinate>();
@@ -161,49 +161,39 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                addBound(set, length, radius);
                return set;
        }
-       
+
        @Override
        public Coordinate getComponentCG() {
                return new Coordinate(length / 2, 0, 0, getComponentMass());
        }
-       
+
        @Override
        public String getComponentName() {
                return "Launch lug";
        }
-       
+
        @Override
        public double getLongitudinalUnitInertia() {
                // 1/12 * (3 * (r1^2 + r2^2) + h^2)
                return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getOuterRadius()) +
                                MathUtil.pow2(getLength())) / 12;
        }
-       
+
        @Override
        public double getRotationalUnitInertia() {
                // 1/2 * (r1^2 + r2^2)
                return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius()))/2;
        }
-       
+
        @Override
        public boolean allowsChildren() {
                return false;
        }
-       
+
        @Override
        public boolean isCompatible(Class<? extends RocketComponent> type) {
                // Allow nothing to be attached to a LaunchLug
                return false;
        }
-       
-    /**
-     * Accept a visitor to this LaunchLug in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this LaunchLug
-     */    
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-    
+
 }
index bbd9789db1b98a006985e00144ecc8308d944522..70d22ff3b6d0b84bf3430c7cf9f396f11372a0bd 100644 (file)
@@ -1,12 +1,12 @@
 package net.sf.openrocket.rocketcomponent;
 
-import static net.sf.openrocket.util.MathUtil.pow2;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.MathUtil;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.MathUtil;
+import static net.sf.openrocket.util.MathUtil.pow2;
 
 
 /**
@@ -19,31 +19,31 @@ import net.sf.openrocket.util.MathUtil;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public abstract class MassObject extends InternalComponent {
-       
+
        private double radius;
-       
+
        private double radialPosition;
        private double radialDirection;
-       
+
        private double shiftY = 0;
        private double shiftZ = 0;
-       
-       
+
+
        public MassObject() {
                this(0.03, 0.015);
        }
-       
+
        public MassObject(double length, double radius) {
                super();
-               
+
                this.length = length;
                this.radius = radius;
-               
+
                this.setRelativePosition(Position.TOP);
                this.setPositionValue(0.0);
        }
-       
-       
+
+
        public void setLength(double length) {
                length = Math.max(length, 0);
                if (MathUtil.equals(this.length, length)) {
@@ -52,13 +52,13 @@ public abstract class MassObject extends InternalComponent {
                this.length = length;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        public final double getRadius() {
                return radius;
        }
-       
-       
+
+
        public final void setRadius(double radius) {
                radius = Math.max(radius, 0);
                if (MathUtil.equals(this.radius, radius)) {
@@ -67,13 +67,13 @@ public abstract class MassObject extends InternalComponent {
                this.radius = radius;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
        public final double getRadialPosition() {
                return radialPosition;
        }
-       
+
        public final void setRadialPosition(double radialPosition) {
                radialPosition = Math.max(radialPosition, 0);
                if (MathUtil.equals(this.radialPosition, radialPosition)) {
@@ -84,11 +84,11 @@ public abstract class MassObject extends InternalComponent {
                shiftZ = radialPosition * Math.sin(radialDirection);
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public final double getRadialDirection() {
                return radialDirection;
        }
-       
+
        public final void setRadialDirection(double radialDirection) {
                radialDirection = MathUtil.reduce180(radialDirection);
                if (MathUtil.equals(this.radialDirection, radialDirection)) {
@@ -99,8 +99,8 @@ public abstract class MassObject extends InternalComponent {
                shiftZ = radialPosition * Math.sin(radialDirection);
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        /**
         * Shift the coordinates according to the radial position and direction.
         */
@@ -111,22 +111,22 @@ public abstract class MassObject extends InternalComponent {
                }
                return array;
        }
-       
+
        @Override
        public final Coordinate getComponentCG() {
                return new Coordinate(length / 2, shiftY, shiftZ, getComponentMass());
        }
-       
+
        @Override
        public final double getLongitudinalUnitInertia() {
                return (3 * pow2(radius) + pow2(length)) / 12;
        }
-       
+
        @Override
        public final double getRotationalUnitInertia() {
                return pow2(radius) / 2;
        }
-       
+
        @Override
        public final Collection<Coordinate> getComponentBounds() {
                Collection<Coordinate> c = new ArrayList<Coordinate>();
@@ -134,15 +134,5 @@ public abstract class MassObject extends InternalComponent {
                addBound(c, length, radius);
                return c;
        }
-       
-       /**
-        * Accept a visitor to this MassObject in the component hierarchy.
-        *
-        * @param theVisitor the visitor that will be called back with a reference to this MassObject
-        */
-       @Override
-       public void accept(final ComponentVisitor theVisitor) {
-               theVisitor.visit(this);
-       }
-       
+
 }
index 1aa61a4cb38d297615cda765f4f0e5c4ffaebbe0..229fcbf5a93be462794f11d92f923d0313b35931 100644 (file)
@@ -3,18 +3,18 @@ package net.sf.openrocket.rocketcomponent;
 /**
  * Rocket nose cones of various types.  Implemented as a transition with the
  * fore radius == 0.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
 public class NoseCone extends Transition {
-       
-       
+
+
        /********* Constructors **********/
        public NoseCone() {
                this(Transition.Shape.OGIVE, 6*DEFAULT_RADIUS, DEFAULT_RADIUS);
        }
-       
+
        public NoseCone(Transition.Shape type, double length, double radius) {
                super();
                super.setType(type);
@@ -27,9 +27,9 @@ public class NoseCone extends Transition {
                super.setThickness(0.002);
                super.setLength(length);
                super.setClipped(false);
-               
+
        }
-       
+
 
        /********** Get/set methods for component parameters **********/
 
@@ -37,7 +37,7 @@ public class NoseCone extends Transition {
        public double getForeRadius() {
                return 0;
        }
-       
+
        @Override
        public void setForeRadius(double r) {
                // No-op
@@ -47,7 +47,7 @@ public class NoseCone extends Transition {
        public boolean isForeRadiusAutomatic() {
                return false;
        }
-       
+
        @Override
        public void setForeRadiusAutomatic(boolean b) {
                // No-op
@@ -97,14 +97,14 @@ public class NoseCone extends Transition {
        public boolean isClipped() {
                return false;
        }
-       
+
        @Override
        public void setClipped(boolean b) {
                // No-op
        }
-       
 
-       
+
+
        /********** RocketComponent methods **********/
 
        /**
@@ -114,14 +114,5 @@ public class NoseCone extends Transition {
        public String getComponentName() {
                return "Nose cone";
        }
-    
-    /**
-     * Accept a visitor to this NoseCone in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this NoseCone
-     */
-    @Override
-    public void accept(ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
+
 }
index b3d862510c99505c3b7b81ca35f349eef8446fa9..46a35143900afddd218c2cda1d29facf7139f4c7 100644 (file)
@@ -6,16 +6,16 @@ import net.sf.openrocket.util.MathUtil;
 /**
  * An inner component that consists of a hollow cylindrical component.  This can be
  * an inner tube, tube coupler, centering ring, bulkhead etc.
- * 
+ *
  * The properties include the inner and outer radii, length and radial position.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public abstract class RadiusRingComponent extends RingComponent implements Coaxial {
 
        protected double outerRadius = 0;
        protected double innerRadius = 0;
-       
+
        @Override
        public double getOuterRadius() {
                if (outerRadiusAutomatic && getParent() instanceof RadialParent) {
@@ -27,7 +27,7 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
                        outerRadius = Math.min(((RadialParent)parent).getInnerRadius(pos1),
                                        ((RadialParent)parent).getInnerRadius(pos2));
                }
-                               
+
                return outerRadius;
        }
 
@@ -36,7 +36,7 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
                r = Math.max(r,0);
                if (MathUtil.equals(outerRadius, r) && !isOuterRadiusAutomatic())
                        return;
-               
+
                outerRadius = r;
                outerRadiusAutomatic = false;
                if (getInnerRadius() > r) {
@@ -46,8 +46,8 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
 
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getInnerRadius() {
                return innerRadius;
@@ -57,18 +57,18 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
                r = Math.max(r,0);
                if (MathUtil.equals(innerRadius, r))
                        return;
-               
+
                innerRadius = r;
                innerRadiusAutomatic = false;
                if (getOuterRadius() < r) {
                        outerRadius = r;
                        outerRadiusAutomatic = false;
                }
-               
+
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        @Override
        public double getThickness() {
                return Math.max(getOuterRadius() - getInnerRadius(), 0);
@@ -76,19 +76,9 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
        @Override
        public void setThickness(double thickness) {
                double outer = getOuterRadius();
-               
+
                thickness = MathUtil.clamp(thickness, 0, outer);
                setInnerRadius(outer - thickness);
        }
 
-    /**
-     * Accept a visitor to this RadiusRingComponent in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this RadiusRingComponent
-     */    
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-    
 }
index b6c6cec60f729dac5ad8fca6952f5d390c820fc9..233457c25e8929637e37919e680afff27c07bcee 100644 (file)
@@ -11,90 +11,90 @@ import java.util.List;
 /**
  * An inner component that consists of a hollow cylindrical component.  This can be
  * an inner tube, tube coupler, centering ring, bulkhead etc.
- * 
+ *
  * The properties include the inner and outer radii, length and radial position.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public abstract class RingComponent extends StructuralComponent implements Coaxial {
 
        protected boolean outerRadiusAutomatic = false;
        protected boolean innerRadiusAutomatic = false;
-       
-       
+
+
        private double radialDirection = 0;
        private double radialPosition = 0;
-       
+
        private double shiftY = 0;
        private double shiftZ = 0;
-       
 
-       
+
+
     @Override
        public abstract double getOuterRadius();
     @Override
        public abstract void setOuterRadius(double r);
-       
+
     @Override
-       public abstract double getInnerRadius();        
+       public abstract double getInnerRadius();
     @Override
        public abstract void setInnerRadius(double r);
-       
+
     @Override
        public abstract double getThickness();
        public abstract void setThickness(double thickness);
-       
-       
+
+
        public final boolean isOuterRadiusAutomatic() {
                return outerRadiusAutomatic;
        }
-       
+
        protected void setOuterRadiusAutomatic(boolean auto) {
                if (auto == outerRadiusAutomatic)
                        return;
                outerRadiusAutomatic = auto;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
        public final boolean isInnerRadiusAutomatic() {
                return innerRadiusAutomatic;
        }
-       
+
        protected void setInnerRadiusAutomatic(boolean auto) {
                if (auto == innerRadiusAutomatic)
                        return;
                innerRadiusAutomatic = auto;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
-       
-       
+
+
+
+
        public final void setLength(double length) {
                double l = Math.max(length,0);
                if (this.length == l)
                        return;
-               
+
                this.length = l;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
-       
+
        /**
         * Return the radial direction of displacement of the component.  Direction 0
         * is equivalent to the Y-direction.
-        * 
+        *
         * @return  the radial direction.
         */
        public double getRadialDirection() {
                return radialDirection;
        }
-       
+
        /**
         * Set the radial direction of displacement of the component.  Direction 0
         * is equivalent to the Y-direction.
-        * 
+        *
         * @param dir  the radial direction.
         */
        public void setRadialDirection(double dir) {
@@ -107,23 +107,23 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
-       
-       
-       
+
+
+
        /**
         * Return the radial position of the component.  The position is the distance
         * of the center of the component from the center of the parent component.
-        * 
+        *
         * @return  the radial position.
         */
        public double getRadialPosition() {
                return radialPosition;
        }
-       
+
        /**
         * Set the radial position of the component.  The position is the distance
         * of the center of the component from the center of the parent component.
-        * 
+        *
         * @param pos  the radial position.
         */
        public void setRadialPosition(double pos) {
@@ -136,25 +136,25 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
-       
+
        public double getRadialShiftY() {
                return shiftY;
        }
-       
+
        public double getRadialShiftZ() {
                return shiftZ;
        }
-       
+
        public void setRadialShift(double y, double z) {
                radialPosition = Math.hypot(y, z);
                radialDirection = Math.atan2(z, y);
-               
-               // Re-calculate to ensure consistency 
+
+               // Re-calculate to ensure consistency
                shiftY = radialPosition * Math.cos(radialDirection);
                shiftZ = radialPosition * Math.sin(radialDirection);
                assert(MathUtil.equals(y, shiftY));
                assert(MathUtil.equals(z, shiftZ));
-               
+
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
@@ -167,8 +167,8 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                        return ((Clusterable)this).getClusterConfiguration().getClusterCount();
                return 1;
        }
-       
-       
+
+
        /**
         * Shift the coordinates according to the radial position and direction.
         */
@@ -179,8 +179,8 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                }
                return array;
        }
-       
-       
+
+
        @Override
        public Collection<Coordinate> getComponentBounds() {
                List<Coordinate> bounds = new ArrayList<Coordinate>();
@@ -188,9 +188,9 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                addBound(bounds,length,getOuterRadius());
                return bounds;
        }
-       
 
-       
+
+
        @Override
        public Coordinate getComponentCG() {
                return new Coordinate(length/2, 0, 0, getComponentMass());
@@ -201,7 +201,7 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                return ringMass(getOuterRadius(), getInnerRadius(), getLength(),
                                getMaterial().getDensity()) * getClusterCount();
        }
-       
+
 
        @Override
        public double getLongitudinalUnitInertia() {
@@ -213,14 +213,4 @@ public abstract class RingComponent extends StructuralComponent implements Coaxi
                return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius());
        }
 
-    /**
-     * Accept a visitor to this RingComponent in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this RingComponent
-     */    
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-
 }
index 3a284534b36cf33638d04e4a1f446db8a3538338..64c1f687c02e549644a981118aa7a5f193bfa45e 100644 (file)
@@ -1,25 +1,15 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
-
-import javax.swing.event.ChangeListener;
-import javax.swing.event.EventListenerList;
-
 import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
-import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.UniqueID;
+import net.sf.openrocket.util.*;
+
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import java.util.*;
 
 
 /**
@@ -28,46 +18,46 @@ import net.sf.openrocket.util.UniqueID;
  * (eg. the rocket listener lists) and the methods defined in RocketComponent call these.
  * It also defines some other methods that concern the whole rocket, and helper methods
  * that keep information about the program state.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
 public class Rocket extends RocketComponent {
        private static final LogHelper log = Application.getLogger();
-       
+
        public static final double DEFAULT_REFERENCE_LENGTH = 0.01;
-       
+
 
        /**
         * List of component change listeners.
         */
        private EventListenerList listenerList = new EventListenerList();
-       
+
        /**
         * When freezeList != null, events are not dispatched but stored in the list.
         * When the structure is thawed, a single combined event will be fired.
         */
        private List<ComponentChangeEvent> freezeList = null;
-       
+
 
        private int modID;
        private int massModID;
        private int aeroModID;
        private int treeModID;
        private int functionalModID;
-       
+
 
        private ReferenceType refType = ReferenceType.MAXIMUM; // Set in constructor
        private double customReferenceLength = DEFAULT_REFERENCE_LENGTH;
-       
+
 
        // The default configuration used in dialogs
        private final Configuration defaultConfiguration;
-       
+
 
        private String designer = "";
        private String revision = "";
-       
+
 
        // Motor configuration list
        private ArrayList<String> motorConfigurationIDs = new ArrayList<String>();
@@ -75,15 +65,15 @@ public class Rocket extends RocketComponent {
        {
                motorConfigurationIDs.add(null);
        }
-       
+
 
        // Does the rocket have a perfect finish (a notable amount of laminar flow)
        private boolean perfectFinish = false;
-       
-       
+
+
 
        /////////////  Constructor  /////////////
-       
+
        public Rocket() {
                super(RocketComponent.Position.AFTER);
                modID = UniqueID.next();
@@ -93,150 +83,150 @@ public class Rocket extends RocketComponent {
                functionalModID = modID;
                defaultConfiguration = new Configuration(this);
        }
-       
-       
+
+
 
        public String getDesigner() {
                checkState();
                return designer;
        }
-       
+
        public void setDesigner(String s) {
                if (s == null)
                        s = "";
                designer = s;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        public String getRevision() {
                checkState();
                return revision;
        }
-       
+
        public void setRevision(String s) {
                if (s == null)
                        s = "";
                revision = s;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
 
 
        /**
         * Return the number of stages in this rocket.
-        * 
+        *
         * @return   the number of stages in this rocket.
         */
        public int getStageCount() {
                checkState();
                return this.getChildCount();
        }
-       
-       
+
+
        /**
         * Return the non-negative modification ID of this rocket.  The ID is changed
-        * every time any change occurs in the rocket.  This can be used to check 
+        * every time any change occurs in the rocket.  This can be used to check
         * whether it is necessary to void cached data in cases where listeners can not
         * or should not be used.
         * <p>
         * Three other modification IDs are also available, {@link #getMassModID()},
-        * {@link #getAerodynamicModID()} {@link #getTreeModID()}, which change every time 
-        * a mass change, aerodynamic change, or tree change occur.  Even though the values 
-        * of the different modification ID's may be equal, they should be treated totally 
+        * {@link #getAerodynamicModID()} {@link #getTreeModID()}, which change every time
+        * a mass change, aerodynamic change, or tree change occur.  Even though the values
+        * of the different modification ID's may be equal, they should be treated totally
         * separate.
         * <p>
         * Note that undo events restore the modification IDs that were in use at the
         * corresponding undo level.  Subsequent modifications, however, produce modIDs
         * distinct from those already used.
-        * 
+        *
         * @return   a unique ID number for this modification state.
         */
        public int getModID() {
                return modID;
        }
-       
+
        /**
         * Return the non-negative mass modification ID of this rocket.  See
         * {@link #getModID()} for details.
-        * 
+        *
         * @return   a unique ID number for this mass-modification state.
         */
        public int getMassModID() {
                return massModID;
        }
-       
+
        /**
         * Return the non-negative aerodynamic modification ID of this rocket.  See
         * {@link #getModID()} for details.
-        * 
+        *
         * @return   a unique ID number for this aerodynamic-modification state.
         */
        public int getAerodynamicModID() {
                return aeroModID;
        }
-       
+
        /**
         * Return the non-negative tree modification ID of this rocket.  See
         * {@link #getModID()} for details.
-        * 
+        *
         * @return   a unique ID number for this tree-modification state.
         */
        public int getTreeModID() {
                return treeModID;
        }
-       
+
        /**
         * Return the non-negative functional modificationID of this rocket.
         * This changes every time a functional change occurs.
-        * 
+        *
         * @return      a unique ID number for this functional modification state.
         */
        public int getFunctionalModID() {
                return functionalModID;
        }
-       
-       
+
+
 
 
        public ReferenceType getReferenceType() {
                checkState();
                return refType;
        }
-       
+
        public void setReferenceType(ReferenceType type) {
                if (refType == type)
                        return;
                refType = type;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        public double getCustomReferenceLength() {
                checkState();
                return customReferenceLength;
        }
-       
+
        public void setCustomReferenceLength(double length) {
                if (MathUtil.equals(customReferenceLength, length))
                        return;
-               
+
                this.customReferenceLength = Math.max(length, 0.001);
-               
+
                if (refType == ReferenceType.CUSTOM) {
                        fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
                }
        }
-       
-       
+
+
 
 
 
        /**
         * Set whether the rocket has a perfect finish.  This will affect whether the
         * boundary layer is assumed to be fully turbulent or not.
-        * 
+        *
         * @param perfectFinish         whether the finish is perfect.
         */
        public void setPerfectFinish(boolean perfectFinish) {
@@ -245,19 +235,19 @@ public class Rocket extends RocketComponent {
                this.perfectFinish = perfectFinish;
                fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
        }
-       
-       
+
+
 
        /**
         * Get whether the rocket has a perfect finish.
-        * 
+        *
         * @return the perfectFinish
         */
        public boolean isPerfectFinish() {
                return perfectFinish;
        }
-       
-       
+
+
 
 
 
@@ -273,10 +263,10 @@ public class Rocket extends RocketComponent {
                copy.motorConfigurationNames =
                                (HashMap<String, String>) this.motorConfigurationNames.clone();
                copy.resetListeners();
-               
+
                return copy;
        }
-       
+
        /**
         * Load the rocket structure from the source.  The method loads the fields of this
         * Rocket object and copies the references to siblings from the <code>source</code>.
@@ -289,10 +279,10 @@ public class Rocket extends RocketComponent {
         */
        @SuppressWarnings("unchecked")
        public void loadFrom(Rocket r) {
-               
+
                // Store list of components to invalidate after event has been fired
                List<RocketComponent> toInvalidate = this.copyFrom(r);
-               
+
                int type = ComponentChangeEvent.UNDO_CHANGE | ComponentChangeEvent.NONFUNCTIONAL_CHANGE;
                if (this.massModID != r.massModID)
                        type |= ComponentChangeEvent.MASS_CHANGE;
@@ -300,7 +290,7 @@ public class Rocket extends RocketComponent {
                        type |= ComponentChangeEvent.AERODYNAMIC_CHANGE;
                // Loading a rocket is always a tree change since the component objects change
                type |= ComponentChangeEvent.TREE_CHANGE;
-               
+
                this.modID = r.modID;
                this.massModID = r.massModID;
                this.aeroModID = r.aeroModID;
@@ -308,31 +298,31 @@ public class Rocket extends RocketComponent {
                this.functionalModID = r.functionalModID;
                this.refType = r.refType;
                this.customReferenceLength = r.customReferenceLength;
-               
+
                this.motorConfigurationIDs = r.motorConfigurationIDs.clone();
                this.motorConfigurationNames =
                                (HashMap<String, String>) r.motorConfigurationNames.clone();
                this.perfectFinish = r.perfectFinish;
-               
+
                String id = defaultConfiguration.getMotorConfigurationID();
                if (!this.motorConfigurationIDs.contains(id))
                        defaultConfiguration.setMotorConfigurationID(null);
-               
+
                this.checkComponentStructure();
-               
+
                fireComponentChangeEvent(type);
-               
+
                // Invalidate obsolete components after event
                for (RocketComponent c : toInvalidate) {
                        c.invalidate();
                }
        }
-       
-       
+
+
 
 
        ///////  Implement the ComponentChangeListener lists
-       
+
        /**
         * Creates a new EventListenerList for this component.  This is necessary when cloning
         * the structure.
@@ -341,15 +331,15 @@ public class Rocket extends RocketComponent {
                //              System.out.println("RESETTING LISTENER LIST of Rocket "+this);
                listenerList = new EventListenerList();
        }
-       
-       
+
+
        public void printListeners() {
                System.out.println("" + this + " has " + listenerList.getListenerCount() + " listeners:");
                Object[] list = listenerList.getListenerList();
                for (int i = 1; i < list.length; i += 2)
                        System.out.println("  " + ((i + 1) / 2) + ": " + list[i]);
        }
-       
+
        @Override
        public void addComponentChangeListener(ComponentChangeListener l) {
                checkState();
@@ -357,15 +347,15 @@ public class Rocket extends RocketComponent {
                log.verbose("Added ComponentChangeListener " + l + ", current number of listeners is " +
                                listenerList.getListenerCount());
        }
-       
+
        @Override
        public void removeComponentChangeListener(ComponentChangeListener l) {
                listenerList.remove(ComponentChangeListener.class, l);
                log.verbose("Removed ComponentChangeListener " + l + ", current number of listeners is " +
                                listenerList.getListenerCount());
        }
-       
-       
+
+
        @Override
        public void addChangeListener(ChangeListener l) {
                checkState();
@@ -373,21 +363,21 @@ public class Rocket extends RocketComponent {
                log.verbose("Added ChangeListener " + l + ", current number of listeners is " +
                                listenerList.getListenerCount());
        }
-       
+
        @Override
        public void removeChangeListener(ChangeListener l) {
                listenerList.remove(ChangeListener.class, l);
                log.verbose("Removed ChangeListener " + l + ", current number of listeners is " +
                                listenerList.getListenerCount());
        }
-       
-       
+
+
        @Override
        protected void fireComponentChangeEvent(ComponentChangeEvent e) {
                mutex.lock("fireComponentChangeEvent");
                try {
                        checkState();
-                       
+
                        // Update modification ID's only for normal (not undo/redo) events
                        if (!e.isUndoChange()) {
                                modID = UniqueID.next();
@@ -400,22 +390,22 @@ public class Rocket extends RocketComponent {
                                if (e.getType() != ComponentChangeEvent.NONFUNCTIONAL_CHANGE)
                                        functionalModID = modID;
                        }
-                       
+
                        // Check whether frozen
                        if (freezeList != null) {
                                log.debug("Rocket is in frozen state, adding event " + e + " info freeze list");
                                freezeList.add(e);
                                return;
                        }
-                       
+
                        log.debug("Firing rocket change event " + e);
-                       
+
                        // Notify all components first
                        Iterator<RocketComponent> iterator = this.iterator(true);
                        while (iterator.hasNext()) {
                                iterator.next().componentChanged(e);
                        }
-                       
+
                        // Notify all listeners
                        Object[] listeners = listenerList.getListenerList();
                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
@@ -429,13 +419,13 @@ public class Rocket extends RocketComponent {
                        mutex.unlock("fireComponentChangeEvent");
                }
        }
-       
-       
+
+
        /**
         * Freezes the rocket structure from firing any events.  This may be performed to
         * combine several actions on the structure into a single large action.
         * <code>thaw()</code> must always be called afterwards.
-        * 
+        *
         * NOTE:  Always use a try/finally to ensure <code>thaw()</code> is called:
         * <pre>
         *     Rocket r = c.getRocket();
@@ -446,7 +436,7 @@ public class Rocket extends RocketComponent {
         *         r.thaw();
         *     }
         * </pre>
-        * 
+        *
         * @see #thaw()
         */
        public void freeze() {
@@ -459,7 +449,7 @@ public class Rocket extends RocketComponent {
                                        "freezeList=" + freezeList);
                }
        }
-       
+
        /**
         * Thaws a frozen rocket structure and fires a combination of the events fired during
         * the freeze.  The event type is a combination of those fired and the source is the
@@ -478,9 +468,9 @@ public class Rocket extends RocketComponent {
                        freezeList = null;
                        return;
                }
-               
+
                log.debug("Thawing rocket, freezeList=" + freezeList);
-               
+
                int type = 0;
                Object c = null;
                for (ComponentChangeEvent e : freezeList) {
@@ -488,44 +478,44 @@ public class Rocket extends RocketComponent {
                        c = e.getSource();
                }
                freezeList = null;
-               
+
                fireComponentChangeEvent(new ComponentChangeEvent((RocketComponent) c, type));
        }
-       
-       
+
+
 
 
        ////////  Motor configurations  ////////
-       
+
 
        /**
         * Return the default configuration.  This should be used in the user interface
         * to ensure a consistent rocket configuration between dialogs.  It should NOT
         * be used in simulations not relating to the UI.
-        * 
+        *
         * @return   the default {@link Configuration}.
         */
        public Configuration getDefaultConfiguration() {
                checkState();
                return defaultConfiguration;
        }
-       
-       
+
+
        /**
         * Return an array of the motor configuration IDs.  This array is guaranteed
         * to contain the <code>null</code> ID as the first element.
-        * 
+        *
         * @return  an array of the motor configuration IDs.
         */
        public String[] getMotorConfigurationIDs() {
                checkState();
                return motorConfigurationIDs.toArray(new String[0]);
        }
-       
+
        /**
         * Add a new motor configuration ID to the motor configurations.  The new ID
         * is returned.
-        * 
+        *
         * @return  the new motor configuration ID.
         */
        public String newMotorConfigurationID() {
@@ -535,10 +525,10 @@ public class Rocket extends RocketComponent {
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
                return id;
        }
-       
+
        /**
         * Add a specified motor configuration ID to the motor configurations.
-        * 
+        *
         * @param id    the motor configuration ID.
         * @return              true if successful, false if the ID was already used.
         */
@@ -550,11 +540,11 @@ public class Rocket extends RocketComponent {
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
                return true;
        }
-       
+
        /**
         * Remove a motor configuration ID from the configuration IDs.  The <code>null</code>
         * ID cannot be removed, and an attempt to remove it will be silently ignored.
-        * 
+        *
         * @param id   the motor configuration ID to remove
         */
        public void removeMotorConfigurationID(String id) {
@@ -564,11 +554,11 @@ public class Rocket extends RocketComponent {
                motorConfigurationIDs.remove(id);
                fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
        }
-       
-       
+
+
        /**
         * Check whether <code>id</code> is a valid motor configuration ID.
-        * 
+        *
         * @param id    the configuration ID.
         * @return              whether a motor configuration with that ID exists.
         */
@@ -576,12 +566,12 @@ public class Rocket extends RocketComponent {
                checkState();
                return motorConfigurationIDs.contains(id);
        }
-       
-       
+
+
 
        /**
         * Check whether the given motor configuration ID has motors defined for it.
-        * 
+        *
         * @param id    the motor configuration ID (may be invalid).
         * @return              whether any motors are defined for it.
         */
@@ -589,11 +579,11 @@ public class Rocket extends RocketComponent {
                checkState();
                if (id == null)
                        return false;
-               
+
                Iterator<RocketComponent> iterator = this.iterator();
                while (iterator.hasNext()) {
                        RocketComponent c = iterator.next();
-                       
+
                        if (c instanceof MotorMount) {
                                MotorMount mount = (MotorMount) c;
                                if (!mount.isMotorMount())
@@ -605,12 +595,12 @@ public class Rocket extends RocketComponent {
                }
                return false;
        }
-       
-       
+
+
        /**
         * Return the user-set name of the motor configuration.  If no name has been set,
         * returns an empty string (not null).
-        *  
+        *
         * @param id   the motor configuration id
         * @return         the configuration name
         */
@@ -623,12 +613,12 @@ public class Rocket extends RocketComponent {
                        return "";
                return s;
        }
-       
-       
+
+
        /**
         * Set the name of the motor configuration.  A name can be unset by passing
         * <code>null</code> or an empty string.
-        * 
+        *
         * @param id    the motor configuration id
         * @param name  the name for the motor configuration
         */
@@ -637,29 +627,29 @@ public class Rocket extends RocketComponent {
                motorConfigurationNames.put(id, name);
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        /**
-        * Return either the motor configuration name (if set) or its description. 
-        * 
+        * Return either the motor configuration name (if set) or its description.
+        *
         * @param id  the motor configuration ID.
         * @return    a textual representation of the configuration
         */
        public String getMotorConfigurationNameOrDescription(String id) {
                checkState();
                String name;
-               
+
                name = getMotorConfigurationName(id);
                if (name != null && !name.equals(""))
                        return name;
-               
+
                return getMotorConfigurationDescription(id);
        }
-       
+
        /**
-        * Return a description for the motor configuration, generated from the motor 
+        * Return a description for the motor configuration, generated from the motor
         * designations of the components.
-        * 
+        *
         * @param id  the motor configuration ID.
         * @return    a textual representation of the configuration
         */
@@ -668,59 +658,59 @@ public class Rocket extends RocketComponent {
                checkState();
                String name;
                int motorCount = 0;
-               
+
                // Generate the description
-               
+
                // First iterate over each stage and store the designations of each motor
                List<List<String>> list = new ArrayList<List<String>>();
                List<String> currentList = null;
-               
+
                Iterator<RocketComponent> iterator = this.iterator();
                while (iterator.hasNext()) {
                        RocketComponent c = iterator.next();
-                       
+
                        if (c instanceof Stage) {
-                               
+
                                currentList = new ArrayList<String>();
                                list.add(currentList);
-                               
+
                        } else if (c instanceof MotorMount) {
-                               
+
                                MotorMount mount = (MotorMount) c;
                                Motor motor = mount.getMotor(id);
-                               
+
                                if (mount.isMotorMount() && motor != null) {
                                        String designation = motor.getDesignation(mount.getMotorDelay(id));
-                                       
+
                                        for (int i = 0; i < mount.getMotorCount(); i++) {
                                                currentList.add(designation);
                                                motorCount++;
                                        }
                                }
-                               
+
                        }
                }
-               
+
                if (motorCount == 0) {
                        return "[No motors]";
                }
-               
-               // Change multiple occurrences of a motor to n x motor 
+
+               // Change multiple occurrences of a motor to n x motor
                List<String> stages = new ArrayList<String>();
-               
+
                for (List<String> stage : list) {
                        String stageName = "";
                        String previous = null;
                        int count = 0;
-                       
+
                        Collections.sort(stage);
                        for (String current : stage) {
                                if (current.equals(previous)) {
-                                       
+
                                        count++;
-                                       
+
                                } else {
-                                       
+
                                        if (previous != null) {
                                                String s = "";
                                                if (count > 1) {
@@ -728,16 +718,16 @@ public class Rocket extends RocketComponent {
                                                } else {
                                                        s = previous;
                                                }
-                                               
+
                                                if (stageName.equals(""))
                                                        stageName = s;
                                                else
                                                        stageName = stageName + "," + s;
                                        }
-                                       
+
                                        previous = current;
                                        count = 1;
-                                       
+
                                }
                        }
                        if (previous != null) {
@@ -747,16 +737,16 @@ public class Rocket extends RocketComponent {
                                } else {
                                        s = previous;
                                }
-                               
+
                                if (stageName.equals(""))
                                        stageName = s;
                                else
                                        stageName = stageName + "," + s;
                        }
-                       
+
                        stages.add(stageName);
                }
-               
+
                name = "[";
                for (int i = 0; i < stages.size(); i++) {
                        String s = stages.get(i);
@@ -770,57 +760,57 @@ public class Rocket extends RocketComponent {
                name += "]";
                return name;
        }
-       
-       
+
+
 
        ////////  Obligatory component information
-       
+
 
        @Override
        public String getComponentName() {
                return "Rocket";
        }
-       
+
        @Override
        public Coordinate getComponentCG() {
                return new Coordinate(0, 0, 0, 0);
        }
-       
+
        @Override
        public double getComponentMass() {
                return 0;
        }
-       
+
        @Override
        public double getLongitudinalUnitInertia() {
                return 0;
        }
-       
+
        @Override
        public double getRotationalUnitInertia() {
                return 0;
        }
-       
+
        @Override
        public Collection<Coordinate> getComponentBounds() {
                return Collections.emptyList();
        }
-       
+
        @Override
        public boolean isAerodynamic() {
                return false;
        }
-       
+
        @Override
        public boolean isMassive() {
                return false;
        }
-       
+
        @Override
        public boolean allowsChildren() {
                return true;
        }
-       
+
        /**
         * Allows only <code>Stage</code> components to be added to the type Rocket.
         */
@@ -828,14 +818,5 @@ public class Rocket extends RocketComponent {
        public boolean isCompatible(Class<? extends RocketComponent> type) {
                return (Stage.class.isAssignableFrom(type));
        }
-       
-       /**
-        * Accept a visitor to this Rocket in the component hierarchy.
-        * 
-        * @param theVisitor  the visitor that will be called back with a reference to this Rocket
-        */
-       @Override
-       public void accept(final ComponentVisitor theVisitor) {
-               theVisitor.visit(this);
-       }
+
 }
index 8573caa67f9b019ca8bbc4a5d6d41a2ef9b01fb8..e109f6b389abdb4f0a57248e72a847d4938df140 100644 (file)
@@ -1,32 +1,19 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.awt.Color;
-import java.util.ArrayDeque;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import javax.swing.event.ChangeListener;
-
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
-import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.ChangeSource;
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.Invalidator;
-import net.sf.openrocket.util.LineStyle;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.SafetyMutex;
-import net.sf.openrocket.util.UniqueID;
-
-
-public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent>,
-               Visitable<ComponentVisitor, RocketComponent> {
+import net.sf.openrocket.util.*;
+
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+
+public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> {
        private static final LogHelper log = Application.getLogger();
-       
+
        /*
         * Text is suitable to the form
         *    Position relative to:  <title>
@@ -42,38 +29,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                AFTER("After the parent component"),
                /** Specify an absolute X-coordinate position. */
                ABSOLUTE("Tip of the nose cone");
-               
+
                private String title;
-               
+
                Position(String title) {
                        this.title = title;
                }
-               
+
                @Override
                public String toString() {
                        return title;
                }
        }
-       
+
        /**
         * A safety mutex that can be used to prevent concurrent access to this component.
         */
        protected SafetyMutex mutex = SafetyMutex.newInstance();
-       
+
        ////////  Parent/child trees
        /**
         * Parent component of the current component, or null if none exists.
         */
        private RocketComponent parent = null;
-       
+
        /**
         * List of child components of this component.
         */
        private ArrayList<RocketComponent> children = new ArrayList<RocketComponent>();
-       
+
 
        ////////  Parameters common to all components:
-       
+
        /**
         * Characteristic length of the component.  This is used in calculating the coordinate
         * transformations and positions of other components in reference to this component.
@@ -81,50 +68,50 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * By default it is zero, i.e. no translation.
         */
        protected double length = 0;
-       
+
        /**
         * Positioning of this component relative to the parent component.
         */
        protected Position relativePosition;
-       
+
        /**
         * Offset of the position of this component relative to the normal position given by
         * relativePosition.  By default zero, i.e. no position change.
         */
        protected double position = 0;
-       
+
 
        // Color of the component, null means to use the default color
        private Color color = null;
        private LineStyle lineStyle = null;
-       
+
 
        // Override mass/CG
        private double overrideMass = 0;
        private boolean massOverriden = false;
        private double overrideCGX = 0;
        private boolean cgOverriden = false;
-       
+
        private boolean overrideSubcomponents = false;
-       
+
 
        // User-given name of the component
        private String name = null;
-       
+
        // User-specified comment
        private String comment = "";
-       
+
        // Unique ID of the component
        private String id = null;
-       
+
        /**
         * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}.
         */
        private Invalidator invalidator = new Invalidator(this);
-       
-       
+
+
        ////  NOTE !!!  All fields must be copied in the method copyFrom()!  ////
-       
+
 
 
        /**
@@ -137,74 +124,74 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.relativePosition = relativePosition;
                newID();
        }
-       
+
        ////////////  Methods that must be implemented  ////////////
-       
+
 
        /**
         * Static component name.  The name may not vary of the parameters, it must be static.
         */
        public abstract String getComponentName(); // Static component type name
-       
+
        /**
         * Return the component mass (regardless of mass overriding).
         */
        public abstract double getComponentMass(); // Mass of non-overridden component
-       
+
        /**
         * Return the component CG and mass (regardless of CG or mass overriding).
         */
        public abstract Coordinate getComponentCG(); // CG of non-overridden component
-       
+
 
        /**
-        * Return the longitudinal (around the y- or z-axis) unitary moment of inertia.  
+        * Return the longitudinal (around the y- or z-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
         * the mass of the component is one kilogram.  The inertia is measured in
         * respect to the non-overridden CG.
-        * 
+        *
         * @return   the longitudinal unitary moment of inertia of this component.
         */
        public abstract double getLongitudinalUnitInertia();
-       
-       
+
+
        /**
-        * Return the rotational (around the x-axis) unitary moment of inertia.  
+        * Return the rotational (around the x-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
         * the mass of the component is one kilogram.  The inertia is measured in
         * respect to the non-overridden CG.
-        * 
+        *
         * @return   the rotational unitary moment of inertia of this component.
         */
        public abstract double getRotationalUnitInertia();
-       
-       
+
+
        /**
         * Test whether this component allows any children components.  This method must
         * return true if and only if {@link #isCompatible(Class)} returns true for any
         * rocket component class.
-        * 
+        *
         * @return      <code>true</code> if children can be attached to this component, <code>false</code> otherwise.
         */
        public abstract boolean allowsChildren();
-       
+
        /**
         * Test whether the given component type can be added to this component.  This type safety
         * is enforced by the <code>addChild()</code> methods.  The return value of this method
         * may change to reflect the current state of this component (e.g. two components of some
         * type cannot be placed as children).
-        * 
+        *
         * @param type  The RocketComponent class type to add.
         * @return      Whether such a component can be added.
         */
        public abstract boolean isCompatible(Class<? extends RocketComponent> type);
-       
-       
+
+
        /* Non-abstract helper method */
        /**
         * Test whether the given component can be added to this component.  This is equivalent
         * to calling <code>isCompatible(c.getClass())</code>.
-        * 
+        *
         * @param c  Component to test.
         * @return   Whether the component can be added.
         * @see #isCompatible(Class)
@@ -213,33 +200,33 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return isCompatible(c.getClass());
        }
-       
-       
+
+
 
        /**
         * Return a collection of bounding coordinates.  The coordinates must be such that
         * the component is fully enclosed in their convex hull.
-        * 
+        *
         * @return      a collection of coordinates that bound the component.
         */
        public abstract Collection<Coordinate> getComponentBounds();
-       
+
        /**
         * Return true if the component may have an aerodynamic effect on the rocket.
         */
        public abstract boolean isAerodynamic();
-       
+
        /**
         * Return true if the component may have an effect on the rocket's mass.
         */
        public abstract boolean isMassive();
-       
-       
+
+
 
 
 
        ////////////  Methods that may be overridden  ////////////
-       
+
 
        /**
         * Shift the coordinates in the array corresponding to radial movement.  A component
@@ -248,7 +235,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * coordinate for each cluster.
         * <p>
         * The default implementation simply returns the array, and thus produces no shift.
-        * 
+        *
         * @param c   an array of coordinates to shift.
         * @return    an array of shifted coordinates.  The method may modify the contents
         *                        of the passed array and return the array itself.
@@ -257,28 +244,28 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return c;
        }
-       
-       
+
+
        /**
-        * Called when any component in the tree fires a ComponentChangeEvent.  This is by 
-        * default a no-op, but subclasses may override this method to e.g. invalidate 
-        * cached data.  The overriding method *must* call 
+        * Called when any component in the tree fires a ComponentChangeEvent.  This is by
+        * default a no-op, but subclasses may override this method to e.g. invalidate
+        * cached data.  The overriding method *must* call
         * <code>super.componentChanged(e)</code> at some point.
-        * 
+        *
         * @param e  The event fired
         */
        protected void componentChanged(ComponentChangeEvent e) {
                // No-op
                checkState();
        }
-       
-       
+
+
 
 
        /**
         * Return the user-provided name of the component, or the component base
         * name if the user-provided name is empty.  This can be used in the UI.
-        * 
+        *
         * @return A string describing the component.
         */
        @Override
@@ -289,8 +276,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        return name;
        }
-       
-       
+
+
        /**
         * Create a string describing the basic component structure from this component downwards.
         * @return      a string containing the rocket structure
@@ -305,7 +292,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("toDebugString");
                }
        }
-       
+
        private void toDebugString(StringBuilder sb) {
                sb.append(this.getClass().getSimpleName()).append('@').append(System.identityHashCode(this));
                sb.append("[\"").append(this.getName()).append('"');
@@ -315,26 +302,26 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                sb.append(']');
        }
-       
-       
+
+
        /**
         * Make a deep copy of the rocket component tree structure from this component
         * downwards for copying purposes.  Each component in the copy will be assigned
         * a new component ID, making it a safe copy.  This method does not fire any events.
-        * 
+        *
         * @return A deep copy of the structure.
         */
        public final RocketComponent copy() {
                RocketComponent clone = copyWithOriginalID();
-               
+
                Iterator<RocketComponent> iterator = clone.iterator(true);
                while (iterator.hasNext()) {
                        iterator.next().newID();
                }
                return clone;
        }
-       
-       
+
+
 
        /**
         * Make a deep copy of the rocket component tree structure from this component
@@ -343,13 +330,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * undo/redo mechanism.  This method should not be used for other purposes,
         * such as copy/paste.  This method does not fire any events.
         * <p>
-        * This method must be overridden by any component that refers to mutable objects, 
+        * This method must be overridden by any component that refers to mutable objects,
         * or if some fields should not be copied.  This should be performed by
         * <code>RocketComponent c = super.copyWithOriginalID();</code> and then cloning/modifying
         * the appropriate fields.
         * <p>
         * This is not performed as serializing/deserializing for performance reasons.
-        * 
+        *
         * @return A deep copy of the structure.
         */
        protected RocketComponent copyWithOriginalID() {
@@ -362,14 +349,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        } catch (CloneNotSupportedException e) {
                                throw new BugException("CloneNotSupportedException encountered, report a bug!", e);
                        }
-                       
+
                        // Reset the mutex
                        clone.mutex = SafetyMutex.newInstance();
-                       
+
                        // Reset all parent/child information
                        clone.parent = null;
                        clone.children = new ArrayList<RocketComponent>();
-                       
+
                        // Add copied children to the structure without firing events.
                        for (RocketComponent child : this.children) {
                                RocketComponent childCopy = child.copyWithOriginalID();
@@ -377,33 +364,23 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                clone.children.add(childCopy);
                                childCopy.parent = clone;
                        }
-                       
+
                        this.checkComponentStructure();
                        clone.checkComponentStructure();
-                       
+
                        return clone;
                } finally {
                        mutex.unlock("copyWithOriginalID");
                }
        }
-       
-       
-       /**
-        * Accept a visitor to this RocketComponent in the component hierarchy.
-        * 
-        * @param theVisitor  the visitor that will be called back with a reference to this RocketComponent
-        */
-       @Override
-       public void accept(final ComponentVisitor theVisitor) {
-               theVisitor.visit(this);
-       }
-       
+
+
        //////////////  Methods that may not be overridden  ////////////
-       
+
 
 
        ////////// Common parameter setting/getting //////////
-       
+
        /**
         * Return the color of the object to use in 2D figures, or <code>null</code>
         * to use the default color.
@@ -412,26 +389,26 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return color;
        }
-       
+
        /**
-        * Set the color of the object to use in 2D figures.  
+        * Set the color of the object to use in 2D figures.
         */
        public final void setColor(Color c) {
                if ((color == null && c == null) ||
                                (color != null && color.equals(c)))
                        return;
-               
+
                checkState();
                this.color = c;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        public final LineStyle getLineStyle() {
                mutex.verify();
                return lineStyle;
        }
-       
+
        public final void setLineStyle(LineStyle style) {
                if (this.lineStyle == style)
                        return;
@@ -439,25 +416,25 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.lineStyle = style;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
 
 
        /**
         * Get the current override mass.  The mass is not necessarily in use
         * at the moment.
-        * 
+        *
         * @return  the override mass
         */
        public final double getOverrideMass() {
                mutex.verify();
                return overrideMass;
        }
-       
+
        /**
         * Set the current override mass.  The mass is not set to use by this
         * method.
-        * 
+        *
         * @param m  the override mass
         */
        public final void setOverrideMass(double m) {
@@ -468,21 +445,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (massOverriden)
                        fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        /**
         * Return whether mass override is active for this component.  This does NOT
         * take into account whether a parent component is overriding the mass.
-        * 
+        *
         * @return  whether the mass is overridden
         */
        public final boolean isMassOverridden() {
                mutex.verify();
                return massOverriden;
        }
-       
+
        /**
         * Set whether the mass is currently overridden.
-        * 
+        *
         * @param o  whether the mass is overridden
         */
        public final void setMassOverridden(boolean o) {
@@ -493,34 +470,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                massOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
 
 
        /**
         * Return the current override CG.  The CG is not necessarily overridden.
-        * 
+        *
         * @return  the override CG
         */
        public final Coordinate getOverrideCG() {
                mutex.verify();
                return getComponentCG().setX(overrideCGX);
        }
-       
+
        /**
         * Return the x-coordinate of the current override CG.
-        * 
+        *
         * @return      the x-coordinate of the override CG.
         */
        public final double getOverrideCGX() {
                mutex.verify();
                return overrideCGX;
        }
-       
+
        /**
         * Set the current override CG to (x,0,0).
-        * 
+        *
         * @param x  the x-coordinate of the override CG to set.
         */
        public final void setOverrideCGX(double x) {
@@ -533,20 +510,20 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
+
        /**
         * Return whether the CG is currently overridden.
-        * 
+        *
         * @return  whether the CG is overridden
         */
        public final boolean isCGOverridden() {
                mutex.verify();
                return cgOverriden;
        }
-       
+
        /**
         * Set whether the CG is currently overridden.
-        * 
+        *
         * @param o  whether the CG is overridden
         */
        public final void setCGOverridden(boolean o) {
@@ -557,8 +534,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                cgOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
        /**
         * Return whether the mass and/or CG override overrides all subcomponent values
@@ -567,19 +544,19 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * always or never overrides subcomponents.  In this case the subclass should
         * also override {@link #isOverrideSubcomponentsEnabled()} to return
         * <code>false</code>.
-        * 
+        *
         * @return      whether the current mass and/or CG override overrides subcomponents as well.
         */
        public boolean getOverrideSubcomponents() {
                mutex.verify();
                return overrideSubcomponents;
        }
-       
-       
+
+
        /**
         * Set whether the mass and/or CG override overrides all subcomponent values
         * as well.  See {@link #getOverrideSubcomponents()} for details.
-        * 
+        *
         * @param override      whether the mass and/or CG override overrides all subcomponent.
         */
        public void setOverrideSubcomponents(boolean override) {
@@ -590,7 +567,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                overrideSubcomponents = override;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        /**
         * Return whether the option to override all subcomponents is enabled or not.
         * The default implementation returns <code>false</code> if neither mass nor
@@ -598,15 +575,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * <p>
         * This method may be overridden if the setting of overriding subcomponents
         * cannot be set.
-        * 
+        *
         * @return      whether the option to override subcomponents is currently enabled.
         */
        public boolean isOverrideSubcomponentsEnabled() {
                mutex.verify();
                return isCGOverridden() || isMassOverridden();
        }
-       
-       
+
+
 
 
        /**
@@ -616,7 +593,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return name;
        }
-       
+
        /**
         * Set the user-defined name of the component.  If name==null, sets the name to
         * the default name, currently the component name.
@@ -632,22 +609,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.name = name;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        /**
         * Return the comment of the component.  The component may contain multiple lines
         * using \n as a newline separator.
-        * 
+        *
         * @return  the comment of the component.
         */
        public final String getComment() {
                mutex.verify();
                return comment;
        }
-       
+
        /**
         * Set the comment of the component.
-        * 
+        *
         * @param comment  the comment of the component.
         */
        public final void setComment(String comment) {
@@ -660,18 +637,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.comment = comment;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
 
        /**
         * Returns the unique ID of the component.
-        * 
+        *
         * @return      the ID of the component.
         */
        public final String getID() {
                return id;
        }
-       
+
        /**
         * Generate a new ID for this component.
         */
@@ -679,15 +656,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                this.id = UniqueID.uuid();
        }
-       
-       
+
+
 
 
        /**
         * Get the characteristic length of the component, for example the length of a body tube
         * of the length of the root chord of a fin.  This is used in positioning the component
         * relative to its parent.
-        * 
+        *
         * If the length of a component is settable, the class must define the setter method
         * itself.
         */
@@ -695,7 +672,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return length;
        }
-       
+
        /**
         * Get the positioning of the component relative to its parent component.
         * This is one of the enums of {@link Position}.  A setter method is not provided,
@@ -705,8 +682,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return relativePosition;
        }
-       
-       
+
+
        /**
         * Set the positioning of the component relative to its parent component.
         * The actual position of the component is maintained to the best ability.
@@ -715,59 +692,59 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * do not support setting the relative position.  A component that does support
         * it should override this with a public method that simply calls this
         * supermethod AND fire a suitable ComponentChangeEvent.
-        * 
+        *
         * @param position      the relative positioning.
         */
        protected void setRelativePosition(RocketComponent.Position position) {
                if (this.relativePosition == position)
                        return;
                checkState();
-               
+
                // Update position so as not to move the component
                if (this.parent != null) {
                        double thisPos = this.toRelative(Coordinate.NUL, this.parent)[0].x;
-                       
+
                        switch (position) {
                        case ABSOLUTE:
                                this.position = this.toAbsolute(Coordinate.NUL)[0].x;
                                break;
-                       
+
                        case TOP:
                                this.position = thisPos;
                                break;
-                       
+
                        case MIDDLE:
                                this.position = thisPos - (this.parent.length - this.length) / 2;
                                break;
-                       
+
                        case BOTTOM:
                                this.position = thisPos - (this.parent.length - this.length);
                                break;
-                       
+
                        default:
                                throw new BugException("Unknown position type: " + position);
                        }
                }
-               
+
                this.relativePosition = position;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
 
        /**
         * Get the position value of the component.  The exact meaning of the value is
         * dependent on the current relative positioning.
-        * 
+        *
         * @return  the positional value.
         */
        public final double getPositionValue() {
                mutex.verify();
                return position;
        }
-       
-       
+
+
        /**
         * Set the position value of the component.  The exact meaning of the value
         * depends on the current relative positioning.
@@ -776,7 +753,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * do not support setting the relative position.  A component that does support
         * it should override this with a public method that simply calls this
         * supermethod AND fire a suitable ComponentChangeEvent.
-        * 
+        *
         * @param value         the position value of the component.
         */
        public void setPositionValue(double value) {
@@ -785,11 +762,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                this.position = value;
        }
-       
-       
+
+
 
        ///////////  Coordinate changes  ///////////
-       
+
        /**
         * Returns coordinate c in absolute coordinates.  Equivalent to toComponent(c,null).
         */
@@ -797,19 +774,19 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return toRelative(c, null);
        }
-       
-       
+
+
        /**
-        * Return coordinate <code>c</code> described in the coordinate system of 
+        * Return coordinate <code>c</code> described in the coordinate system of
         * <code>dest</code>.  If <code>dest</code> is <code>null</code> returns
         * absolute coordinates.
         * <p>
         * This method returns an array of coordinates, each of which represents a
         * position of the coordinate in clustered cases.  The array is guaranteed
-        * to contain at least one element.  
+        * to contain at least one element.
         * <p>
         * The current implementation does not support rotating components.
-        * 
+        *
         * @param c    Coordinate in the component's coordinate system.
         * @param dest Destination component coordinate system.
         * @return     an array of coordinates describing <code>c</code> in coordinates
@@ -823,33 +800,33 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        RocketComponent search = dest;
                        Coordinate[] array = new Coordinate[1];
                        array[0] = c;
-                       
+
                        RocketComponent component = this;
                        while ((component != search) && (component.parent != null)) {
-                               
+
                                array = component.shiftCoordinates(array);
-                               
+
                                switch (component.relativePosition) {
                                case TOP:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position, 0, 0);
                                        }
                                        break;
-                               
+
                                case MIDDLE:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length) / 2, 0, 0);
                                        }
                                        break;
-                               
+
                                case BOTTOM:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length), 0, 0);
                                        }
                                        break;
-                               
+
                                case AFTER:
                                        // Add length of all previous brother-components with POSITION_RELATIVE_AFTER
                                        int index = component.parent.children.indexOf(component);
@@ -865,48 +842,48 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                                array[i] = array[i].add(component.position + component.parent.length, 0, 0);
                                        }
                                        break;
-                               
+
                                case ABSOLUTE:
                                        search = null; // Requires back-search if dest!=null
                                        if (Double.isNaN(absoluteX)) {
                                                absoluteX = component.position;
                                        }
                                        break;
-                               
+
                                default:
                                        throw new BugException("Unknown relative positioning type of component" +
                                                        component + ": " + component.relativePosition);
                                }
-                               
+
                                component = component.parent; // parent != null
                        }
-                       
+
                        if (!Double.isNaN(absoluteX)) {
                                for (int i = 0; i < array.length; i++) {
                                        array[i] = array[i].setX(absoluteX + c.x);
                                }
                        }
-                       
+
                        // Check whether destination has been found or whether to backtrack
-                       // TODO: LOW: Backtracking into clustered components uses only one component 
+                       // TODO: LOW: Backtracking into clustered components uses only one component
                        if ((dest != null) && (component != dest)) {
                                Coordinate[] origin = dest.toAbsolute(Coordinate.NUL);
                                for (int i = 0; i < array.length; i++) {
                                        array[i] = array[i].sub(origin[0]);
                                }
                        }
-                       
+
                        return array;
                } finally {
                        mutex.unlock("toRelative");
                }
        }
-       
-       
+
+
        /**
-        * Recursively sum the lengths of all subcomponents that have position 
+        * Recursively sum the lengths of all subcomponents that have position
         * Position.AFTER.
-        * 
+        *
         * @return  Sum of the lengths.
         */
        private final double getTotalLength() {
@@ -924,14 +901,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("getTotalLength");
                }
        }
-       
-       
+
+
 
        /////////// Total mass and CG calculation ////////////
-       
+
        /**
         * Return the (possibly overridden) mass of component.
-        * 
+        *
         * @return The mass of the component or the given override mass.
         */
        public final double getMass() {
@@ -940,63 +917,63 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        return overrideMass;
                return getComponentMass();
        }
-       
+
        /**
         * Return the (possibly overridden) center of gravity and mass.
-        * 
+        *
         * Returns the CG with the weight of the coordinate set to the weight of the component.
         * Both CG and mass may be separately overridden.
-        * 
+        *
         * @return The CG of the component or the given override CG.
         */
        public final Coordinate getCG() {
                checkState();
                if (cgOverriden)
                        return getOverrideCG().setWeight(getMass());
-               
+
                if (massOverriden)
                        return getComponentCG().setWeight(getMass());
-               
+
                return getComponentCG();
        }
-       
-       
+
+
        /**
         * Return the longitudinal (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
         * and is relative to the non-overridden CG.
-        * 
+        *
         * @return    the longitudinal moment of inertia of this component.
         */
        public final double getLongitudinalInertia() {
                checkState();
                return getLongitudinalUnitInertia() * getMass();
        }
-       
+
        /**
         * Return the rotational (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
         * and is relative to the non-overridden CG.
-        * 
+        *
         * @return    the rotational moment of inertia of this component.
         */
        public final double getRotationalInertia() {
                checkState();
                return getRotationalUnitInertia() * getMass();
        }
-       
-       
+
+
 
        ///////////  Children handling  ///////////
-       
+
 
        /**
         * Adds a child to the rocket component tree.  The component is added to the end
-        * of the component's child list.  This is a helper method that calls 
+        * of the component's child list.  This is a helper method that calls
         * {@link #addChild(RocketComponent,int)}.
-        * 
+        *
         * @param component  The component to add.
-        * @throws IllegalArgumentException  if the component is already part of some 
+        * @throws IllegalArgumentException  if the component is already part of some
         *                                                                       component tree.
         * @see #addChild(RocketComponent,int)
         */
@@ -1004,18 +981,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                addChild(component, children.size());
        }
-       
-       
+
+
        /**
-        * Adds a child to the rocket component tree.  The component is added to 
+        * Adds a child to the rocket component tree.  The component is added to
         * the given position of the component's child list.
         * <p>
-        * This method may be overridden to enforce more strict component addition rules.  
+        * This method may be overridden to enforce more strict component addition rules.
         * The tests should be performed first and then this method called.
-        * 
+        *
         * @param component     The component to add.
         * @param index         Position to add component to.
-        * @throws IllegalArgumentException  If the component is already part of 
+        * @throws IllegalArgumentException  If the component is already part of
         *                                                                       some component tree.
         */
        public void addChild(RocketComponent component, int index) {
@@ -1028,20 +1005,20 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        throw new IllegalStateException("Component " + component.getComponentName() +
                                        " not currently compatible with component " + getComponentName());
                }
-               
+
                children.add(index, component);
                component.parent = this;
-               
+
                this.checkComponentStructure();
                component.checkComponentStructure();
-               
+
                fireAddRemoveEvent(component);
        }
-       
-       
+
+
        /**
         * Removes a child from the rocket component tree.
-        * 
+        *
         * @param n  remove the n'th child.
         * @throws IndexOutOfBoundsException  if n is out of bounds
         */
@@ -1049,43 +1026,43 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                RocketComponent component = children.remove(n);
                component.parent = null;
-               
+
                this.checkComponentStructure();
                component.checkComponentStructure();
-               
+
                fireAddRemoveEvent(component);
        }
-       
+
        /**
         * Removes a child from the rocket component tree.  Does nothing if the component
         * is not present as a child.
-        * 
+        *
         * @param component             the component to remove
         * @return                              whether the component was a child
         */
        public final boolean removeChild(RocketComponent component) {
                checkState();
-               
+
                component.checkComponentStructure();
-               
+
                if (children.remove(component)) {
                        component.parent = null;
-                       
+
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-                       
+
                        fireAddRemoveEvent(component);
                        return true;
                }
                return false;
        }
-       
-       
+
+
 
 
        /**
         * Move a child to another position.
-        * 
+        *
         * @param component     the component to move
         * @param index the component's new position
         * @throws IllegalArgumentException If an illegal placement was attempted.
@@ -1094,15 +1071,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                if (children.remove(component)) {
                        children.add(index, component);
-                       
+
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-                       
+
                        fireAddRemoveEvent(component);
                }
        }
-       
-       
+
+
        /**
         * Fires an AERODYNAMIC_CHANGE, MASS_CHANGE or OTHER_CHANGE event depending on the
         * type of component removed.
@@ -1117,34 +1094,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        if (c.isMassive())
                                type |= ComponentChangeEvent.MASS_CHANGE;
                }
-               
+
                fireComponentChangeEvent(type);
        }
-       
-       
+
+
        public final int getChildCount() {
                checkState();
                this.checkComponentStructure();
                return children.size();
        }
-       
+
        public final RocketComponent getChild(int n) {
                checkState();
                this.checkComponentStructure();
                return children.get(n);
        }
-       
+
        public final List<RocketComponent> getChildren() {
                checkState();
                this.checkComponentStructure();
                return children.clone();
        }
-       
-       
+
+
        /**
         * Returns the position of the child in this components child list, or -1 if the
         * component is not a child of this component.
-        * 
+        *
         * @param child  The child to search for.
         * @return  Position in the list or -1 if not found.
         */
@@ -1153,21 +1130,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.checkComponentStructure();
                return children.indexOf(child);
        }
-       
+
        /**
         * Get the parent component of this component.  Returns <code>null</code> if the component
         * has no parent.
-        * 
+        *
         * @return  The parent of this component or <code>null</code>.
         */
        public final RocketComponent getParent() {
                checkState();
                return parent;
        }
-       
+
        /**
         * Get the root component of the component tree.
-        * 
+        *
         * @return  The root component of the component tree.
         */
        public final RocketComponent getRoot() {
@@ -1177,11 +1154,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        gp = gp.parent;
                return gp;
        }
-       
+
        /**
-        * Returns the root Rocket component of this component tree.  Throws an 
+        * Returns the root Rocket component of this component tree.  Throws an
         * IllegalStateException if the root component is not a Rocket.
-        * 
+        *
         * @return  The root Rocket component of the component tree.
         * @throws  IllegalStateException  If the root component is not a Rocket.
         */
@@ -1193,12 +1170,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                throw new IllegalStateException("getRocket() called with root component "
                                + r.getComponentName());
        }
-       
-       
+
+
        /**
         * Return the Stage component that this component belongs to.  Throws an
         * IllegalStateException if a Stage is not in the parentage of this component.
-        * 
+        *
         * @return      The Stage component this component belongs to.
         * @throws      IllegalStateException   if a Stage component is not in the parentage.
         */
@@ -1212,11 +1189,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                throw new IllegalStateException("getStage() called without Stage as a parent.");
        }
-       
+
        /**
         * Return the stage number of the stage this component belongs to.  The stages
         * are numbered from zero upwards.
-        * 
+        *
         * @return   the stage number this component belongs to.
         */
        public final int getStageNumber() {
@@ -1224,7 +1201,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (parent == null) {
                        throw new IllegalArgumentException("getStageNumber() called for root component");
                }
-               
+
                RocketComponent stage = this;
                while (!(stage instanceof Stage)) {
                        stage = stage.parent;
@@ -1235,13 +1212,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return stage.parent.getChildPosition(stage);
        }
-       
-       
+
+
        /**
         * Find a component with the given ID.  The component tree is searched from this component
         * down (including this component) for the ID and the corresponding component is returned,
         * or null if not found.
-        * 
+        *
         * @param idToFind  ID to search for.
         * @return    The component with the ID, or null if not found.
         */
@@ -1255,8 +1232,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return null;
        }
-       
-       
+
+
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getPreviousComponent() {
                checkState();
@@ -1287,52 +1264,52 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        c = c.getChild(c.getChildCount() - 1);
                return c;
        }
-       
+
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getNextComponent() {
                checkState();
                if (getChildCount() > 0)
                        return getChild(0);
-               
+
                RocketComponent current = this;
                RocketComponent nextParent = this.parent;
-               
+
                while (nextParent != null) {
                        int pos = nextParent.getChildPosition(current);
                        if (pos < nextParent.getChildCount() - 1)
                                return nextParent.getChild(pos + 1);
-                       
+
                        current = nextParent;
                        nextParent = current.parent;
                }
                return null;
        }
-       
-       
+
+
        ///////////  Event handling  //////////
        //
        // Listener lists are provided by the root Rocket component,
        // a single listener list for the whole rocket.
        //
-       
+
        /**
         * Adds a ComponentChangeListener to the rocket tree.  The listener is added to the root
         * component, which must be of type Rocket (which overrides this method).  Events of all
         * subcomponents are sent to all listeners.
-        * 
+        *
         * @throws IllegalStateException - if the root component is not a Rocket
         */
        public void addComponentChangeListener(ComponentChangeListener l) {
                checkState();
                getRocket().addComponentChangeListener(l);
        }
-       
+
        /**
         * Removes a ComponentChangeListener from the rocket tree.  The listener is removed from
         * the root component, which must be of type Rocket (which overrides this method).
         * Does nothing if the root component is not a Rocket.  (The asymmetry is so
         * that listeners can always be removed just in case.)
-        * 
+        *
         * @param l  Listener to remove
         */
        public void removeComponentChangeListener(ComponentChangeListener l) {
@@ -1340,15 +1317,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeComponentChangeListener(l);
                }
        }
-       
-       
+
+
        /**
-        * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to 
-        * <code>addComponentChangeListener()</code> except that it uses a 
+        * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to
+        * <code>addComponentChangeListener()</code> except that it uses a
         * <code>ChangeListener</code>.  The same events are dispatched to the
-        * <code>ChangeListener</code>, as <code>ComponentChangeEvent</code> is a subclass 
+        * <code>ChangeListener</code>, as <code>ComponentChangeEvent</code> is a subclass
         * of <code>ChangeEvent</code>.
-        * 
+        *
         * @throws IllegalStateException - if the root component is not a <code>Rocket</code>
         */
        @Override
@@ -1356,13 +1333,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                getRocket().addChangeListener(l);
        }
-       
+
        /**
         * Removes a ChangeListener from the rocket tree.  This is identical to
         * removeComponentChangeListener() except it uses a ChangeListener.
         * Does nothing if the root component is not a Rocket.  (The asymmetry is so
         * that listeners can always be removed just in case.)
-        * 
+        *
         * @param l  Listener to remove
         */
        @Override
@@ -1371,17 +1348,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeChangeListener(l);
                }
        }
-       
-       
+
+
        /**
-        * Fires a ComponentChangeEvent on the rocket structure.  The call is passed to the 
+        * Fires a ComponentChangeEvent on the rocket structure.  The call is passed to the
         * root component, which must be of type Rocket (which overrides this method).
         * Events of all subcomponents are sent to all listeners.
-        * 
-        * If the component tree root is not a Rocket, the event is ignored.  This is the 
-        * case when constructing components not in any Rocket tree.  In this case it 
+        *
+        * If the component tree root is not a Rocket, the event is ignored.  This is the
+        * case when constructing components not in any Rocket tree.  In this case it
         * would be impossible for the component to have listeners in any case.
-        *  
+        *
         * @param e  Event to send
         */
        protected void fireComponentChangeEvent(ComponentChangeEvent e) {
@@ -1393,34 +1370,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                getRoot().fireComponentChangeEvent(e);
        }
-       
-       
+
+
        /**
         * Fires a ComponentChangeEvent of the given type.  The source of the event is set to
         * this component.
-        * 
+        *
         * @param type  Type of event
         * @see #fireComponentChangeEvent(ComponentChangeEvent)
         */
        protected void fireComponentChangeEvent(int type) {
                fireComponentChangeEvent(new ComponentChangeEvent(this, type));
        }
-       
-       
+
+
        /**
         * Checks whether this component has been invalidated and should no longer be used.
         * This is a safety check that in-place replaced components are no longer used.
         * All non-trivial methods (with the exception of methods simply getting a property)
         * should call this method before changing or computing anything.
-        * 
+        *
         * @throws      BugException    if this component has been invalidated by {@link #copyFrom(RocketComponent)}.
         */
        protected void checkState() {
                invalidator.check(true);
                mutex.verify();
        }
-       
-       
+
+
        /**
         * Check that the local component structure is correct.  This can be called after changing
         * the component structure in order to verify the integrity.
@@ -1443,7 +1420,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        }
                }
        }
-       
+
        // Check whether the list contains exactly the searched-for component (with == operator)
        private boolean containsExact(List<RocketComponent> haystack, RocketComponent needle) {
                for (RocketComponent c : haystack) {
@@ -1453,10 +1430,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return false;
        }
-       
-       
+
+
        ///////////  Iterators  //////////
-       
+
        /**
         * Returns an iterator that iterates over all children and sub-children.
         * <p>
@@ -1466,10 +1443,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * <p>
         * If an iterator iterating over only the direct children of the component is required,
         * use <code>component.getChildren().iterator()</code>.
-        * 
+        *
         * TODO: HIGH: Remove this after merges have been done
-        * 
-        * @param returnSelf boolean value specifying whether the component itself should be 
+        *
+        * @param returnSelf boolean value specifying whether the component itself should be
         *                                       returned
         * @return An iterator for the children and sub-children.
         * @deprecated Use {@link #iterator(boolean)} instead
@@ -1478,15 +1455,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator(boolean returnSelf) {
                return iterator(returnSelf);
        }
-       
-       
+
+
        /**
         * Returns an iterator that iterates over all children and sub-children, including itself.
         * <p>
         * This method is equivalent to <code>deepIterator(true)</code>.
-        * 
+        *
         * TODO: HIGH: Remove this after merges have been done
-        * 
+        *
         * @return An iterator for this component, its children and sub-children.
         * @deprecated Use {@link #iterator()} instead
         */
@@ -1494,8 +1471,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator() {
                return iterator();
        }
-       
-       
+
+
 
        /**
         * Returns an iterator that iterates over all children and sub-children.
@@ -1506,8 +1483,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * <p>
         * If an iterator iterating over only the direct children of the component is required,
         * use <code>component.getChildren().iterator()</code>.
-        * 
-        * @param returnSelf boolean value specifying whether the component itself should be 
+        *
+        * @param returnSelf boolean value specifying whether the component itself should be
         *                                       returned
         * @return An iterator for the children and sub-children.
         */
@@ -1515,21 +1492,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return new RocketComponentIterator(this, returnSelf);
        }
-       
-       
+
+
        /**
         * Returns an iterator that iterates over this components, its children and sub-children.
         * <p>
         * This method is equivalent to <code>iterator(true)</code>.
-        * 
+        *
         * @return An iterator for this component, its children and sub-children.
         */
        @Override
        public final Iterator<RocketComponent> iterator() {
                return iterator(true);
        }
-       
-       
+
+
 
 
 
@@ -1548,25 +1525,25 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                RocketComponent other = (RocketComponent) obj;
                return this.id.equals(other.id);
        }
-       
-       
+
+
 
        @Override
        public int hashCode() {
                return id.hashCode();
        }
-       
-       
+
+
 
        ////////////  Helper methods for subclasses
-       
+
 
 
 
        /**
         * Helper method to add rotationally symmetric bounds at the specified coordinates.
         * The X-axis value is <code>x</code> and the radius at the specified position is
-        * <code>r</code>. 
+        * <code>r</code>.
         */
        protected static final void addBound(Collection<Coordinate> bounds, double x, double r) {
                bounds.add(new Coordinate(x, -r, -r));
@@ -1574,36 +1551,36 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                bounds.add(new Coordinate(x, r, r));
                bounds.add(new Coordinate(x, -r, r));
        }
-       
-       
+
+
        protected static final Coordinate ringCG(double outerRadius, double innerRadius,
                        double x1, double x2, double density) {
                return new Coordinate((x1 + x2) / 2, 0, 0,
                                ringMass(outerRadius, innerRadius, x2 - x1, density));
        }
-       
+
        protected static final double ringMass(double outerRadius, double innerRadius,
                        double length, double density) {
                return Math.PI * (MathUtil.pow2(outerRadius) - MathUtil.pow2(innerRadius)) *
                                        length * density;
        }
-       
+
        protected static final double ringLongitudinalUnitInertia(double outerRadius,
                        double innerRadius, double length) {
                // 1/12 * (3 * (r1^2 + r2^2) + h^2)
                return (3 * (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) + MathUtil.pow2(length)) / 12;
        }
-       
+
        protected static final double ringRotationalUnitInertia(double outerRadius,
                        double innerRadius) {
                // 1/2 * (r1^2 + r2^2)
                return (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) / 2;
        }
-       
-       
+
+
 
        ////////////  OTHER
-       
+
 
        /**
         * Loads the RocketComponent fields from the given component.  This method is meant
@@ -1619,40 +1596,40 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * to them have been removed (for example by firing appropriate events).  The list contains
         * all children and sub-children of the current component and the entire component
         * tree of <code>src</code>.
-        * 
+        *
         * @return      a list of components that should not be used after this call.
         */
        protected List<RocketComponent> copyFrom(RocketComponent src) {
                checkState();
                List<RocketComponent> toInvalidate = new ArrayList<RocketComponent>();
-               
+
                if (this.parent != null) {
                        throw new UnsupportedOperationException("copyFrom called for non-root component, parent=" +
                                        this.parent.toDebugString() + ", this=" + this.toDebugString());
                }
-               
+
                // Add current structure to be invalidated
                Iterator<RocketComponent> iterator = this.iterator(false);
                while (iterator.hasNext()) {
                        toInvalidate.add(iterator.next());
                }
-               
+
                // Remove previous components
                for (RocketComponent child : this.children) {
                        child.parent = null;
                }
                this.children.clear();
-               
+
                // Copy new children to this component
                for (RocketComponent c : src.children) {
                        RocketComponent copy = c.copyWithOriginalID();
                        this.children.add(copy);
                        copy.parent = this;
                }
-               
+
                this.checkComponentStructure();
                src.checkComponentStructure();
-               
+
                // Set all parameters
                this.length = src.length;
                this.relativePosition = src.relativePosition;
@@ -1667,40 +1644,40 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.name = src.name;
                this.comment = src.comment;
                this.id = src.id;
-               
+
                // Add source components to invalidation tree
                for (RocketComponent c : src) {
                        toInvalidate.add(c);
                }
-               
+
                return toInvalidate;
        }
-       
+
        protected void invalidate() {
                invalidator.invalidate();
        }
-       
-       
+
+
        //////////  Iterator implementation  ///////////
-       
+
        /**
         * Private inner class to implement the Iterator.
-        * 
+        *
         * This iterator is fail-fast if the root of the structure is a Rocket.
         */
        private static class RocketComponentIterator implements Iterator<RocketComponent> {
                // Stack holds iterators which still have some components left.
                private final Deque<Iterator<RocketComponent>> iteratorStack = new ArrayDeque<Iterator<RocketComponent>>();
-               
+
                private final Rocket root;
                private final int treeModID;
-               
+
                private final RocketComponent original;
                private boolean returnSelf = false;
-               
+
                // Construct iterator with component's child's iterator, if it has elements
                public RocketComponentIterator(RocketComponent c, boolean returnSelf) {
-                       
+
                        RocketComponent gp = c.getRoot();
                        if (gp instanceof Rocket) {
                                root = (Rocket) gp;
@@ -1709,15 +1686,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                root = null;
                                treeModID = -1;
                        }
-                       
+
                        Iterator<RocketComponent> i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-                       
+
                        this.original = c;
                        this.returnSelf = returnSelf;
                }
-               
+
                @Override
                public boolean hasNext() {
                        checkID();
@@ -1725,38 +1702,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                return true;
                        return !iteratorStack.isEmpty(); // Elements remain if stack is not empty
                }
-               
+
                @Override
                public RocketComponent next() {
                        Iterator<RocketComponent> i;
-                       
+
                        checkID();
-                       
+
                        // Return original component first
                        if (returnSelf) {
                                returnSelf = false;
                                return original;
                        }
-                       
+
                        // Peek first iterator from stack, throw exception if empty
                        i = iteratorStack.peek();
                        if (i == null) {
                                throw new NoSuchElementException("No further elements in RocketComponent iterator");
                        }
-                       
+
                        // Retrieve next component of the iterator, remove iterator from stack if empty
                        RocketComponent c = i.next();
                        if (!i.hasNext())
                                iteratorStack.pop();
-                       
+
                        // Add iterator of component children to stack if it has children
                        i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-                       
+
                        return c;
                }
-               
+
                private void checkID() {
                        if (root != null) {
                                if (root.getTreeModID() != treeModID) {
@@ -1764,12 +1741,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                }
                        }
                }
-               
+
                @Override
                public void remove() {
                        throw new UnsupportedOperationException("remove() not supported by " +
                                        "RocketComponent iterator");
                }
        }
-       
+
 }
index b16cd4b660e96a39c42d99533f66061cea79080f..5acbe85439791e0b8687e7c73ce32b69ca57b452 100644 (file)
@@ -1,20 +1,20 @@
 package net.sf.openrocket.rocketcomponent;
 
 public class Stage extends ComponentAssembly {
-       
+
     @Override
     public String getComponentName () {
         return "Stage";
     }
-       
-       
+
+
        @Override
        public boolean allowsChildren() {
                return true;
        }
-       
+
     /**
-        * Check whether the given type can be added to this component.  A Stage allows 
+        * Check whether the given type can be added to this component.  A Stage allows
         * only BodyComponents to be added.
      *
      * @param type The RocketComponent class type to add.
@@ -25,14 +25,4 @@ public class Stage extends ComponentAssembly {
     public boolean isCompatible (Class<? extends RocketComponent> type) {
         return BodyComponent.class.isAssignableFrom(type);
     }
-
-    /**
-     * Accept a visitor to this Stage in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this Stage
-     */    
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
 }
index 81140a66dc60b208c821d433d2adcaaf279b233c..0daa5f7f185bc481cc6da67179cfbfe2b1f997bc 100644 (file)
@@ -15,15 +15,15 @@ import static net.sf.openrocket.util.MathUtil.pow3;
 
 public class Transition extends SymmetricComponent {
        private static final double CLIP_PRECISION = 0.0001;
-       
+
 
        private Shape type;
        private double shapeParameter;
        private boolean clipped; // Not to be read - use isClipped(), which may be overriden
-       
+
        private double radius1, radius2;
        private boolean autoRadius1, autoRadius2; // Whether the start radius is automatic
-                       
+
 
        private double foreShoulderRadius;
        private double foreShoulderThickness;
@@ -33,30 +33,30 @@ public class Transition extends SymmetricComponent {
        private double aftShoulderThickness;
        private double aftShoulderLength;
        private boolean aftShoulderCapped;
-       
+
 
        // Used to cache the clip length
        private double clipLength = -1;
-       
+
        public Transition() {
                super();
-               
+
                this.radius1 = DEFAULT_RADIUS;
                this.radius2 = DEFAULT_RADIUS;
                this.length = DEFAULT_RADIUS * 3;
                this.autoRadius1 = true;
                this.autoRadius2 = true;
-               
+
                this.type = Shape.CONICAL;
                this.shapeParameter = 0;
                this.clipped = true;
        }
-       
-       
+
+
 
 
        ////////  Fore radius  ////////
-       
+
 
        @Override
        public double getForeRadius() {
@@ -73,35 +73,35 @@ public class Transition extends SymmetricComponent {
                }
                return radius1;
        }
-       
+
        public void setForeRadius(double radius) {
                if ((this.radius1 == radius) && (autoRadius1 == false))
                        return;
-               
+
                this.autoRadius1 = false;
                this.radius1 = Math.max(radius, 0);
-               
+
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        @Override
        public boolean isForeRadiusAutomatic() {
                return autoRadius1;
        }
-       
+
        public void setForeRadiusAutomatic(boolean auto) {
                if (autoRadius1 == auto)
                        return;
-               
+
                autoRadius1 = auto;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        ////////  Aft radius  /////////
-       
+
        @Override
        public double getAftRadius() {
                if (isAftRadiusAutomatic()) {
@@ -117,62 +117,62 @@ public class Transition extends SymmetricComponent {
                }
                return radius2;
        }
-       
-       
+
+
 
        public void setAftRadius(double radius) {
                if ((this.radius2 == radius) && (autoRadius2 == false))
                        return;
-               
+
                this.autoRadius2 = false;
                this.radius2 = Math.max(radius, 0);
-               
+
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        @Override
        public boolean isAftRadiusAutomatic() {
                return autoRadius2;
        }
-       
+
        public void setAftRadiusAutomatic(boolean auto) {
                if (autoRadius2 == auto)
                        return;
-               
+
                autoRadius2 = auto;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
        //// Radius automatics
-       
+
        @Override
        protected double getFrontAutoRadius() {
                if (isAftRadiusAutomatic())
                        return -1;
                return getAftRadius();
        }
-       
-       
+
+
        @Override
        protected double getRearAutoRadius() {
                if (isForeRadiusAutomatic())
                        return -1;
                return getForeRadius();
        }
-       
-       
+
+
 
 
        ////////  Type & shape  /////////
-       
+
        public Shape getType() {
                return type;
        }
-       
+
        public void setType(Shape type) {
                if (type == null) {
                        throw new IllegalArgumentException("setType called with null argument");
@@ -184,142 +184,142 @@ public class Transition extends SymmetricComponent {
                this.shapeParameter = type.defaultParameter();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public double getShapeParameter() {
                return shapeParameter;
        }
-       
+
        public void setShapeParameter(double n) {
                if (shapeParameter == n)
                        return;
                this.shapeParameter = MathUtil.clamp(n, type.minParameter(), type.maxParameter());
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public boolean isClipped() {
                if (!type.isClippable())
                        return false;
                return clipped;
        }
-       
+
        public void setClipped(boolean c) {
                if (clipped == c)
                        return;
                clipped = c;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public boolean isClippedEnabled() {
                return type.isClippable();
        }
-       
+
        public double getShapeParameterMin() {
                return type.minParameter();
        }
-       
+
        public double getShapeParameterMax() {
                return type.maxParameter();
        }
-       
-       
+
+
        ////////  Shoulders  ////////
-       
+
        public double getForeShoulderRadius() {
                return foreShoulderRadius;
        }
-       
+
        public void setForeShoulderRadius(double foreShoulderRadius) {
                if (MathUtil.equals(this.foreShoulderRadius, foreShoulderRadius))
                        return;
                this.foreShoulderRadius = foreShoulderRadius;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getForeShoulderThickness() {
                return foreShoulderThickness;
        }
-       
+
        public void setForeShoulderThickness(double foreShoulderThickness) {
                if (MathUtil.equals(this.foreShoulderThickness, foreShoulderThickness))
                        return;
                this.foreShoulderThickness = foreShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getForeShoulderLength() {
                return foreShoulderLength;
        }
-       
+
        public void setForeShoulderLength(double foreShoulderLength) {
                if (MathUtil.equals(this.foreShoulderLength, foreShoulderLength))
                        return;
                this.foreShoulderLength = foreShoulderLength;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public boolean isForeShoulderCapped() {
                return foreShoulderCapped;
        }
-       
+
        public void setForeShoulderCapped(boolean capped) {
                if (this.foreShoulderCapped == capped)
                        return;
                this.foreShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
 
        public double getAftShoulderRadius() {
                return aftShoulderRadius;
        }
-       
+
        public void setAftShoulderRadius(double aftShoulderRadius) {
                if (MathUtil.equals(this.aftShoulderRadius, aftShoulderRadius))
                        return;
                this.aftShoulderRadius = aftShoulderRadius;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getAftShoulderThickness() {
                return aftShoulderThickness;
        }
-       
+
        public void setAftShoulderThickness(double aftShoulderThickness) {
                if (MathUtil.equals(this.aftShoulderThickness, aftShoulderThickness))
                        return;
                this.aftShoulderThickness = aftShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getAftShoulderLength() {
                return aftShoulderLength;
        }
-       
+
        public void setAftShoulderLength(double aftShoulderLength) {
                if (MathUtil.equals(this.aftShoulderLength, aftShoulderLength))
                        return;
                this.aftShoulderLength = aftShoulderLength;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public boolean isAftShoulderCapped() {
                return aftShoulderCapped;
        }
-       
+
        public void setAftShoulderCapped(boolean capped) {
                if (this.aftShoulderCapped == capped)
                        return;
                this.aftShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
 
        ///////////   Shape implementations   ////////////
-       
+
 
 
        /**
@@ -329,20 +329,20 @@ public class Transition extends SymmetricComponent {
        public double getRadius(double x) {
                if (x < 0 || x > length)
                        return 0;
-               
+
                double r1 = getForeRadius();
                double r2 = getAftRadius();
-               
+
                if (r1 == r2)
                        return r1;
-               
+
                if (r1 > r2) {
                        x = length - x;
                        double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
                }
-               
+
                if (isClipped()) {
                        // Check clip calculation
                        if (clipLength < 0)
@@ -353,7 +353,7 @@ public class Transition extends SymmetricComponent {
                        return r1 + type.getRadius(x, r2 - r1, length, shapeParameter);
                }
        }
-       
+
        /**
         * Numerically solve clipLength from the equation
         *     r1 == type.getRadius(clipLength,r2,clipLength+length)
@@ -361,27 +361,27 @@ public class Transition extends SymmetricComponent {
         */
        private void calculateClip(double r1, double r2) {
                double min = 0, max = length;
-               
+
                if (r1 >= r2) {
                        double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
                }
-               
+
                if (r1 == 0) {
                        clipLength = 0;
                        return;
                }
-               
+
                if (length <= 0) {
                        clipLength = 0;
                        return;
                }
-               
+
                // Required:
                //    getR(min,min+length,r2) - r1 < 0
                //    getR(max,max+length,r2) - r1 > 0
-               
+
                int n = 0;
                while (type.getRadius(max, r2, max + length, shapeParameter) - r1 < 0) {
                        min = max;
@@ -390,7 +390,7 @@ public class Transition extends SymmetricComponent {
                        if (n > 10)
                                break;
                }
-               
+
                while (true) {
                        clipLength = (min + max) / 2;
                        if ((max - min) < CLIP_PRECISION)
@@ -403,14 +403,14 @@ public class Transition extends SymmetricComponent {
                        }
                }
        }
-       
-       
+
+
        @Override
        public double getInnerRadius(double x) {
                return Math.max(getRadius(x) - thickness, 0);
        }
-       
-       
+
+
 
        @Override
        public Collection<Coordinate> getComponentBounds() {
@@ -421,7 +421,7 @@ public class Transition extends SymmetricComponent {
                        addBound(bounds, getLength() + aftShoulderLength, aftShoulderRadius);
                return bounds;
        }
-       
+
        @Override
        public double getComponentMass() {
                double mass = super.getComponentMass();
@@ -434,7 +434,7 @@ public class Transition extends SymmetricComponent {
                        final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0);
                        mass += ringMass(ir, 0, getForeShoulderThickness(), getMaterial().getDensity());
                }
-               
+
                if (getAftShoulderLength() > 0.001) {
                        final double or = getAftShoulderRadius();
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
@@ -444,10 +444,10 @@ public class Transition extends SymmetricComponent {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
                        mass += ringMass(ir, 0, getAftShoulderThickness(), getMaterial().getDensity());
                }
-               
+
                return mass;
        }
-       
+
        @Override
        public Coordinate getComponentCG() {
                Coordinate cg = super.getComponentCG();
@@ -462,7 +462,7 @@ public class Transition extends SymmetricComponent {
                                        getForeShoulderThickness() - getForeShoulderLength(),
                                        getMaterial().getDensity()));
                }
-               
+
                if (getAftShoulderLength() > 0.001) {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
                        cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(),
@@ -476,8 +476,8 @@ public class Transition extends SymmetricComponent {
                }
                return cg;
        }
-       
-       
+
+
        /*
         * The moments of inertia are not explicitly corrected for the shoulders.
         * However, since the mass is corrected, the inertia is automatically corrected
@@ -493,27 +493,17 @@ public class Transition extends SymmetricComponent {
        public String getComponentName() {
                return "Transition";
        }
-       
+
        @Override
        protected void componentChanged(ComponentChangeEvent e) {
                super.componentChanged(e);
                clipLength = -1;
        }
-       
-    /**
-     * Accept a visitor to this Transition in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this Transition
-     */
-    @Override 
-    public void accept (final ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
-       
+
        /**
         * Check whether the given type can be added to this component.  Transitions allow any
         * InternalComponents to be added.
-        * 
+        *
         * @param type  The RocketComponent class type to add.
         * @return      Whether such a component can be added.
         */
@@ -523,16 +513,16 @@ public class Transition extends SymmetricComponent {
                        return true;
                return false;
        }
-       
-       
+
+
 
        /**
         * An enumeration listing the possible shapes of transitions.
-        * 
+        *
         * @author Sampo Niskanen <sampo.niskanen@iki.fi>
         */
        public static enum Shape {
-               
+
                /**
                 * Conical shape.
                 */
@@ -547,7 +537,7 @@ public class Transition extends SymmetricComponent {
                                return radius * x / length;
                        }
                },
-               
+
                /**
                 * Ogive shape.  The shape parameter is the portion of an extended tangent ogive
                 * that will be used.  That is, for param==1 a tangent ogive will be produced, and
@@ -566,12 +556,12 @@ public class Transition extends SymmetricComponent {
                        public boolean usesParameter() {
                                return true; // Range 0...1 is default
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 1.0; // Tangent ogive by default
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -579,17 +569,17 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-                               
+
                                // Impossible to calculate ogive for length < radius, scale instead
                                // TODO: LOW: secant ogive could be calculated lower
                                if (length < radius) {
                                        x = x * radius / length;
                                        length = radius;
                                }
-                               
+
                                if (param < 0.001)
                                        return CONICAL.getRadius(x, radius, length, param);
-                               
+
                                // Radius of circle is:
                                double R = sqrt((pow2(length) + pow2(radius)) *
                                                (pow2((2 - param) * length) + pow2(param * radius)) / (4 * pow2(param * radius)));
@@ -599,7 +589,7 @@ public class Transition extends SymmetricComponent {
                                return sqrt(R * R - (L - x) * (L - x)) - y0;
                        }
                },
-               
+
                /**
                 * Ellipsoidal shape.
                 */
@@ -619,7 +609,7 @@ public class Transition extends SymmetricComponent {
                                return sqrt(2 * radius * x - x * x); // radius/length * sphere
                        }
                },
-               
+
                POWER("Power series",
                                "A power series nose cone has a profile of " +
                                                "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
@@ -637,12 +627,12 @@ public class Transition extends SymmetricComponent {
                        public boolean usesParameter() { // Range 0...1
                                return true;
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 0.5;
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -658,9 +648,9 @@ public class Transition extends SymmetricComponent {
                                }
                                return radius * Math.pow(x / length, param);
                        }
-                       
+
                },
-               
+
                PARABOLIC("Parabolic series",
                                "A parabolic series nose cone has a profile of a parabola.  The shape " +
                                                "parameter defines the segment of the parabola to utilize.  The shape " +
@@ -672,20 +662,20 @@ public class Transition extends SymmetricComponent {
                                                "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
                                                "tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
                                                "<b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.") {
-                       
+
                        // In principle a parabolic transition is clippable, but the difference is
                        // negligible.
-                       
+
                        @Override
                        public boolean usesParameter() { // Range 0...1
                                return true;
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 1.0;
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -693,11 +683,11 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-                               
+
                                return radius * ((2 * x / length - param * pow2(x / length)) / (2 - param));
                        }
                },
-               
+
 
 
                HAACK("Haack series",
@@ -714,12 +704,12 @@ public class Transition extends SymmetricComponent {
                        public boolean usesParameter() {
                                return true;
                        }
-                       
+
                        @Override
                        public double maxParameter() {
                                return 1.0 / 3.0; // Range 0...1/3
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -727,7 +717,7 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 2;
-                               
+
                                double theta = Math.acos(1 - 2 * x / length);
                                if (param == 0) {
                                        return radius * sqrt((theta - sin(2 * theta) / 2) / Math.PI);
@@ -735,7 +725,7 @@ public class Transition extends SymmetricComponent {
                                return radius * sqrt((theta - sin(2 * theta) / 2 + param * pow3(sin(theta))) / Math.PI);
                        }
                },
-               
+
                //              POLYNOMIAL("Smooth polynomial",
                //                              "A polynomial is fitted such that the nose cone profile is horizontal "+
                //                              "at the aft end of the transition.  The angle at the tip is defined by "+
@@ -767,18 +757,18 @@ public class Transition extends SymmetricComponent {
                //                      }
                //              }
                ;
-               
+
                // Privete fields of the shapes
                private final String name;
                private final String transitionDesc;
                private final String noseconeDesc;
                private final boolean canClip;
-               
+
                // Non-clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc) {
                        this(name, noseconeDesc, transitionDesc, false);
                }
-               
+
                // Clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc, boolean canClip) {
                        this.name = name;
@@ -786,29 +776,29 @@ public class Transition extends SymmetricComponent {
                        this.noseconeDesc = noseconeDesc;
                        this.transitionDesc = transitionDesc;
                }
-               
-               
+
+
                /**
                 * Return the name of the transition shape name.
                 */
                public String getName() {
                        return name;
                }
-               
+
                /**
                 * Get a description of the Transition shape.
                 */
                public String getTransitionDescription() {
                        return transitionDesc;
                }
-               
+
                /**
                 * Get a description of the NoseCone shape.
                 */
                public String getNoseConeDescription() {
                        return noseconeDesc;
                }
-               
+
                /**
                 * Check whether the shape differs in clipped mode.  The clipping should be
                 * enabled by default if possible.
@@ -816,41 +806,41 @@ public class Transition extends SymmetricComponent {
                public boolean isClippable() {
                        return canClip;
                }
-               
+
                /**
                 * Return whether the shape uses the shape parameter.  (Default false.)
                 */
                public boolean usesParameter() {
                        return false;
                }
-               
+
                /**
                 * Return the minimum value of the shape parameter.  (Default 0.)
                 */
                public double minParameter() {
                        return 0.0;
                }
-               
+
                /**
                 * Return the maximum value of the shape parameter.  (Default 1.)
                 */
                public double maxParameter() {
                        return 1.0;
                }
-               
+
                /**
                 * Return the default value of the shape parameter.  (Default 0.)
                 */
                public double defaultParameter() {
                        return 0.0;
                }
-               
+
                /**
                 * Calculate the basic radius of a transition with the given radius, length and
                 * shape parameter at the point x from the tip of the component.  It is assumed
                 * that the fore radius if zero and the aft radius is <code>radius >= 0</code>.
                 * Boattails are achieved by reversing the component.
-                * 
+                *
                 * @param x      Position from the tip of the component.
                 * @param radius Aft end radius >= 0.
                 * @param length Length of the transition >= 0.
@@ -858,8 +848,8 @@ public class Transition extends SymmetricComponent {
                 * @return       The basic radius at the given position.
                 */
                public abstract double getRadius(double x, double radius, double length, double param);
-               
-               
+
+
                /**
                 * Returns the name of the shape (same as getName()).
                 */
index 6f8ef943dbf212ed755dc6ac30bc7c1fe327ec54..9c3076a3301474d5c7509b00a00e641997356ff3 100644 (file)
@@ -5,7 +5,7 @@ import net.sf.openrocket.util.Coordinate;
 /**
  * A set of trapezoidal fins.  The root and tip chords are perpendicular to the rocket
  * base line, while the leading and aft edges may be slanted.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
@@ -16,37 +16,37 @@ public class TrapezoidFinSet extends FinSet {
         *           sweep   tipChord
         *           |    |___________
         *           |   /            |
-        *           |  /             | 
+        *           |  /             |
         *           | /              |  height
         *            /               |
         * __________/________________|_____________
         *                length
         *              == rootChord
         */
-       
+
        // rootChord == length
        private double tipChord = 0;
        private double height = 0;
        private double sweep = 0;
-       
-       
+
+
        public TrapezoidFinSet() {
                this (3, 0.05, 0.05, 0.025, 0.05);
        }
-       
+
        // TODO: HIGH:  height=0 -> CP = NaN
-       public TrapezoidFinSet(int fins, double rootChord, double tipChord, double sweep, 
+       public TrapezoidFinSet(int fins, double rootChord, double tipChord, double sweep,
                        double height) {
                super();
-               
+
                this.setFinCount(fins);
                this.length = rootChord;
                this.tipChord = tipChord;
                this.sweep = sweep;
                this.height = height;
        }
-       
-       
+
+
        public void setFinShape(double rootChord, double tipChord, double sweep, double height,
                        double thickness) {
                if (this.length==rootChord && this.tipChord==tipChord && this.sweep==sweep &&
@@ -69,7 +69,7 @@ public class TrapezoidFinSet extends FinSet {
                length = Math.max(r,0);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public double getTipChord() {
                return tipChord;
        }
@@ -95,7 +95,7 @@ public class TrapezoidFinSet extends FinSet {
                sweep = r;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        /**
         * Get the sweep angle.  This is calculated from the true sweep and height, and is not
         * stored separetely.
@@ -135,7 +135,7 @@ public class TrapezoidFinSet extends FinSet {
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
 
-       
+
 
        /**
         * Returns the geometry of a trapezoidal fin.
@@ -143,15 +143,15 @@ public class TrapezoidFinSet extends FinSet {
        @Override
        public Coordinate[] getFinPoints() {
                Coordinate[] c = new Coordinate[4];
-               
+
                c[0] = Coordinate.NUL;
                c[1] = new Coordinate(sweep,height);
                c[2] = new Coordinate(sweep+tipChord,height);
                c[3] = new Coordinate(length,0);
-               
+
                return c;
        }
-       
+
        /**
         * Returns the span of a trapezoidal fin.
         */
@@ -159,20 +159,11 @@ public class TrapezoidFinSet extends FinSet {
        public double getSpan() {
                return height;
        }
-       
+
 
        @Override
        public String getComponentName() {
                return "Trapezoidal fin set";
        }
 
-    /**
-     * Accept a visitor to this TrapezoidFinSet in the component hierarchy.
-     * 
-     * @param theVisitor  the visitor that will be called back with a reference to this TrapezoidFinSet
-     */    
-    @Override
-    public void accept(ComponentVisitor theVisitor) {
-        theVisitor.visit(this);
-    }
 }