From: rodinia814 Date: Fri, 12 Nov 2010 02:51:18 +0000 (+0000) Subject: DGP - merged printing support from branch X-Git-Tag: upstream/1.1.4^2~10 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=50f171ab51eae5c91117ebdc9b7a0d43d764ddb5;p=debian%2Fopenrocket DGP - merged printing support from branch git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@95 180e2498-e6e9-4542-8430-84ac67f01cd8 --- 50f171ab51eae5c91117ebdc9b7a0d43d764ddb5 diff --cc src/net/sf/openrocket/gui/main/BasicFrame.java index 4f1561ce,43c214c7..3c8f4e2c --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@@ -1,64 -1,10 +1,7 @@@ package net.sf.openrocket.gui.main; - import java.awt.Dimension; - import java.awt.Font; - import java.awt.Toolkit; - import java.awt.Window; - import java.awt.event.ActionEvent; - import java.awt.event.ActionListener; - import java.awt.event.ComponentAdapter; - import java.awt.event.ComponentEvent; - import java.awt.event.KeyEvent; - import java.awt.event.MouseAdapter; - import java.awt.event.MouseEvent; - import java.awt.event.MouseListener; - import java.awt.event.WindowAdapter; - import java.awt.event.WindowEvent; - import java.io.File; - import java.io.FileNotFoundException; - import java.io.IOException; - import java.io.InputStream; - import java.io.UnsupportedEncodingException; - import java.net.URI; - import java.net.URISyntaxException; - import java.net.URL; - import java.net.URLDecoder; - import java.util.ArrayList; - import java.util.Arrays; - import java.util.LinkedList; - import java.util.List; - import java.util.concurrent.ExecutionException; - - import javax.swing.Action; - import javax.swing.InputMap; - import javax.swing.JButton; - import javax.swing.JComponent; - import javax.swing.JFileChooser; - import javax.swing.JFrame; - import javax.swing.JMenu; - import javax.swing.JMenuBar; - import javax.swing.JMenuItem; - import javax.swing.JOptionPane; - import javax.swing.JPanel; - import javax.swing.JScrollPane; - import javax.swing.JSeparator; - import javax.swing.JSplitPane; - import javax.swing.JTabbedPane; - import javax.swing.JTextField; - import javax.swing.KeyStroke; - import javax.swing.ListSelectionModel; - import javax.swing.ScrollPaneConstants; - import javax.swing.SwingUtilities; - import javax.swing.border.TitledBorder; - import javax.swing.event.TreeSelectionEvent; - import javax.swing.event.TreeSelectionListener; - import javax.swing.filechooser.FileFilter; - import javax.swing.tree.DefaultTreeSelectionModel; - import javax.swing.tree.TreePath; - import javax.swing.tree.TreeSelectionModel; - import net.miginfocom.swing.MigLayout; import net.sf.openrocket.aerodynamics.WarningSet; -import net.sf.openrocket.communication.UpdateInfo; -import net.sf.openrocket.communication.UpdateInfoRetriever; -import net.sf.openrocket.database.Databases; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.file.GeneralRocketLoader; import net.sf.openrocket.file.RocketLoadException; @@@ -75,10 -19,11 +18,11 @@@ import net.sf.openrocket.gui.dialogs.De import net.sf.openrocket.gui.dialogs.ExampleDesignDialog; import net.sf.openrocket.gui.dialogs.LicenseDialog; import net.sf.openrocket.gui.dialogs.MotorDatabaseLoadingDialog; + import net.sf.openrocket.gui.dialogs.PrintDialog; import net.sf.openrocket.gui.dialogs.SwingWorkerDialog; -import net.sf.openrocket.gui.dialogs.UpdateInfoDialog; import net.sf.openrocket.gui.dialogs.WarningDialog; import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog; +import net.sf.openrocket.gui.main.componenttree.ComponentTree; import net.sf.openrocket.gui.scalefigure.RocketPanel; import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; @@@ -98,6 -41,62 +42,62 @@@ import net.sf.openrocket.util.Reflectio import net.sf.openrocket.util.SaveFileWorker; import net.sf.openrocket.util.TestRockets; + import javax.swing.Action; + import javax.swing.InputMap; + import javax.swing.JButton; + import javax.swing.JComponent; + import javax.swing.JFileChooser; + import javax.swing.JFrame; + import javax.swing.JMenu; + import javax.swing.JMenuBar; + import javax.swing.JMenuItem; + import javax.swing.JOptionPane; + import javax.swing.JPanel; + import javax.swing.JScrollPane; + import javax.swing.JSeparator; + import javax.swing.JSplitPane; + import javax.swing.JTabbedPane; + import javax.swing.JTextField; + import javax.swing.KeyStroke; + import javax.swing.ListSelectionModel; + import javax.swing.ScrollPaneConstants; + import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.ToolTipManager; + import javax.swing.border.TitledBorder; + import javax.swing.event.TreeSelectionEvent; + import javax.swing.event.TreeSelectionListener; + import javax.swing.filechooser.FileFilter; + import javax.swing.tree.DefaultTreeSelectionModel; + import javax.swing.tree.TreePath; + import javax.swing.tree.TreeSelectionModel; + import java.awt.Dimension; + import java.awt.Font; + import java.awt.Toolkit; + import java.awt.Window; + import java.awt.event.ActionEvent; + import java.awt.event.ActionListener; + import java.awt.event.ComponentAdapter; + import java.awt.event.ComponentEvent; + import java.awt.event.KeyEvent; + import java.awt.event.MouseAdapter; + import java.awt.event.MouseEvent; + import java.awt.event.MouseListener; + import java.awt.event.WindowAdapter; + import java.awt.event.WindowEvent; + import java.io.File; + import java.io.FileNotFoundException; + import java.io.IOException; + import java.io.InputStream; + import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; + import java.net.URI; + import java.net.URISyntaxException; + import java.net.URL; + import java.net.URLDecoder; + import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.LinkedList; ++import java.util.List; + import java.util.concurrent.ExecutionException; + public class BasicFrame extends JFrame { private static final LogHelper log = Application.getLogger(); @@@ -1266,7 -1116,22 +1277,14 @@@ } - /** - * Closes this frame if it is replaceable. - */ - public void closeIfReplaceable() { - if (this.replaceable && document.isSaved()) { - closeAction(); - } - } + /** + * + */ + public void printAction() { + new PrintDialog(document); + } + /** * Open a new design window with a basic rocket+stage. */ diff --cc src/net/sf/openrocket/gui/print/DesignReport.java index 00000000,1da0bd00..247881e8 mode 000000,100644..100644 --- a/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/src/net/sf/openrocket/gui/print/DesignReport.java @@@ -1,0 -1,466 +1,466 @@@ + /* - * DrawingsPrintable.java ++ * DesignReport.java + */ + 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.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 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.motor.Motor; + import net.sf.openrocket.rocketcomponent.ComponentVisitor; + import net.sf.openrocket.rocketcomponent.Configuration; + import net.sf.openrocket.rocketcomponent.Rocket; + import net.sf.openrocket.simulation.FlightData; + import net.sf.openrocket.unit.Unit; + import net.sf.openrocket.unit.UnitGroup; + import net.sf.openrocket.util.Prefs; + + import java.awt.Graphics2D; + import java.io.IOException; + import java.text.DecimalFormat; + import java.util.List; + + /** + *
+  * #  Title # Section describing the rocket in general without motors
+  * # Section describing the rocket in general without motors
+  * 

+ * design name + * empty mass & CG + * CP position + * CP position at 5 degree AOA (or similar) + * number of stages + * parachute/streamer sizes + * max. diameter (caliber) + * velocity at exit of rail/rod + * minimum safe velocity reached in x inches/cm + *

+ * # Section for each motor configuration + *

+ * a summary of the motors, e.g. 3xC6-0; B4-6 + * a list of the motors including the manufacturer, designation (maybe also info like burn time, grams of propellant, + * total impulse) + * total grams of propellant + * total impulse + * takeoff weight + * CG and CP position, stability margin + * predicted flight altitude, max. velocity and max. acceleration + * predicted velocity at chute deployment + * predicted descent rate + * Thrust to Weight Ratio of each stage + *

+ *

+ */ + public class DesignReport extends BaseVisitorStrategy { + + /** + * The OR Document. + */ + private OpenRocketDocument rocketDocument; + + /** + * A panel used for rendering of the design diagram. + */ + final RocketPanel panel; + + /** + * A stage visitor. + */ + private StageVisitorStrategy svs = new StageVisitorStrategy(); + + /** + * Constructor. + * + * @param theRocDoc the OR document + * @param theIDoc the iText document + */ + public DesignReport (OpenRocketDocument theRocDoc, Document theIDoc) { + super(theIDoc, null); + rocketDocument = theRocDoc; + panel = new RocketPanel(rocketDocument); + } + + /** + * Main entry point. Prints the rocket drawing and design data. + * + * @param writer a direct byte writer + */ + public void print (PdfWriter writer) { + if (writer == null) { + return; + } + com.itextpdf.text.Rectangle pageSize = document.getPageSize(); + 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"); + + Rocket rocket = rocketDocument.getRocket(); + final Configuration configuration = rocket.getDefaultConfiguration(); + configuration.setAllStages(); + PdfContentByte canvas = writer.getDirectContent(); + + final PrintFigure figure = new PrintFigure(configuration); + + FigureElement cp = panel.getExtraCP(); + FigureElement cg = panel.getExtraCG(); + RocketInfo text = panel.getExtraText(); + + double scale = paintRocketDiagram(pageImageableWidth, pageImageableHeight, canvas, figure, cp, cg); + + canvas.beginText(); + try { + canvas.setFontAndSize(BaseFont.createFont(PrintUtilities.NORMAL.getFamilyname(), BaseFont.CP1252, + BaseFont.EMBEDDED), PrintUtilities.NORMAL_FONT_SIZE); + } + catch (DocumentException e) { + e.printStackTrace(); + } + catch (IOException e) { + e.printStackTrace(); + } + int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getFigureHeight()) * 0.4 * (scale / PrintUnit.METERS + .toPoints(1))); + final int diagramHeight = pageImageableHeight * 2 - 70 - (int) (figHeightPts); + canvas.moveText(document.leftMargin() + pageSize.getBorderWidthLeft(), diagramHeight); + canvas.moveTextWithLeading(0, -16); + + float initialY = canvas.getYTLM(); + + canvas.showText(rocketDocument.getRocket().getName()); + + canvas.newlineShowText("Stages: "); + canvas.showText("" + rocket.getStageCount()); + + + if (configuration.hasMotors()) { + canvas.newlineShowText("Mass (with motor" + ((configuration.getStageCount() > 1) ? "s): " : "): ")); + } + else { + canvas.newlineShowText("Mass (Empty): "); + } + canvas.showText(text.getMass(UnitGroup.UNITS_MASS.getDefaultUnit())); + + canvas.newlineShowText("Stability: "); + canvas.showText(text.getStability()); + + canvas.newlineShowText("Cg: "); + canvas.showText(text.getCg()); + + canvas.newlineShowText("Cp: "); + canvas.showText(text.getCp()); + canvas.endText(); + + try { + //Move the internal pointer of the document below that of what was just written using the direct byte buffer. + Paragraph paragraph = new Paragraph(); + float finalY = canvas.getYTLM(); + int heightOfDiagramAndText = (int) (pageSize.getHeight() - (finalY - initialY + diagramHeight)); + + paragraph.setSpacingAfter(heightOfDiagramAndText); + document.add(paragraph); + + String[] mids = rocket.getMotorConfigurationIDs(); + + List 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)); + PdfPTable parent = new PdfPTable(2); + parent.setWidthPercentage(100); + parent.setHorizontalAlignment(Element.ALIGN_LEFT); + parent.setSpacingBefore(0); + parent.setWidths(new int[]{1, 3}); + int leading = 0; + //The first motor config is always null. Skip it and the top-most motor, then set the leading. + if (j > 1) { + leading = 25; + } + addFlightData(rocket, mid, parent, leading); + addMotorData(mmvs.getMotors(), parent, stages); + document.add(parent); + } + } + } + catch (DocumentException e) { + e.printStackTrace(); + } + } + + /** + * Paint a diagram of the rocket into the PDF document. + * + * @param thePageImageableWidth the number of points in the width of the page available for drawing + * @param thePageImageableHeight the number of points in the height of the page available for drawing + * @param theCanvas the direct byte writer + * @param theFigure the print figure + * @param theCp the center of pressure figure element + * @param theCg the center of gravity figure element + * + * @return the scale of the diagram + */ + private double paintRocketDiagram (final int thePageImageableWidth, final int thePageImageableHeight, + final PdfContentByte theCanvas, final PrintFigure theFigure, + final FigureElement theCp, final FigureElement theCg) { + theFigure.clearAbsoluteExtra(); + theFigure.clearRelativeExtra(); + theFigure.addRelativeExtra(theCp); + theFigure.addRelativeExtra(theCg); + theFigure.updateFigure(); + + double scale = + (thePageImageableWidth * 2.2) / theFigure.getFigureWidth(); + + theFigure.setScale(scale); + /* + * page dimensions are in points-per-inch, which, in Java2D, are the same as pixels-per-inch; thus we don't need any conversion + */ + theFigure.setSize(thePageImageableWidth, thePageImageableHeight); + theFigure.updateFigure(); + + + final DefaultFontMapper mapper = new DefaultFontMapper(); + Graphics2D g2d = theCanvas.createGraphics(thePageImageableWidth, thePageImageableHeight * 2, mapper); + g2d.translate(20, 120); + + g2d.scale(0.4d, 0.4d); + theFigure.paint(g2d); + g2d.dispose(); + return scale; + } + + /** + * Add the motor data for a motor configuration to the table. + * + * @param motors a motor configuration's list of motors + * @param parent the parent to which the motor data will be added + * @param stageWeights the stageWeights of each stage, in order + */ + private void addMotorData (List motors, final PdfPTable parent, List stageWeights) { + + PdfPTable motorTable = new PdfPTable(8); + motorTable.setWidthPercentage(68); + motorTable.setHorizontalAlignment(Element.ALIGN_LEFT); + + 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)); + + DecimalFormat df = new DecimalFormat("#,##0.0#"); + for (int i = 0; i < motors.size(); i++) { + int border = Rectangle.BOTTOM; + if (i == motors.size() - 1) { + border = Rectangle.NO_BORDER; + } + Motor motor = motors.get(i); + double motorWeight = (motor.getLaunchCG().weight - motor.getEmptyCG().weight) * 1000; //convert to grams + + final PdfPCell motorVCell = ITextHelper.createCell(motor.getDesignation(), border); + motorVCell.setPaddingLeft(mPad); + motorTable.addCell(motorVCell); + motorTable.addCell(ITextHelper.createCell(df.format(motor.getAverageThrustEstimate()) + " " + UnitGroup + .UNITS_FORCE + .getDefaultUnit().toString(), border)); + motorTable.addCell(ITextHelper.createCell(df.format(motor.getBurnTimeEstimate()) + " " + UnitGroup + .UNITS_FLIGHT_TIME + .getDefaultUnit().toString(), border)); + motorTable.addCell(ITextHelper.createCell(df.format(motor.getMaxThrustEstimate()) + " " + UnitGroup + .UNITS_FORCE.getDefaultUnit() + .toString(), border)); + motorTable.addCell(ITextHelper.createCell(df.format(motor.getTotalImpulseEstimate()) + " " + UnitGroup + .UNITS_IMPULSE + .getDefaultUnit().toString(), border)); + double ttw = motor.getAverageThrustEstimate() / (getStageWeight(stageWeights, i) + (motor + .getLaunchCG().weight * 9.80665)); + motorTable.addCell(ITextHelper.createCell(df.format(ttw) + ":1", border)); + + motorTable.addCell(ITextHelper.createCell(df.format(motorWeight) + " " + UnitGroup.UNITS_MASS + .getDefaultUnit().toString(), border)); + + final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS + .getDefaultUnit(); + motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) + + "/" + + motorUnit.toString(motor.getLength()) + " " + + motorUnit.toString(), border)); + } + PdfPCell c = new PdfPCell(motorTable); + c.setBorder(PdfPCell.LEFT); + c.setBorderWidthTop(0f); + parent.addCell(c); + } + + + /** + * Add the motor data for a motor configuration to the table. + * + * @param theRocket the rocket + * @param mid a motor configuration id + * @param parent the parent to which the motor data will be added + * @param leading the number of points for the leading + */ + 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.copy(); ++ Rocket duplicate= theRocket.copyWithOriginalID(); + Simulation simulation = Prefs.getBackgroundSimulation(duplicate); + simulation.getConditions().setMotorConfigurationID(mid); + + flight = PrintSimulationWorker.doit(simulation); + + if (flight != null) { + try { + final Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit(); + final Unit velocityUnit = UnitGroup.UNITS_VELOCITY.getDefaultUnit(); + final Unit flightUnit = UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit(); + + PdfPTable labelTable = new PdfPTable(2); + labelTable.setWidths(new int[]{3, 2}); + final Paragraph chunk = ITextHelper.createParagraph(stripBrackets( + theRocket.getMotorConfigurationNameOrDescription(mid)), PrintUtilities.BOLD); + chunk.setLeading(leading); + chunk.setSpacingAfter(3f); + + document.add(chunk); + + DecimalFormat df = new DecimalFormat("#,##0.0#"); + + 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(df.format(flight.getFlightTime()) + " " + flightUnit, 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(df.format( + flight.getLaunchRodVelocity()) + " " + velocityUnit, 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(df.format( + flight.getGroundHitVelocity()) + " " + velocityUnit, 2, 2)); + + //Add the table to the parent; have to wrap it in a cell + PdfPCell c = new PdfPCell(labelTable); + c.setBorder(PdfPCell.RIGHT); + c.setBorderWidthTop(0); + c.setTop(0); + parent.addCell(c); + } + catch (DocumentException e) { + e.printStackTrace(); + } + } + } + } + + /** + * Strip [] brackets from a string. + * + * @param target the original string + * + * @return target with [] removed + */ + private String stripBrackets (String target) { + return stripLeftBracket(stripRightBracket(target)); + } + + /** + * Strip [ from a string. + * + * @param target the original string + * + * @return target with [ removed + */ + private String stripLeftBracket (String target) { + return target.replace("[", ""); + } + + /** + * Strip ] from a string. + * + * @param target the original string + * + * @return target with ] removed + */ + private String stripRightBracket (String target) { + return target.replace("]", ""); + } + + /** + * Use a visitor to get the sorted list of Stage references, then from those 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 getStageWeights (Rocket rocket) { + rocket.accept(new ComponentVisitor(svs)); + svs.close(); + List stages = svs.getStages(); + for (int i = 0; i < stages.size(); i++) { + Double stage = stages.get(i); + stages.set(i, stage * 9.80665); + } + return stages; + } + + /** + * Compute the total stage weight from a list of stage weights. This sums up the weight of the given stage plus all + * stages that sit atop it (depend upon it for thrust). + * + * @param weights the list of stage weights, in Newtons + * @param stage a stage number, 0 being topmost stage + * + * @return the total weight of the stage and all stages sitting atop the given stage, in Newtons + */ + private double getStageWeight (List weights, int stage) { + + double result = 0d; + for (int i = 0; i <= stage; i++) { + result += weights.get(i); + } + return result; + } + } diff --cc src/net/sf/openrocket/rocketcomponent/BodyComponent.java index 884893d5,9eb970c6..97a12406 --- a/src/net/sf/openrocket/rocketcomponent/BodyComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/BodyComponent.java @@@ -59,9 -58,33 +58,20 @@@ public abstract class BodyComponent ext fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); } - - /** - * Check whether the given type can be added to this component. BodyComponents 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. - */ @Override - public boolean isCompatible(Class type) { - if (InternalComponent.class.isAssignableFrom(type)) - return true; - if (ExternalComponent.class.isAssignableFrom(type) && - !BodyComponent.class.isAssignableFrom(type)) - return true; - return false; + 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); + } + + } diff --cc src/net/sf/openrocket/rocketcomponent/BodyTube.java index 086c9efc,fd5eb4a4..5656c72b --- a/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@@ -15,10 -15,10 +15,10 @@@ import java.util.HashMap * @author Sampo Niskanen */ - public class BodyTube extends SymmetricComponent implements MotorMount { + public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial { - - private double radius=0; - private boolean autoRadius = false; // Radius chosen automatically based on parent component + + private double radius = 0; + private boolean autoRadius = false; // Radius chosen automatically based on parent component // When changing the inner radius, thickness is modified @@@ -56,13 -56,16 +56,16 @@@ this.thickness = thickness; } - + /************ Get/set component parameter methods ************/ - + /** * Return the outer radius of the body tube. + * + * @return the outside radius of the tube */ - public double getRadius() { + @Override + public double getOuterRadius () { if (autoRadius) { // Return auto radius from front or rear double r = -1; @@@ -88,9 -91,12 +91,12 @@@ * 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 */ - public void setRadius(double radius) { + @Override + public void setOuterRadius (double radius) { - if ((this.radius == radius) && (autoRadius==false)) + if ((this.radius == radius) && (autoRadius == false)) return; this.autoRadius = false; @@@ -123,27 -129,16 +129,21 @@@ @Override - public double getAftRadius() { - return getRadius(); - } - + public double getAftRadius() { return getOuterRadius(); } @Override - public double getForeRadius() { - return getRadius(); - } - + public double getForeRadius() { return getOuterRadius(); } @Override - public boolean isAftRadiusAutomatic() { return isRadiusAutomatic(); } - @Override - public boolean isForeRadiusAutomatic() { return isRadiusAutomatic(); } + public boolean isAftRadiusAutomatic() { + return isRadiusAutomatic(); + } + @Override + public boolean isForeRadiusAutomatic() { + return isRadiusAutomatic(); + } + @Override protected double getFrontAutoRadius() { if (isRadiusAutomatic()) { @@@ -155,9 -150,9 +155,9 @@@ return -1; } } - return getRadius(); + return getOuterRadius(); } - + @Override protected double getRearAutoRadius() { if (isRadiusAutomatic()) { @@@ -169,13 -164,15 +169,17 @@@ return -1; } } - return getRadius(); + return getOuterRadius(); } + + - + + + + + @Override public double getInnerRadius() { if (filled) return 0; @@@ -206,9 -214,9 +221,9 @@@ */ @Override public double getRadius(double x) { - return getRadius(); + return getOuterRadius(); } - + /** * Returns the inner radius at the position x. If the tube is filled, returns always zero. */ @@@ -217,10 -225,10 +232,10 @@@ if (filled) return 0.0; else - return Math.max(getRadius() - thickness, 0); + return Math.max(getOuterRadius()-thickness,0); } - + /** * Returns the body tube's center of gravity. */ @@@ -234,29 -242,30 +249,30 @@@ */ @Override public double getComponentVolume() { - double r = getRadius(); + double r = getOuterRadius(); if (filled) - return getFilledVolume(r,length); + return getFilledVolume(r, length); else - return getFilledVolume(r,length) - getFilledVolume(getInnerRadius(0),length); + return getFilledVolume(r, length) - getFilledVolume(getInnerRadius(0), length); } @Override public double getLongitudalUnitInertia() { // 1/12 * (3 * (r1^2 + r2^2) + h^2) - return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getRadius()) + MathUtil.pow2(getLength())) / 12; + 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(getRadius())) / 2; + return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius()))/2; } - - + + /** * Helper function for cylinder volume. */ @@@ -274,31 -283,13 +290,31 @@@ @Override public Collection getComponentBounds() { Collection bounds = new ArrayList(8); - double r = getRadius(); + double r = getOuterRadius(); - addBound(bounds,0,r); - addBound(bounds,length,r); + addBound(bounds, 0, r); + 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. + */ + @Override + public boolean isCompatible(Class type) { + if (InternalComponent.class.isAssignableFrom(type)) + return true; + if (ExternalComponent.class.isAssignableFrom(type) && + !BodyComponent.class.isAssignableFrom(type)) + return true; + return false; + } + //////////////// Motor mount ///////////////// @Override diff --cc src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index f51f4650,1b80e426..ce640215 --- a/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java +++ b/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java @@@ -1,17 -1,14 +1,17 @@@ package net.sf.openrocket.rocketcomponent; - import java.util.ArrayList; - import java.util.Arrays; - +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Coordinate; + import java.util.ArrayList; + import java.util.Arrays; + public class FreeformFinSet extends FinSet { - + private static final LogHelper log = Application.getLogger(); + private ArrayList points = new ArrayList(); public FreeformFinSet() { diff --cc src/net/sf/openrocket/rocketcomponent/InnerTube.java index 10c0e7ee,0a0b6327..036daef6 --- a/src/net/sf/openrocket/rocketcomponent/InnerTube.java +++ b/src/net/sf/openrocket/rocketcomponent/InnerTube.java @@@ -1,11 -1,6 +1,7 @@@ package net.sf.openrocket.rocketcomponent; - import java.util.ArrayList; - import java.util.HashMap; - import java.util.List; - import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; @@@ -314,10 -305,19 +314,19 @@@ public class InnerTube extends Thicknes 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. diff --cc src/net/sf/openrocket/rocketcomponent/LaunchLug.java index 6e3f7b39,2670bc60..500e9063 --- a/src/net/sf/openrocket/rocketcomponent/LaunchLug.java +++ b/src/net/sf/openrocket/rocketcomponent/LaunchLug.java @@@ -3,12 -6,9 +6,10 @@@ 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; + - public class LaunchLug extends ExternalComponent { - + public class LaunchLug extends ExternalComponent implements Coaxial { + private double radius; private double thickness; @@@ -27,26 -27,26 +28,26 @@@ } - public double getRadius() { + public double getOuterRadius () { return radius; } - + - public void setRadius(double radius) { + public void setOuterRadius (double radius) { if (MathUtil.equals(this.radius, radius)) return; this.radius = radius; this.thickness = Math.min(this.thickness, this.radius); fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); } - + public double getInnerRadius() { - return radius-thickness; + return radius - thickness; } - + public void setInnerRadius(double innerRadius) { - setRadius(innerRadius + thickness); + setOuterRadius(innerRadius + thickness); } - + public double getThickness() { return thickness; } @@@ -174,24 -175,31 +175,35 @@@ @Override public double getLongitudalUnitInertia() { // 1/12 * (3 * (r1^2 + r2^2) + h^2) - return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getRadius()) + MathUtil.pow2(getLength())) / 12; + 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(getRadius())) / 2; + return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius()))/2; } - - + + @Override + public boolean allowsChildren() { + return false; + } + @Override public boolean isCompatible(Class 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); + } + } diff --cc src/net/sf/openrocket/rocketcomponent/Rocket.java index 7ba088b9,a0c923ed..509c9ff5 --- a/src/net/sf/openrocket/rocketcomponent/Rocket.java +++ b/src/net/sf/openrocket/rocketcomponent/Rocket.java @@@ -1,26 -1,21 +1,25 @@@ package net.sf.openrocket.rocketcomponent; - import java.util.ArrayList; - 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.Chars; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.UniqueID; + import javax.swing.event.ChangeListener; + import javax.swing.event.EventListenerList; + import java.util.ArrayList; + 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; + /** * Base for all rocket components. This is the "starting point" for all rocket trees. diff --cc src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 34ae962f,71d2c139..02d4c1d0 --- a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@@ -1,32 -1,27 +1,31 @@@ package net.sf.openrocket.rocketcomponent; - import java.awt.Color; - import java.util.ArrayList; - import java.util.Collection; - import java.util.Collections; - import java.util.EmptyStackException; - import java.util.Iterator; - import java.util.List; - import java.util.NoSuchElementException; - import java.util.Stack; - - import javax.swing.event.ChangeListener; - +import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.logging.TraceException; +import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LineStyle; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.UniqueID; + import javax.swing.event.ChangeListener; + import java.awt.Color; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; + import java.util.EmptyStackException; + import java.util.Iterator; + import java.util.List; + import java.util.NoSuchElementException; + import java.util.Stack; -import java.util.UUID; + -public abstract class RocketComponent implements ChangeSource, Cloneable, +public abstract class RocketComponent implements ChangeSource, Cloneable, - Iterable { + Iterable , Visitable { - + private static final LogHelper log = Application.getLogger(); + /* * Text is suitable to the form * Position relative to: @@@ -130,16 -118,12 +129,12 @@@ // These must not fire any events, due to Rocket undo system initialization this.name = getComponentName(); this.relativePosition = relativePosition; - this.id = UUID.randomUUID().toString(); + newID(); } - - + //////////// Methods that must be implemented //////////// - //////////// Methods that must be implemented //////////// - - /** * Static component name. The name may not vary of the parameters, it must be static. */ @@@ -366,14 -318,24 +361,24 @@@ clone.children.add(childCopy); childCopy.parent = clone; } - + return clone; } - - + + + /** + * 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 ////////// diff --cc src/net/sf/openrocket/rocketcomponent/Stage.java index 361f5023,ed2fc7a9..b16cd4b6 --- a/src/net/sf/openrocket/rocketcomponent/Stage.java +++ b/src/net/sf/openrocket/rocketcomponent/Stage.java @@@ -1,28 -1,32 +1,38 @@@ package net.sf.openrocket.rocketcomponent; public class Stage extends ComponentAssembly { - + - @Override - public String getComponentName() { - return "Stage"; - } + @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 only BodyComponents to be added. + * 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. - * @return Whether such a component can be added. - */ - @Override - public boolean isCompatible(Class<? extends RocketComponent> type) { - return BodyComponent.class.isAssignableFrom(type); - } - + * + * @param type The RocketComponent class type to add. + * + * @return Whether such a component can be added. + */ + @Override + 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); + } } diff --cc src/net/sf/openrocket/rocketcomponent/Transition.java index 53b1a196,f26666ae..81140a66 --- a/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/src/net/sf/openrocket/rocketcomponent/Transition.java @@@ -354,13 -357,13 +357,13 @@@ public class Transition extends Symmetr /** * Numerically solve clipLength from the equation * r1 == type.getRadius(clipLength,r2,clipLength+length) - * using a binary search. It assumes getRadius() to be monotonically increasing. + * using a binary search. It assumes getOuterRadius() to be monotonically increasing. */ private void calculateClip(double r1, double r2) { - double min=0, max=length; + double min = 0, max = length; if (r1 >= r2) { - double tmp=r1; + double tmp = r1; r1 = r2; r2 = tmp; } @@@ -497,23 -500,17 +500,32 @@@ 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. + */ + @Override + public boolean isCompatible(Class<? extends RocketComponent> type) { + if (InternalComponent.class.isAssignableFrom(type)) + return true; + return false; + } + + /** * An enumeration listing the possible shapes of transitions. *