From: plaa Date: Thu, 24 Nov 2011 19:19:39 +0000 (+0000) Subject: version 1.1.9 X-Git-Tag: upstream/1.1.9^2~1 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=36a7942e7433b8493e4142a5f3dd85a956bb498b;p=debian%2Fopenrocket version 1.1.9 git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@208 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/ChangeLog b/ChangeLog index b678d506..86aede34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ +2011-11-24 Sampo Niskanen + + * Released version 1.1.9 + 2011-11-18 Doug Pedrick - * Printable Fin Marking Guides, Transitions, and Nose Cones (simple projection only) + * Printable Fin Marking Guides, Transitions, and Nose Cones + +2011-10-20 Sampo Niskanen + + * [BUG] NPE if plot data type is not present 2011-10-11 Sampo Niskanen diff --git a/README.TXT b/README.TXT index 6f969448..c3c68458 100644 --- a/README.TXT +++ b/README.TXT @@ -2,7 +2,7 @@ OpenRocket - an Open Source model rocket simulator -------------------------------------------------- -Copyright (C) 2007-2010 Sampo Niskanen +Copyright (C) 2007-2011 Sampo Niskanen For license information see the file LICENSE.TXT. @@ -25,5 +25,8 @@ Contributions have been made by: -------------------------------- Sampo Niskanen, main developer -Doug Pedrick, support for reading RockSim designs +Doug Pedrick, support for reading RockSim designs, printing +Richard Graham, geodetic computations +Boris du Reau, internationalization +Tripoli France, Tripoli Spain, Stefan Lobas / ERIG, translations diff --git a/ReleaseNotes b/ReleaseNotes index 140644ae..491e9846 100644 --- a/ReleaseNotes +++ b/ReleaseNotes @@ -1,3 +1,13 @@ +OpenRocket 1.1.9 (2011-11-24): +------------------------------- + +This release calculates rocket flight in real-world coordinates and +takes into account geodetic effects (including coriolis effect) thanks +to work by Richard Graham. Printing of transitions, nose cone +profiles and fin marking guides is available thanks to Doug Pedrick. +It also contains some usability features and bug fixes. + + OpenRocket 1.1.8 (2011-08-25): ------------------------------- diff --git a/build.properties b/build.properties index 175fedc9..9a2cca35 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ # The OpenRocket build version -build.version=1.1.9pre +build.version=1.1.9 # The source of the package. When building a package for a specific diff --git a/src/net/sf/openrocket/gui/dialogs/AboutDialog.java b/src/net/sf/openrocket/gui/dialogs/AboutDialog.java index 9a10d9c3..5f42865b 100644 --- a/src/net/sf/openrocket/gui/dialogs/AboutDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/AboutDialog.java @@ -30,7 +30,8 @@ public class AboutDialog extends JDialog { "OpenRocket has been developed by:

" + "Sampo Niskanen (main developer)
" + "Doug Pedrick (RockSim file format, printing)
" + - "Boris du Reau (internationalization, translation lead)

" + + "Boris du Reau (internationalization, translation lead)
" + + "Richard Graham (geodetic computations)

" + "Translations by:

" + "Tripoli France (French)
" + "Stefan Lobas / ERIG e.V. (German)
" + diff --git a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java index 00591c94..92c2dac8 100644 --- a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java @@ -88,8 +88,6 @@ public class SimulationEditDialog extends JDialog { private static final Translator trans = Application.getTranslator(); - // FIXME: NPE if FlightDataType has disappeared - public SimulationEditDialog(Window parent, Simulation s) { this(parent, s, 0); } diff --git a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java index fc4dc5af..9ac4a369 100644 --- a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java @@ -123,7 +123,7 @@ public class SimulationRunDialog extends JDialog { //// Simulation time: panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Simutime") + " "), "gapright para"); timeLabel = new JLabel(""); - panel.add(timeLabel, "growx, wrap rel"); + panel.add(timeLabel, "growx, wmin 200lp, wrap rel"); //// Altitude: panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Altitude") + " ")); diff --git a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java index 898d7f67..f2afcae6 100644 --- a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java +++ b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java @@ -118,8 +118,6 @@ public class SimulationPlotPanel extends JPanel { } } - // FIXME: Bugs when expected branch is not present - configurationSelector.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { @@ -189,7 +187,7 @@ public class SimulationPlotPanel extends JPanel { typeSelectorPanel = new JPanel(new MigLayout("gapy rel")); JScrollPane scroll = new JScrollPane(typeSelectorPanel); - this.add(scroll, "spany 2, height 10px, grow 100, gapright para"); + this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para"); //// Flight events @@ -379,10 +377,6 @@ public class SimulationPlotPanel extends JPanel { private JComboBox axisSelector; - public PlotTypeSelector(int index, FlightDataType type) { - this(index, type, null, -1); - } - public PlotTypeSelector(int plotIndex, FlightDataType type, Unit unit, int position) { super(new MigLayout("ins 0")); diff --git a/src/net/sf/openrocket/gui/print/DesignReport.java b/src/net/sf/openrocket/gui/print/DesignReport.java index d149b83c..e0e22458 100644 --- a/src/net/sf/openrocket/gui/print/DesignReport.java +++ b/src/net/sf/openrocket/gui/print/DesignReport.java @@ -6,9 +6,6 @@ package net.sf.openrocket.gui.print; import java.awt.Graphics2D; import java.io.IOException; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; @@ -152,7 +149,7 @@ public class DesignReport { PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN); Rocket rocket = rocketDocument.getRocket(); - final Configuration configuration = rocket.getDefaultConfiguration(); + final Configuration configuration = rocket.getDefaultConfiguration().clone(); configuration.setAllStages(); PdfContentByte canvas = writer.getDirectContent(); @@ -219,8 +216,6 @@ public class DesignReport { String[] motorIds = rocket.getMotorConfigurationIDs(); - List stageMasses = getStageMasses(rocket); - for (int j = 0; j < motorIds.length; j++) { String motorId = motorIds[j]; if (motorId != null) { @@ -244,29 +239,6 @@ public class DesignReport { } } - /** - * 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 getMotorList(final Rocket theRocket, final String theMid) { - Iterator components = theRocket.iterator(); - final List motorList = new ArrayList(); - 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; - } /** * Paint a diagram of the rocket into the PDF document. @@ -545,27 +517,4 @@ public class DesignReport { return target.replace("]", ""); } - - /** - * Return a list of cumulative stage masses. The latter masses include the mass - * of the upper stages as well. - * - * @param rocket the rocket - * @return a list containing the cumulative stage masses - */ - private List getStageMasses(final Rocket rocket) { - List masses = new ArrayList(); - int stages = rocket.getStageCount(); - - Configuration config = new Configuration(rocket); - MassCalculator calc = new BasicMassCalculator(); - - for (int i = 0; i < stages; i++) { - config.setToStage(i); - masses.add(calc.getCG(config, MassCalcType.NO_MOTORS).weight); - } - - return masses; - } - } diff --git a/src/net/sf/openrocket/gui/print/PrintFigure.java b/src/net/sf/openrocket/gui/print/PrintFigure.java index ae909269..3f4655c6 100644 --- a/src/net/sf/openrocket/gui/print/PrintFigure.java +++ b/src/net/sf/openrocket/gui/print/PrintFigure.java @@ -11,23 +11,24 @@ import net.sf.openrocket.rocketcomponent.Configuration; * to fit in the width of the chosen page size. */ public class PrintFigure extends RocketFigure { - - /** - * Constructor. - * - * @param configuration the configuration - */ - public PrintFigure (final Configuration configuration) { - super(configuration); - } - - protected double computeTy (int heightPx) { - super.computeTy(heightPx); - return 0; - } - - public void setScale (final double theScale) { - this.scale = theScale; //dpi/0.0254*scaling; - updateFigure(); - } + + /** + * Constructor. + * + * @param configuration the configuration + */ + public PrintFigure(final Configuration configuration) { + super(configuration); + } + + @Override + protected double computeTy(int heightPx) { + super.computeTy(heightPx); + return 0; + } + + public void setScale(final double theScale) { + this.scale = theScale; //dpi/0.0254*scaling; + updateFigure(); + } } diff --git a/src/net/sf/openrocket/gui/print/PrintableContext.java b/src/net/sf/openrocket/gui/print/PrintableContext.java index 1f37435d..4a5ddcac 100644 --- a/src/net/sf/openrocket/gui/print/PrintableContext.java +++ b/src/net/sf/openrocket/gui/print/PrintableContext.java @@ -4,113 +4,118 @@ */ package net.sf.openrocket.gui.print; -import java.util.*; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; /** * Instances of this class are meant to keep track of what the user has selected to be printed. */ public class PrintableContext implements Comparable, Iterable { - - /** - * The stage number. May be null for printables that have no stage meaning. - */ - private Set stageNumber; - - /** - * The type of thing to be printed. - */ - 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> previous = new TreeMap>(); - - /** - * Constructor. - */ - public PrintableContext () { - } - - /** - * Constructor. - * - * @param theStageNumber the stage number of the printable; may be null if not applicable - * @param thePrintable the type of the thing to be printed - * - * @throws IllegalArgumentException thrown if thePrintable.isStageSpecific - */ - private PrintableContext (final Set theStageNumber, final OpenRocketPrintable thePrintable) - throws IllegalArgumentException { - if (thePrintable.isStageSpecific() && theStageNumber == null) { - throw new IllegalArgumentException("A stage number must be provided when a printable is stage specific."); - } - stageNumber = theStageNumber; - printable = thePrintable; - } - - /** - * 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 stages = previous.get(thePrintable); - if (stages == null) { - stages = new TreeSet(); - previous.put(thePrintable, stages); - } - if (theStageNumber != null) { - stages.add(theStageNumber); - } - } - - /** PrintableContext iterator. */ - public Iterator iterator () { - return new Iterator() { - - Iterator keyIter = previous.keySet().iterator(); - - @Override - public boolean hasNext () { - return keyIter.hasNext(); - } - - @Override - public PrintableContext next () { - final OpenRocketPrintable key = keyIter.next(); - return new PrintableContext(previous.get(key), key); - } - - @Override - public void remove () { - } - }; - - } - - /** - * Get the stage number, if it's applicable to the printable. - * - * @return the stage number - */ - public Set getStageNumber () { - return stageNumber; - } - - /** - * Get the printable. - * - * @return the printable - */ - public OpenRocketPrintable getPrintable () { - return printable; - } - - @Override - public int compareTo (final PrintableContext other) { - return this.printable.getPrintOrder() - other.printable.getPrintOrder(); - } - + + /** + * The stage number. May be null for printables that have no stage meaning. + */ + private Set stageNumber; + + /** + * The type of thing to be printed. + */ + 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> previous = new TreeMap>(); + + /** + * Constructor. + */ + public PrintableContext() { + } + + /** + * Constructor. + * + * @param theStageNumber the stage number of the printable; may be null if not applicable + * @param thePrintable the type of the thing to be printed + * + * @throws IllegalArgumentException thrown if thePrintable.isStageSpecific + */ + private PrintableContext(final Set theStageNumber, final OpenRocketPrintable thePrintable) + throws IllegalArgumentException { + if (thePrintable.isStageSpecific() && theStageNumber == null) { + throw new IllegalArgumentException("A stage number must be provided when a printable is stage specific."); + } + stageNumber = theStageNumber; + printable = thePrintable; + } + + /** + * 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 stages = previous.get(thePrintable); + if (stages == null) { + stages = new TreeSet(); + previous.put(thePrintable, stages); + } + if (theStageNumber != null) { + stages.add(theStageNumber); + } + } + + /** PrintableContext iterator. */ + @Override + public Iterator iterator() { + return new Iterator() { + + Iterator keyIter = previous.keySet().iterator(); + + @Override + public boolean hasNext() { + return keyIter.hasNext(); + } + + @Override + public PrintableContext next() { + final OpenRocketPrintable key = keyIter.next(); + return new PrintableContext(previous.get(key), key); + } + + @Override + public void remove() { + } + }; + + } + + /** + * Get the stage number, if it's applicable to the printable. + * + * @return the stage number + */ + public Set getStageNumber() { + return stageNumber; + } + + /** + * Get the printable. + * + * @return the printable + */ + public OpenRocketPrintable getPrintable() { + return printable; + } + + @Override + public int compareTo(final PrintableContext other) { + return this.printable.getPrintOrder() - other.printable.getPrintOrder(); + } + } diff --git a/src/net/sf/openrocket/gui/print/PrintableNoseCone.java b/src/net/sf/openrocket/gui/print/PrintableNoseCone.java index 77ea45b7..78afe6f0 100644 --- a/src/net/sf/openrocket/gui/print/PrintableNoseCone.java +++ b/src/net/sf/openrocket/gui/print/PrintableNoseCone.java @@ -1,56 +1,59 @@ package net.sf.openrocket.gui.print; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; + import net.sf.openrocket.gui.rocketfigure.TransitionShapes; import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.util.Transformation; -import java.awt.*; - public class PrintableNoseCone extends AbstractPrintableTransition { - - /** - * If the component to be drawn is a nose cone, save a reference to it. - */ - private NoseCone target; - - /** - * Construct a printable nose cone. - * - * @param noseCone the component to print - */ - public PrintableNoseCone(Transition noseCone) { - super(false, noseCone); - } - - @Override - protected void init(Transition component) { - - target = (NoseCone) component; - double radius = target.getForeRadius(); - if (radius < target.getAftRadius()) { - radius = target.getAftRadius(); - } - setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX, - (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY); - } - - /** - * Draw a nose cone. - * - * @param g2 the graphics context - */ - protected void draw(Graphics2D g2) { - Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1)); - - if (shapes != null && shapes.length > 0) { - Rectangle r = shapes[0].getBounds(); - g2.translate(marginX + r.getHeight() / 2, marginY); - g2.rotate(Math.PI / 2); - for (Shape shape : shapes) { - g2.draw(shape); - } - g2.rotate(-Math.PI / 2); - } - } + + /** + * If the component to be drawn is a nose cone, save a reference to it. + */ + private NoseCone target; + + /** + * Construct a printable nose cone. + * + * @param noseCone the component to print + */ + public PrintableNoseCone(Transition noseCone) { + super(false, noseCone); + } + + @Override + protected void init(Transition component) { + + target = (NoseCone) component; + double radius = target.getForeRadius(); + if (radius < target.getAftRadius()) { + radius = target.getAftRadius(); + } + setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX, + (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY); + } + + /** + * Draw a nose cone. + * + * @param g2 the graphics context + */ + @Override + protected void draw(Graphics2D g2) { + Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1)); + + if (shapes != null && shapes.length > 0) { + Rectangle r = shapes[0].getBounds(); + g2.translate(marginX + r.getHeight() / 2, marginY); + g2.rotate(Math.PI / 2); + for (Shape shape : shapes) { + g2.draw(shape); + } + g2.rotate(-Math.PI / 2); + } + } } diff --git a/src/net/sf/openrocket/gui/print/PrintableTransition.java b/src/net/sf/openrocket/gui/print/PrintableTransition.java index c8e61761..a70703da 100644 --- a/src/net/sf/openrocket/gui/print/PrintableTransition.java +++ b/src/net/sf/openrocket/gui/print/PrintableTransition.java @@ -1,14 +1,15 @@ package net.sf.openrocket.gui.print; -import net.sf.openrocket.rocketcomponent.Transition; - -import java.awt.*; +import java.awt.BasicStroke; +import java.awt.Graphics2D; import java.awt.geom.Arc2D; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.Point2D; +import net.sf.openrocket.rocketcomponent.Transition; + /** * This class allows for a Transition to be printable. It does so by decorating an existing transition (which will not be * modified) and rendering it within a JPanel. The JPanel is not actually visualized on a display, but instead renders @@ -18,188 +19,189 @@ import java.awt.geom.Point2D; * may be to draw a myriahedral projection that can be cut out and bent to form the shape. */ public class PrintableTransition extends AbstractPrintableTransition { - - /** - * Dashed array value. - */ - private final static float dash1[] = {4.0f}; - /** - * The dashed stroke for glue tab. - */ - private final static BasicStroke dashed = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 10.0f, dash1, 0.0f); - - /** - * The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs. - * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system. - */ - private Path2D gp; - - /** - * The glue tab. - */ - private Path2D glueTab1; - - /** - * The alignment marks. - */ - private Line2D tick1, tick2; - - /** - * The x coordinates for the two ticks drawn at theta degrees. - */ - private int tick3X, tick4X; - - /** - * The angle, in degrees. - */ - private float theta; - - /** - * The x,y coordinates for where the virtual circle center is located. - */ - private int circleCenterX, circleCenterY; - - /** - * Constructor. - * - * @param transition the transition to print - */ - public PrintableTransition(Transition transition) { - super(false, transition); - } - - @Override - protected void init(Transition component) { - - double r1 = component.getAftRadius(); - double r2 = component.getForeRadius(); - - //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different. - if (r1 > r2) { - r1 = r2; - r2 = component.getAftRadius(); - } - double len = component.getLength(); - double v = r2 - r1; - double tmp = Math.sqrt(v * v + len * len); - double factor = tmp / v; - - theta = (float) (360d * v / tmp); - - int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor); - int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor); - - int x = marginX; - int tabOffset = 35; - int y = tabOffset + marginY; - - Arc2D.Double outerArc = new Arc2D.Double(); - Arc2D.Double innerArc = new Arc2D.Double(); - - //If the arcs are more than 3/4 of a circle, then assume the height (y) is the same as the radius of the bigger arc. - if (theta >= 270) { - y += r2InPoints; - } - //If the arc is between 1/2 and 3/4 of a circle, then compute the actual height based upon the angle and radius - //of the bigger arc. - else if (theta >= 180) { - double thetaRads = Math.toRadians(theta - 180); - y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads)); - } - - circleCenterY = y; - circleCenterX = r2InPoints + x; - - //Create the larger arc. - outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN); - - //Create the smaller arc. - innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN); - - //Create the line between the start of the larger arc and the start of the smaller arc. - Path2D.Double line = new Path2D.Double(); - line.setWindingRule(Path2D.WIND_NON_ZERO); - line.moveTo(x, y); - final int width = r2InPoints - r1InPoints; - line.lineTo(width + x, y); - - //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc. - Path2D.Double closingLine = new Path2D.Double(); - closingLine.setWindingRule(Path2D.WIND_NON_ZERO); - Point2D innerArcEndPoint = innerArc.getEndPoint(); - closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY()); - Point2D outerArcEndPoint = outerArc.getEndPoint(); - closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY()); - - //Add all shapes to the polygon path. - gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); - gp.append(line, false); - gp.append(outerArc, false); - gp.append(closingLine, false); - gp.append(innerArc, false); - - //Create the glue tab. - glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); - glueTab1.moveTo(x, y); - glueTab1.lineTo(x + tabOffset, y - tabOffset); - glueTab1.lineTo(width + x - tabOffset, y - tabOffset); - glueTab1.lineTo(width + x, y); - - //Create tick marks for alignment, 1/4 of the width in from either edge - int fromEdge = width / 4; - final int tickLength = 8; - //Upper left - tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength); - //Upper right - tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength); - - tick3X = r2InPoints - fromEdge; - tick4X = r1InPoints + fromEdge; - - setSize(gp.getBounds().width, gp.getBounds().height + tabOffset); - } - - /** - * Draw alignment marks on an angle. - * - * @param g2 the graphics context - * @param x the center of the circle's x coordinate - * @param y the center of the circle's y - * @param line the line to draw - * @param theta the angle - */ - private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) { - g2.translate(x, y); - g2.rotate(Math.toRadians(-theta)); - g2.draw(line); - g2.rotate(Math.toRadians(theta)); - g2.translate(-x, -y); - } - - /** - * Draw a transition. - * - * @param g2 the graphics context - */ - protected void draw(Graphics2D g2) { - //Render it. - g2.draw(gp); - g2.draw(tick1); - g2.draw(tick2); - drawAlignmentMarks(g2, circleCenterX, - circleCenterY, - new Line2D.Float(-tick3X, 0, -tick3X, -8), - theta); - drawAlignmentMarks(g2, circleCenterX, - circleCenterY, - new Line2D.Float(-tick4X, 0, -tick4X, -8), - theta); - - g2.setStroke(dashed); - g2.draw(glueTab1); - } - + + /** + * Dashed array value. + */ + private final static float dash1[] = { 4.0f }; + /** + * The dashed stroke for glue tab. + */ + private final static BasicStroke dashed = new BasicStroke(1.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 10.0f, dash1, 0.0f); + + /** + * The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs. + * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system. + */ + private Path2D gp; + + /** + * The glue tab. + */ + private Path2D glueTab1; + + /** + * The alignment marks. + */ + private Line2D tick1, tick2; + + /** + * The x coordinates for the two ticks drawn at theta degrees. + */ + private int tick3X, tick4X; + + /** + * The angle, in degrees. + */ + private float theta; + + /** + * The x,y coordinates for where the virtual circle center is located. + */ + private int circleCenterX, circleCenterY; + + /** + * Constructor. + * + * @param transition the transition to print + */ + public PrintableTransition(Transition transition) { + super(false, transition); + } + + @Override + protected void init(Transition component) { + + double r1 = component.getAftRadius(); + double r2 = component.getForeRadius(); + + //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different. + if (r1 > r2) { + r1 = r2; + r2 = component.getAftRadius(); + } + double len = component.getLength(); + double v = r2 - r1; + double tmp = Math.sqrt(v * v + len * len); + double factor = tmp / v; + + theta = (float) (360d * v / tmp); + + int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor); + int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor); + + int x = marginX; + int tabOffset = 35; + int y = tabOffset + marginY; + + Arc2D.Double outerArc = new Arc2D.Double(); + Arc2D.Double innerArc = new Arc2D.Double(); + + //If the arcs are more than 3/4 of a circle, then assume the height (y) is the same as the radius of the bigger arc. + if (theta >= 270) { + y += r2InPoints; + } + //If the arc is between 1/2 and 3/4 of a circle, then compute the actual height based upon the angle and radius + //of the bigger arc. + else if (theta >= 180) { + double thetaRads = Math.toRadians(theta - 180); + y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads)); + } + + circleCenterY = y; + circleCenterX = r2InPoints + x; + + //Create the larger arc. + outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN); + + //Create the smaller arc. + innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN); + + //Create the line between the start of the larger arc and the start of the smaller arc. + Path2D.Double line = new Path2D.Double(); + line.setWindingRule(Path2D.WIND_NON_ZERO); + line.moveTo(x, y); + final int width = r2InPoints - r1InPoints; + line.lineTo(width + x, y); + + //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc. + Path2D.Double closingLine = new Path2D.Double(); + closingLine.setWindingRule(Path2D.WIND_NON_ZERO); + Point2D innerArcEndPoint = innerArc.getEndPoint(); + closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY()); + Point2D outerArcEndPoint = outerArc.getEndPoint(); + closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY()); + + //Add all shapes to the polygon path. + gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); + gp.append(line, false); + gp.append(outerArc, false); + gp.append(closingLine, false); + gp.append(innerArc, false); + + //Create the glue tab. + glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); + glueTab1.moveTo(x, y); + glueTab1.lineTo(x + tabOffset, y - tabOffset); + glueTab1.lineTo(width + x - tabOffset, y - tabOffset); + glueTab1.lineTo(width + x, y); + + //Create tick marks for alignment, 1/4 of the width in from either edge + int fromEdge = width / 4; + final int tickLength = 8; + //Upper left + tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength); + //Upper right + tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength); + + tick3X = r2InPoints - fromEdge; + tick4X = r1InPoints + fromEdge; + + setSize(gp.getBounds().width, gp.getBounds().height + tabOffset); + } + + /** + * Draw alignment marks on an angle. + * + * @param g2 the graphics context + * @param x the center of the circle's x coordinate + * @param y the center of the circle's y + * @param line the line to draw + * @param theta the angle + */ + private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) { + g2.translate(x, y); + g2.rotate(Math.toRadians(-theta)); + g2.draw(line); + g2.rotate(Math.toRadians(theta)); + g2.translate(-x, -y); + } + + /** + * Draw a transition. + * + * @param g2 the graphics context + */ + @Override + protected void draw(Graphics2D g2) { + //Render it. + g2.draw(gp); + g2.draw(tick1); + g2.draw(tick2); + drawAlignmentMarks(g2, circleCenterX, + circleCenterY, + new Line2D.Float(-tick3X, 0, -tick3X, -8), + theta); + drawAlignmentMarks(g2, circleCenterX, + circleCenterY, + new Line2D.Float(-tick4X, 0, -tick4X, -8), + theta); + + g2.setStroke(dashed); + g2.draw(glueTab1); + } + } diff --git a/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index 60cc67b8..8381313c 100644 --- a/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -109,7 +109,6 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change private SimulationWorker backgroundSimulationWorker = null; - private boolean dirty = false; private List listeners = new ArrayList(); diff --git a/src/net/sf/openrocket/models/gravity/GravityModel.java b/src/net/sf/openrocket/models/gravity/GravityModel.java index 2c60b9b1..6bee52a7 100644 --- a/src/net/sf/openrocket/models/gravity/GravityModel.java +++ b/src/net/sf/openrocket/models/gravity/GravityModel.java @@ -1,18 +1,18 @@ package net.sf.openrocket.models.gravity; -//import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.WorldCoordinate; /** - * An interface to modelling gravitational acceleration. + * An interface for modeling gravitational acceleration. * * @author Sampo Niskanen */ public interface GravityModel extends Monitorable { /** - * Compute the gravity at a given world coordinate + * Compute the gravitational acceleration at a given world coordinate + * * @param wc the world coordinate location * @return gravitational acceleration in m/s/s */ diff --git a/src/net/sf/openrocket/models/gravity/WGSGravityModel.java b/src/net/sf/openrocket/models/gravity/WGSGravityModel.java index 253d4a41..41fb5c23 100644 --- a/src/net/sf/openrocket/models/gravity/WGSGravityModel.java +++ b/src/net/sf/openrocket/models/gravity/WGSGravityModel.java @@ -4,7 +4,7 @@ import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.WorldCoordinate; /** - * A gravity model based on the WGS84 elipsoid. + * A gravity model based on the WGS84 ellipsoid. * * @author Richard Graham */ @@ -44,7 +44,7 @@ public class WGSGravityModel implements GravityModel { // Apply correction due to altitude. Note this assumes a spherical earth, but it is a small correction // so it probably doesn't really matter. Also does not take into account gravity of the atmosphere, again // correction could be done but not really necessary. - double g_alt = g_0 * Math.pow(WorldCoordinate.REARTH / (WorldCoordinate.REARTH + wc.getAltitude()), 2); + double g_alt = g_0 * MathUtil.pow2(WorldCoordinate.REARTH / (WorldCoordinate.REARTH + wc.getAltitude())); return g_alt; } diff --git a/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java b/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java index e971eed9..85be9120 100644 --- a/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java +++ b/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java @@ -93,8 +93,6 @@ public abstract class AbstractSimulationStepper implements SimulationStepper { } // Compute conditions - //double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude(); - //gravity = status.getSimulationConditions().getGravityModel().getGravity(altitude); gravity = status.getSimulationConditions().getGravityModel().getGravity(status.getRocketWorldPosition()); // Call post-listener diff --git a/src/net/sf/openrocket/util/GeodeticComputationStrategy.java b/src/net/sf/openrocket/util/GeodeticComputationStrategy.java index 6f1fb53a..f8a37a09 100644 --- a/src/net/sf/openrocket/util/GeodeticComputationStrategy.java +++ b/src/net/sf/openrocket/util/GeodeticComputationStrategy.java @@ -54,7 +54,7 @@ public enum GeodeticComputationStrategy { double newAlt = location.getAltitude() + delta.z; // bearing (in radians, clockwise from north); - // d/R is the angular distance (in radians), where d is the distance traveled and R is the earth’s radius + // d/R is the angular distance (in radians), where d is the distance traveled and R is the earth's radius double d = MathUtil.hypot(delta.x, delta.y); // Check for zero movement before computing bearing @@ -99,7 +99,7 @@ public enum GeodeticComputationStrategy { double newAlt = location.getAltitude() + delta.z; // bearing (in radians, clockwise from north); - // d/R is the angular distance (in radians), where d is the distance traveled and R is the earth’s radius + // d/R is the angular distance (in radians), where d is the distance traveled and R is the earth's radius double d = MathUtil.hypot(delta.x, delta.y); // Check for zero movement before computing bearing diff --git a/src/net/sf/openrocket/util/LineStyle.java b/src/net/sf/openrocket/util/LineStyle.java index 2bb3af6d..fc2b4fdc 100644 --- a/src/net/sf/openrocket/util/LineStyle.java +++ b/src/net/sf/openrocket/util/LineStyle.java @@ -25,10 +25,6 @@ public enum LineStyle { DASHDOT("LineStyle.Dash-dotted", new float[] { 8f, 3f, 2f, 3f }); private static final Translator trans = Application.getTranslator(); - static { - System.out.println("*** LineStyle initialized trans:" + trans + " ***"); - System.err.println("*** LineStyle initialized ***"); - } private final String name; private final float[] dashes; diff --git a/test/net/sf/openrocket/models/gravity/WGSGravityModelTest.java b/test/net/sf/openrocket/models/gravity/WGSGravityModelTest.java new file mode 100644 index 00000000..a0aea634 --- /dev/null +++ b/test/net/sf/openrocket/models/gravity/WGSGravityModelTest.java @@ -0,0 +1,42 @@ +package net.sf.openrocket.models.gravity; + +import static org.junit.Assert.assertEquals; +import net.sf.openrocket.util.WorldCoordinate; + +import org.junit.Test; + + +public class WGSGravityModelTest { + + private WGSGravityModel model = new WGSGravityModel(); + + @Test + public void testSurfaceGravity() { + // Equator + test(0, 0, 0, 9.780); + // Mid-latitude + test(45, 0, 0, 9.806); + // Mid-latitude + test(45, 99, 0, 9.806); + // South pole + test(-90, 0, 0, 9.832); + } + + @Test + public void testAltitudeEffect() { + test(45, 0, -100, 9.806); + test(45, 0, 0, 9.806); + test(45, 0, 10, 9.806); + test(45, 0, 100, 9.806); + test(45, 0, 1000, 9.803); + test(45, 0, 10000, 9.775); + test(45, 0, 100000, 9.505); + } + + private void test(double lat, double lon, double alt, double g) { + WorldCoordinate wc = new WorldCoordinate(lat, lon, alt); + assertEquals(g, model.getGravity(wc), 0.001); + assertEquals(g, model.getGravity(wc), 0.001); + } + +} diff --git a/test/net/sf/openrocket/util/GeodeticComputationStrategyTest.java b/test/net/sf/openrocket/util/GeodeticComputationStrategyTest.java index 72800d01..29efe41c 100644 --- a/test/net/sf/openrocket/util/GeodeticComputationStrategyTest.java +++ b/test/net/sf/openrocket/util/GeodeticComputationStrategyTest.java @@ -45,6 +45,7 @@ public class GeodeticComputationStrategyTest { // Test zero movement + System.out.println("\nTesting zero movement"); testAddCoordinate(50.0, 20.0, 0, 123, 50.0, 20.0, false); @@ -55,22 +56,27 @@ public class GeodeticComputationStrategyTest { // Long distance NE over England, crosses Greenwich meridian // 50 03N 005 42W to 58 38N 003 04E is 1109km at 027 16'07" + System.out.println("\nTesting 1109km NE over England"); testAddCoordinate(50 + 3 * min, -5 - 42 * min, 1109000, 27 + 16 * min + 7 * sec, 58 + 38 * min, 3 + 4 * min, false); // SW over Brazil // -10N -60E to -11N -61E is 155.9km at 224 25'34" + System.out.println("\nTesting 155km SW over Brazil"); testAddCoordinate(-10, -60, 155900, 224 + 25 * min + 34 * sec, -11, -61, true); // NW over the 180 meridian // 63N -179E to 63 01N 179E is 100.9km at 271 56'34" + System.out.println("\nTesting 100km NW over 180 meridian"); testAddCoordinate(63, -179, 100900, 271 + 56 * min + 34 * sec, 63 + 1 * min, 179, true); // NE near the north pole // 89 50N 0E to 89 45N 175E is 46.29 km at 003 00'01" + System.out.println("\nTesting 46km NE near north pole"); testAddCoordinate(89 + 50 * min, 0, 46290, 3 + 0 * min + 1 * sec, 89 + 45 * min, 175, false); // S directly over south pole // -89 50N 12E to -89 45N 192E is 46.33km at 180 00'00" + System.out.println("\nTesting 46km directly over south pole "); testAddCoordinate(-89 - 50 * min, 12, 46330, 180, -89 - 45 * min, -168, false); } @@ -103,20 +109,20 @@ public class GeodeticComputationStrategyTest { // Test WGS84 /* - * TODO: Since the example values are computed using a spherical earth approximation, - * the WGS84 method will have significantly larger errors. The tolerance should be - * increased correspondingly. + * Note: Since the example values are computed using a spherical earth approximation, + * the WGS84 method will have significantly larger errors. A tolerance of 1% accommodates + * all cases except the NE flight near the north pole, where the ellipsoidal effect is + * the greatest. */ - //tolerance = ... + tolerance = 0.04 * distance / 111325; System.out.println("\nWGS84 tolerance: " + tolerance); - result = GeodeticComputationStrategy.WGS84.addCoordinate(result, coord); + result = GeodeticComputationStrategy.WGS84.addCoordinate(wc, coord); System.out.println("Difference Lat: " + Math.abs(finalLatitude - result.getLatitudeDeg())); System.out.println("Difference Lon: " + Math.abs(finalLongitude - result.getLongitudeDeg())); - // FIXME: Re-enable these when they function - // assertEquals(finalLatitude, result.getLatitudeDeg(), tolerance); - // assertEquals(finalLongitude, result.getLongitudeDeg(), tolerance); - // assertEquals(1000.0, result.getAltitude(), 0.0); + assertEquals(finalLatitude, result.getLatitudeDeg(), tolerance); + assertEquals(finalLongitude, result.getLongitudeDeg(), tolerance); + assertEquals(1000.0, result.getAltitude(), 0.0); // Test FLAT diff --git a/web/html/actions/updates.php b/web/html/actions/updates.php index 874b0cab..6eb20b6c 100644 --- a/web/html/actions/updates.php +++ b/web/html/actions/updates.php @@ -80,21 +80,33 @@ header("Content-type: text/plain"); $version = $_GET["version"]; $updates = ""; -$unstable = "1.1.8"; +$unstable = "1.1.9"; $stable = "1.0.0"; -if (preg_match("/^1\.1\.7/", $version)) { +if (preg_match("/^1\.1\.8/", $version)) { $updates = "Version: " . $unstable . "\n" . + "6: Additional template printing\n" . + "5: Geodetic computations\n" . + "4: Bug fixes\n" . + ""; +} else if (preg_match("/^1\.1\.7/", $version)) { + $updates = "Version: " . $unstable . "\n" . + "6: Additional template printing\n" . + "5: Geodetic computations\n" . "4: Bug fixes\n" . ""; } else if (preg_match("/^1\.1\.6/", $version)) { $updates = "Version: " . $unstable . "\n" . "8: Automatic rocket design optimization\n" . + "6: Additional template printing\n" . + "5: Geodetic computations\n" . ""; } else if (preg_match("/^1\.1\.5/", $version)) { $updates = "Version: " . $unstable . "\n" . "8: Automatic rocket design optimization\n" . "6: Initial localization support\n" . + "6: Additional template printing\n" . + "5: Geodetic computations\n" . "5: Scaling support\n" . "4: Bug fixes\n" . ""; diff --git a/web/html/download.html b/web/html/download.html index 90eed2a9..86ca9fa1 100644 --- a/web/html/download.html +++ b/web/html/download.html @@ -48,6 +48,18 @@

Recent news:

+

24.11.2011: Version 1.1.9 is + released!

+

For this version Richard Graham has implemented geodetic + computation methods, which take into account the curvature of the + Earth and the coriolis effect. The computation method is selected + by the Geodetic calculations option in the simulation + options. It's not (yet) a full spherical computation model, but + should be accurate enough for almost all sub-orbital needs.

+

Doug Pedrick has also enhanced the printing system with the + ability to print fin positioning guides, transition templates and + nose cone profiles. Other smaller enhancements and bug fixes are + also included.

25.8.2011: Version 1.1.8 is released!

This release contains bug fixes to the optimization methods. @@ -66,16 +78,6 @@ easy to optimize against particulars of the simulation methods, instead of true physical phenomena. Always keep common sense at hand and take the results with a grain of salt.

-

22.7.2011: Version 1.1.6 is - released!

-

This release includes initial localization support and - translations to French, German and Spanish. This is thanks to the - great work of Boris du Reau, and the teams from Tripoli France, - Tripoli Spain and ERIG e.V. If you prefer to use some other - language than the system default, you can select the language on - the "Options" tab of the preferences dialog.

-

The release also includes design scaling support and numerous bug - fixes.

Ready packages

@@ -94,13 +96,13 @@ Support This Project

Stable release

@@ -117,7 +119,7 @@ Windows) by double-clicking the package icon. No installation is required.

From the command line OpenRocket can be started by - java -jar OpenRocket-1.1.8.jar

+ java -jar OpenRocket-1.1.9.jar

diff --git a/web/html/index.html b/web/html/index.html index ab701dd6..10a6cc20 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -49,12 +49,12 @@

Introduction

-

OpenRocket is an free, fully featured model +

OpenRocket is a free, fully featured model rocket simulator that allows you to design and simulate your rockets before actually building and flying them.

The main features include:

@@ -96,6 +96,18 @@

News

+

24.11.2011: Version 1.1.9 is + released!

+

For this version Richard Graham has implemented geodetic + computation methods, which take into account the curvature of the + Earth and the coriolis effect. The computation method is selected + by the Geodetic calculations option in the simulation + options. It's not (yet) a full spherical computation model, but + should be accurate enough for almost all sub-orbital needs.

+

Doug Pedrick has also enhanced the printing system with the + ability to print fin positioning guides, transition templates and + nose cone profiles. Other smaller enhancements and bug fixes are + also included.

25.8.2011: Version 1.1.8 is released!

This release contains bug fixes to the optimization methods. diff --git a/web/htp/htp.def b/web/htp/htp.def index cd4568d4..be65ee30 100644 --- a/web/htp/htp.def +++ b/web/htp/htp.def @@ -1,5 +1,5 @@ - + diff --git a/web/htp/news.htp b/web/htp/news.htp index 56db88da..ae125a8c 100644 --- a/web/htp/news.htp +++ b/web/htp/news.htp @@ -9,6 +9,21 @@ +

24.11.2011: Version 1.1.9 is + released!

+ +

For this version Richard Graham has implemented geodetic + computation methods, which take into account the curvature of the + Earth and the coriolis effect. The computation method is selected + by the Geodetic calculations option in the simulation + options. It's not (yet) a full spherical computation model, but + should be accurate enough for almost all sub-orbital needs.

+ +

Doug Pedrick has also enhanced the printing system with the + ability to print fin positioning guides, transition templates and + nose cone profiles. Other smaller enhancements and bug fixes are + also included.

+

25.8.2011: Version 1.1.8 is released!

@@ -33,6 +48,10 @@ instead of true physical phenomena. Always keep common sense at hand and take the results with a grain of salt.

+ + + +

22.7.2011: Version 1.1.6 is released!

@@ -46,10 +65,6 @@

The release also includes design scaling support and numerous bug fixes.

- - - -

10.6.2011: Version 1.1.5 is released!