version 1.1.9

This commit is contained in:
Sampo Niskanen 2011-11-24 19:19:39 +00:00
parent d82a370dd4
commit ab9bf0bce3
26 changed files with 529 additions and 473 deletions

View File

@ -1,6 +1,14 @@
2011-11-24 Sampo Niskanen
* Released version 1.1.9
2011-11-18 Doug Pedrick 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 2011-10-11 Sampo Niskanen

View File

@ -2,7 +2,7 @@
OpenRocket - an Open Source model rocket simulator 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. For license information see the file LICENSE.TXT.
@ -25,5 +25,8 @@ Contributions have been made by:
-------------------------------- --------------------------------
Sampo Niskanen, main developer 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

View File

@ -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): OpenRocket 1.1.8 (2011-08-25):
------------------------------- -------------------------------

View File

@ -1,7 +1,7 @@
# The OpenRocket build version # 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 # The source of the package. When building a package for a specific

View File

@ -30,7 +30,8 @@ public class AboutDialog extends JDialog {
"<font size=\"+1\"><b>OpenRocket has been developed by:</b></font><br><br>" + "<font size=\"+1\"><b>OpenRocket has been developed by:</b></font><br><br>" +
"Sampo Niskanen (main developer)<br>" + "Sampo Niskanen (main developer)<br>" +
"Doug Pedrick (RockSim file format, printing)<br>" + "Doug Pedrick (RockSim file format, printing)<br>" +
"Boris du Reau (internationalization, translation lead)<br><br>" + "Boris du Reau (internationalization, translation lead)<br>" +
"Richard Graham (geodetic computations)<br><br>" +
"<b>Translations by:</b><br><br>" + "<b>Translations by:</b><br><br>" +
"Tripoli France (French)<br>" + "Tripoli France (French)<br>" +
"Stefan Lobas / ERIG e.V. (German)<br>" + "Stefan Lobas / ERIG e.V. (German)<br>" +

View File

@ -88,8 +88,6 @@ public class SimulationEditDialog extends JDialog {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
// FIXME: NPE if FlightDataType has disappeared
public SimulationEditDialog(Window parent, Simulation s) { public SimulationEditDialog(Window parent, Simulation s) {
this(parent, s, 0); this(parent, s, 0);
} }

View File

@ -123,7 +123,7 @@ public class SimulationRunDialog extends JDialog {
//// Simulation time: //// Simulation time:
panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Simutime") + " "), "gapright para"); panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Simutime") + " "), "gapright para");
timeLabel = new JLabel(""); timeLabel = new JLabel("");
panel.add(timeLabel, "growx, wrap rel"); panel.add(timeLabel, "growx, wmin 200lp, wrap rel");
//// Altitude: //// Altitude:
panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Altitude") + " ")); panel.add(new JLabel(trans.get("SimuRunDlg.lbl.Altitude") + " "));

View File

@ -118,8 +118,6 @@ public class SimulationPlotPanel extends JPanel {
} }
} }
// FIXME: Bugs when expected branch is not present
configurationSelector.addItemListener(new ItemListener() { configurationSelector.addItemListener(new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
@ -189,7 +187,7 @@ public class SimulationPlotPanel extends JPanel {
typeSelectorPanel = new JPanel(new MigLayout("gapy rel")); typeSelectorPanel = new JPanel(new MigLayout("gapy rel"));
JScrollPane scroll = new JScrollPane(typeSelectorPanel); 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 //// Flight events
@ -379,10 +377,6 @@ public class SimulationPlotPanel extends JPanel {
private JComboBox axisSelector; private JComboBox axisSelector;
public PlotTypeSelector(int index, FlightDataType type) {
this(index, type, null, -1);
}
public PlotTypeSelector(int plotIndex, FlightDataType type, Unit unit, int position) { public PlotTypeSelector(int plotIndex, FlightDataType type, Unit unit, int position) {
super(new MigLayout("ins 0")); super(new MigLayout("ins 0"));

View File

@ -6,9 +6,6 @@ package net.sf.openrocket.gui.print;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.io.IOException; import java.io.IOException;
import java.text.DecimalFormat; 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.OpenRocketDocument;
import net.sf.openrocket.document.Simulation; import net.sf.openrocket.document.Simulation;
@ -152,7 +149,7 @@ public class DesignReport {
PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN); PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN);
Rocket rocket = rocketDocument.getRocket(); Rocket rocket = rocketDocument.getRocket();
final Configuration configuration = rocket.getDefaultConfiguration(); final Configuration configuration = rocket.getDefaultConfiguration().clone();
configuration.setAllStages(); configuration.setAllStages();
PdfContentByte canvas = writer.getDirectContent(); PdfContentByte canvas = writer.getDirectContent();
@ -219,8 +216,6 @@ public class DesignReport {
String[] motorIds = rocket.getMotorConfigurationIDs(); String[] motorIds = rocket.getMotorConfigurationIDs();
List<Double> stageMasses = getStageMasses(rocket);
for (int j = 0; j < motorIds.length; j++) { for (int j = 0; j < motorIds.length; j++) {
String motorId = motorIds[j]; String motorId = motorIds[j];
if (motorId != null) { 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<Motor> getMotorList(final Rocket theRocket, final String theMid) {
Iterator<RocketComponent> components = theRocket.iterator();
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;
}
/** /**
* Paint a diagram of the rocket into the PDF document. * Paint a diagram of the rocket into the PDF document.
@ -545,27 +517,4 @@ public class DesignReport {
return target.replace("]", ""); 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<Double> getStageMasses(final Rocket rocket) {
List<Double> masses = new ArrayList<Double>();
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;
}
} }

View File

@ -12,22 +12,23 @@ import net.sf.openrocket.rocketcomponent.Configuration;
*/ */
public class PrintFigure extends RocketFigure { public class PrintFigure extends RocketFigure {
/** /**
* Constructor. * Constructor.
* *
* @param configuration the configuration * @param configuration the configuration
*/ */
public PrintFigure (final Configuration configuration) { public PrintFigure(final Configuration configuration) {
super(configuration); super(configuration);
} }
protected double computeTy (int heightPx) { @Override
super.computeTy(heightPx); protected double computeTy(int heightPx) {
return 0; super.computeTy(heightPx);
} return 0;
}
public void setScale (final double theScale) { public void setScale(final double theScale) {
this.scale = theScale; //dpi/0.0254*scaling; this.scale = theScale; //dpi/0.0254*scaling;
updateFigure(); updateFigure();
} }
} }

View File

@ -4,113 +4,118 @@
*/ */
package net.sf.openrocket.gui.print; 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. * Instances of this class are meant to keep track of what the user has selected to be printed.
*/ */
public class PrintableContext implements Comparable<PrintableContext>, Iterable<PrintableContext> { public class PrintableContext implements Comparable<PrintableContext>, Iterable<PrintableContext> {
/** /**
* The stage number. May be null for printables that have no stage meaning. * The stage number. May be null for printables that have no stage meaning.
*/ */
private Set<Integer> stageNumber; private Set<Integer> stageNumber;
/** /**
* The type of thing to be printed. * The type of thing to be printed.
*/ */
private OpenRocketPrintable printable; 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. * 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>>(); private final Map<OpenRocketPrintable, Set<Integer>> previous = new TreeMap<OpenRocketPrintable, Set<Integer>>();
/** /**
* Constructor. * Constructor.
*/ */
public PrintableContext () { public PrintableContext() {
} }
/** /**
* Constructor. * Constructor.
* *
* @param theStageNumber the stage number of the printable; may be null if not applicable * @param theStageNumber the stage number of the printable; may be null if not applicable
* @param thePrintable the type of the thing to be printed * @param thePrintable the type of the thing to be printed
* *
* @throws IllegalArgumentException thrown if thePrintable.isStageSpecific * @throws IllegalArgumentException thrown if thePrintable.isStageSpecific
*/ */
private PrintableContext (final Set<Integer> theStageNumber, final OpenRocketPrintable thePrintable) private PrintableContext(final Set<Integer> theStageNumber, final OpenRocketPrintable thePrintable)
throws IllegalArgumentException { throws IllegalArgumentException {
if (thePrintable.isStageSpecific() && theStageNumber == null) { if (thePrintable.isStageSpecific() && theStageNumber == null) {
throw new IllegalArgumentException("A stage number must be provided when a printable is stage specific."); throw new IllegalArgumentException("A stage number must be provided when a printable is stage specific.");
} }
stageNumber = theStageNumber; stageNumber = theStageNumber;
printable = thePrintable; printable = thePrintable;
} }
/** /**
* Add a type of printable to a stage (number). * Add a type of printable to a stage (number).
* *
* @param theStageNumber the stage number * @param theStageNumber the stage number
* @param thePrintable the printable to associate with the stage * @param thePrintable the printable to associate with the stage
*/ */
public void add (final Integer theStageNumber, final OpenRocketPrintable thePrintable) { public void add(final Integer theStageNumber, final OpenRocketPrintable thePrintable) {
Set<Integer> stages = previous.get(thePrintable); Set<Integer> stages = previous.get(thePrintable);
if (stages == null) { if (stages == null) {
stages = new TreeSet<Integer>(); stages = new TreeSet<Integer>();
previous.put(thePrintable, stages); previous.put(thePrintable, stages);
} }
if (theStageNumber != null) { if (theStageNumber != null) {
stages.add(theStageNumber); stages.add(theStageNumber);
} }
} }
/** PrintableContext iterator. */ /** PrintableContext iterator. */
public Iterator<PrintableContext> iterator () { @Override
return new Iterator<PrintableContext>() { public Iterator<PrintableContext> iterator() {
return new Iterator<PrintableContext>() {
Iterator<OpenRocketPrintable> keyIter = previous.keySet().iterator(); Iterator<OpenRocketPrintable> keyIter = previous.keySet().iterator();
@Override @Override
public boolean hasNext () { public boolean hasNext() {
return keyIter.hasNext(); return keyIter.hasNext();
} }
@Override @Override
public PrintableContext next () { public PrintableContext next() {
final OpenRocketPrintable key = keyIter.next(); final OpenRocketPrintable key = keyIter.next();
return new PrintableContext(previous.get(key), key); return new PrintableContext(previous.get(key), key);
} }
@Override @Override
public void remove () { public void remove() {
} }
}; };
} }
/** /**
* Get the stage number, if it's applicable to the printable. * Get the stage number, if it's applicable to the printable.
* *
* @return the stage number * @return the stage number
*/ */
public Set<Integer> getStageNumber () { public Set<Integer> getStageNumber() {
return stageNumber; return stageNumber;
} }
/** /**
* Get the printable. * Get the printable.
* *
* @return the printable * @return the printable
*/ */
public OpenRocketPrintable getPrintable () { public OpenRocketPrintable getPrintable() {
return printable; return printable;
} }
@Override @Override
public int compareTo (final PrintableContext other) { public int compareTo(final PrintableContext other) {
return this.printable.getPrintOrder() - other.printable.getPrintOrder(); return this.printable.getPrintOrder() - other.printable.getPrintOrder();
} }
} }

View File

@ -1,56 +1,59 @@
package net.sf.openrocket.gui.print; 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.gui.rocketfigure.TransitionShapes;
import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.util.Transformation; import net.sf.openrocket.util.Transformation;
import java.awt.*;
public class PrintableNoseCone extends AbstractPrintableTransition { public class PrintableNoseCone extends AbstractPrintableTransition {
/** /**
* If the component to be drawn is a nose cone, save a reference to it. * If the component to be drawn is a nose cone, save a reference to it.
*/ */
private NoseCone target; private NoseCone target;
/** /**
* Construct a printable nose cone. * Construct a printable nose cone.
* *
* @param noseCone the component to print * @param noseCone the component to print
*/ */
public PrintableNoseCone(Transition noseCone) { public PrintableNoseCone(Transition noseCone) {
super(false, noseCone); super(false, noseCone);
} }
@Override @Override
protected void init(Transition component) { protected void init(Transition component) {
target = (NoseCone) component; target = (NoseCone) component;
double radius = target.getForeRadius(); double radius = target.getForeRadius();
if (radius < target.getAftRadius()) { if (radius < target.getAftRadius()) {
radius = target.getAftRadius(); radius = target.getAftRadius();
} }
setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX, setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
(int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY); (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY);
} }
/** /**
* Draw a nose cone. * Draw a nose cone.
* *
* @param g2 the graphics context * @param g2 the graphics context
*/ */
protected void draw(Graphics2D g2) { @Override
Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1)); protected void draw(Graphics2D g2) {
Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1));
if (shapes != null && shapes.length > 0) { if (shapes != null && shapes.length > 0) {
Rectangle r = shapes[0].getBounds(); Rectangle r = shapes[0].getBounds();
g2.translate(marginX + r.getHeight() / 2, marginY); g2.translate(marginX + r.getHeight() / 2, marginY);
g2.rotate(Math.PI / 2); g2.rotate(Math.PI / 2);
for (Shape shape : shapes) { for (Shape shape : shapes) {
g2.draw(shape); g2.draw(shape);
} }
g2.rotate(-Math.PI / 2); g2.rotate(-Math.PI / 2);
} }
} }
} }

View File

@ -1,14 +1,15 @@
package net.sf.openrocket.gui.print; package net.sf.openrocket.gui.print;
import net.sf.openrocket.rocketcomponent.Transition; import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Arc2D; import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath; import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Point2D; 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 * 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 * modified) and rendering it within a JPanel. The JPanel is not actually visualized on a display, but instead renders
@ -19,187 +20,188 @@ import java.awt.geom.Point2D;
*/ */
public class PrintableTransition extends AbstractPrintableTransition { public class PrintableTransition extends AbstractPrintableTransition {
/** /**
* Dashed array value. * Dashed array value.
*/ */
private final static float dash1[] = {4.0f}; private final static float dash1[] = { 4.0f };
/** /**
* The dashed stroke for glue tab. * The dashed stroke for glue tab.
*/ */
private final static BasicStroke dashed = new BasicStroke(1.0f, private final static BasicStroke dashed = new BasicStroke(1.0f,
BasicStroke.CAP_BUTT, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, BasicStroke.JOIN_MITER,
10.0f, dash1, 0.0f); 10.0f, dash1, 0.0f);
/** /**
* The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs. * 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. * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system.
*/ */
private Path2D gp; private Path2D gp;
/** /**
* The glue tab. * The glue tab.
*/ */
private Path2D glueTab1; private Path2D glueTab1;
/** /**
* The alignment marks. * The alignment marks.
*/ */
private Line2D tick1, tick2; private Line2D tick1, tick2;
/** /**
* The x coordinates for the two ticks drawn at theta degrees. * The x coordinates for the two ticks drawn at theta degrees.
*/ */
private int tick3X, tick4X; private int tick3X, tick4X;
/** /**
* The angle, in degrees. * The angle, in degrees.
*/ */
private float theta; private float theta;
/** /**
* The x,y coordinates for where the virtual circle center is located. * The x,y coordinates for where the virtual circle center is located.
*/ */
private int circleCenterX, circleCenterY; private int circleCenterX, circleCenterY;
/** /**
* Constructor. * Constructor.
* *
* @param transition the transition to print * @param transition the transition to print
*/ */
public PrintableTransition(Transition transition) { public PrintableTransition(Transition transition) {
super(false, transition); super(false, transition);
} }
@Override @Override
protected void init(Transition component) { protected void init(Transition component) {
double r1 = component.getAftRadius(); double r1 = component.getAftRadius();
double r2 = component.getForeRadius(); double r2 = component.getForeRadius();
//Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different. //Regardless of orientation, we have the convention of R1 as the smaller radius. Flip if different.
if (r1 > r2) { if (r1 > r2) {
r1 = r2; r1 = r2;
r2 = component.getAftRadius(); r2 = component.getAftRadius();
} }
double len = component.getLength(); double len = component.getLength();
double v = r2 - r1; double v = r2 - r1;
double tmp = Math.sqrt(v * v + len * len); double tmp = Math.sqrt(v * v + len * len);
double factor = tmp / v; double factor = tmp / v;
theta = (float) (360d * v / tmp); theta = (float) (360d * v / tmp);
int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor); int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor); int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
int x = marginX; int x = marginX;
int tabOffset = 35; int tabOffset = 35;
int y = tabOffset + marginY; int y = tabOffset + marginY;
Arc2D.Double outerArc = new Arc2D.Double(); Arc2D.Double outerArc = new Arc2D.Double();
Arc2D.Double innerArc = 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 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) { if (theta >= 270) {
y += r2InPoints; 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 //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. //of the bigger arc.
else if (theta >= 180) { else if (theta >= 180) {
double thetaRads = Math.toRadians(theta - 180); double thetaRads = Math.toRadians(theta - 180);
y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads)); y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads));
} }
circleCenterY = y; circleCenterY = y;
circleCenterX = r2InPoints + x; circleCenterX = r2InPoints + x;
//Create the larger arc. //Create the larger arc.
outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN); outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
//Create the smaller arc. //Create the smaller arc.
innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN); 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. //Create the line between the start of the larger arc and the start of the smaller arc.
Path2D.Double line = new Path2D.Double(); Path2D.Double line = new Path2D.Double();
line.setWindingRule(Path2D.WIND_NON_ZERO); line.setWindingRule(Path2D.WIND_NON_ZERO);
line.moveTo(x, y); line.moveTo(x, y);
final int width = r2InPoints - r1InPoints; final int width = r2InPoints - r1InPoints;
line.lineTo(width + x, y); line.lineTo(width + x, y);
//Create the line between the endpoint of the larger arc and the endpoint of the smaller arc. //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc.
Path2D.Double closingLine = new Path2D.Double(); Path2D.Double closingLine = new Path2D.Double();
closingLine.setWindingRule(Path2D.WIND_NON_ZERO); closingLine.setWindingRule(Path2D.WIND_NON_ZERO);
Point2D innerArcEndPoint = innerArc.getEndPoint(); Point2D innerArcEndPoint = innerArc.getEndPoint();
closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY()); closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY());
Point2D outerArcEndPoint = outerArc.getEndPoint(); Point2D outerArcEndPoint = outerArc.getEndPoint();
closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY()); closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY());
//Add all shapes to the polygon path. //Add all shapes to the polygon path.
gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
gp.append(line, false); gp.append(line, false);
gp.append(outerArc, false); gp.append(outerArc, false);
gp.append(closingLine, false); gp.append(closingLine, false);
gp.append(innerArc, false); gp.append(innerArc, false);
//Create the glue tab. //Create the glue tab.
glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4); glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
glueTab1.moveTo(x, y); glueTab1.moveTo(x, y);
glueTab1.lineTo(x + tabOffset, y - tabOffset); glueTab1.lineTo(x + tabOffset, y - tabOffset);
glueTab1.lineTo(width + x - tabOffset, y - tabOffset); glueTab1.lineTo(width + x - tabOffset, y - tabOffset);
glueTab1.lineTo(width + x, y); glueTab1.lineTo(width + x, y);
//Create tick marks for alignment, 1/4 of the width in from either edge //Create tick marks for alignment, 1/4 of the width in from either edge
int fromEdge = width / 4; int fromEdge = width / 4;
final int tickLength = 8; final int tickLength = 8;
//Upper left //Upper left
tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength); tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength);
//Upper right //Upper right
tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength); tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength);
tick3X = r2InPoints - fromEdge; tick3X = r2InPoints - fromEdge;
tick4X = r1InPoints + fromEdge; tick4X = r1InPoints + fromEdge;
setSize(gp.getBounds().width, gp.getBounds().height + tabOffset); setSize(gp.getBounds().width, gp.getBounds().height + tabOffset);
} }
/** /**
* Draw alignment marks on an angle. * Draw alignment marks on an angle.
* *
* @param g2 the graphics context * @param g2 the graphics context
* @param x the center of the circle's x coordinate * @param x the center of the circle's x coordinate
* @param y the center of the circle's y * @param y the center of the circle's y
* @param line the line to draw * @param line the line to draw
* @param theta the angle * @param theta the angle
*/ */
private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) { private void drawAlignmentMarks(Graphics2D g2, int x, int y, Line2D.Float line, float theta) {
g2.translate(x, y); g2.translate(x, y);
g2.rotate(Math.toRadians(-theta)); g2.rotate(Math.toRadians(-theta));
g2.draw(line); g2.draw(line);
g2.rotate(Math.toRadians(theta)); g2.rotate(Math.toRadians(theta));
g2.translate(-x, -y); g2.translate(-x, -y);
} }
/** /**
* Draw a transition. * Draw a transition.
* *
* @param g2 the graphics context * @param g2 the graphics context
*/ */
protected void draw(Graphics2D g2) { @Override
//Render it. protected void draw(Graphics2D g2) {
g2.draw(gp); //Render it.
g2.draw(tick1); g2.draw(gp);
g2.draw(tick2); g2.draw(tick1);
drawAlignmentMarks(g2, circleCenterX, g2.draw(tick2);
circleCenterY, drawAlignmentMarks(g2, circleCenterX,
new Line2D.Float(-tick3X, 0, -tick3X, -8), circleCenterY,
theta); new Line2D.Float(-tick3X, 0, -tick3X, -8),
drawAlignmentMarks(g2, circleCenterX, theta);
circleCenterY, drawAlignmentMarks(g2, circleCenterX,
new Line2D.Float(-tick4X, 0, -tick4X, -8), circleCenterY,
theta); new Line2D.Float(-tick4X, 0, -tick4X, -8),
theta);
g2.setStroke(dashed); g2.setStroke(dashed);
g2.draw(glueTab1); g2.draw(glueTab1);
} }
} }

View File

@ -109,7 +109,6 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
private SimulationWorker backgroundSimulationWorker = null; private SimulationWorker backgroundSimulationWorker = null;
private boolean dirty = false;
private List<ChangeListener> listeners = new ArrayList<ChangeListener>(); private List<ChangeListener> listeners = new ArrayList<ChangeListener>();

View File

@ -1,18 +1,18 @@
package net.sf.openrocket.models.gravity; package net.sf.openrocket.models.gravity;
//import net.sf.openrocket.util.Monitorable;
import net.sf.openrocket.util.Monitorable; import net.sf.openrocket.util.Monitorable;
import net.sf.openrocket.util.WorldCoordinate; import net.sf.openrocket.util.WorldCoordinate;
/** /**
* An interface to modelling gravitational acceleration. * An interface for modeling gravitational acceleration.
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public interface GravityModel extends Monitorable { 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 * @param wc the world coordinate location
* @return gravitational acceleration in m/s/s * @return gravitational acceleration in m/s/s
*/ */

View File

@ -4,7 +4,7 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.WorldCoordinate; 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 <richard@rdg.cc> * @author Richard Graham <richard@rdg.cc>
*/ */
@ -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 // 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 // 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. // 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; return g_alt;
} }

View File

@ -93,8 +93,6 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
} }
// Compute conditions // Compute conditions
//double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude();
//gravity = status.getSimulationConditions().getGravityModel().getGravity(altitude);
gravity = status.getSimulationConditions().getGravityModel().getGravity(status.getRocketWorldPosition()); gravity = status.getSimulationConditions().getGravityModel().getGravity(status.getRocketWorldPosition());
// Call post-listener // Call post-listener

View File

@ -54,7 +54,7 @@ public enum GeodeticComputationStrategy {
double newAlt = location.getAltitude() + delta.z; double newAlt = location.getAltitude() + delta.z;
// bearing (in radians, clockwise from north); // bearing (in radians, clockwise from north);
// d/R is the angular distance (in radians), where d is the distance traveled and R is the earths 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); double d = MathUtil.hypot(delta.x, delta.y);
// Check for zero movement before computing bearing // Check for zero movement before computing bearing
@ -99,7 +99,7 @@ public enum GeodeticComputationStrategy {
double newAlt = location.getAltitude() + delta.z; double newAlt = location.getAltitude() + delta.z;
// bearing (in radians, clockwise from north); // bearing (in radians, clockwise from north);
// d/R is the angular distance (in radians), where d is the distance traveled and R is the earths 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); double d = MathUtil.hypot(delta.x, delta.y);
// Check for zero movement before computing bearing // Check for zero movement before computing bearing

View File

@ -25,10 +25,6 @@ public enum LineStyle {
DASHDOT("LineStyle.Dash-dotted", new float[] { 8f, 3f, 2f, 3f }); DASHDOT("LineStyle.Dash-dotted", new float[] { 8f, 3f, 2f, 3f });
private static final Translator trans = Application.getTranslator(); 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 String name;
private final float[] dashes; private final float[] dashes;

View File

@ -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);
}
}

View File

@ -45,6 +45,7 @@ public class GeodeticComputationStrategyTest {
// Test zero movement // Test zero movement
System.out.println("\nTesting zero movement");
testAddCoordinate(50.0, 20.0, 0, 123, 50.0, 20.0, false); 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 // Long distance NE over England, crosses Greenwich meridian
// 50 03N 005 42W to 58 38N 003 04E is 1109km at 027 16'07" // 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); testAddCoordinate(50 + 3 * min, -5 - 42 * min, 1109000, 27 + 16 * min + 7 * sec, 58 + 38 * min, 3 + 4 * min, false);
// SW over Brazil // SW over Brazil
// -10N -60E to -11N -61E is 155.9km at 224 25'34" // -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); testAddCoordinate(-10, -60, 155900, 224 + 25 * min + 34 * sec, -11, -61, true);
// NW over the 180 meridian // NW over the 180 meridian
// 63N -179E to 63 01N 179E is 100.9km at 271 56'34" // 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); testAddCoordinate(63, -179, 100900, 271 + 56 * min + 34 * sec, 63 + 1 * min, 179, true);
// NE near the north pole // NE near the north pole
// 89 50N 0E to 89 45N 175E is 46.29 km at 003 00'01" // 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); testAddCoordinate(89 + 50 * min, 0, 46290, 3 + 0 * min + 1 * sec, 89 + 45 * min, 175, false);
// S directly over south pole // S directly over south pole
// -89 50N 12E to -89 45N 192E is 46.33km at 180 00'00" // -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); testAddCoordinate(-89 - 50 * min, 12, 46330, 180, -89 - 45 * min, -168, false);
} }
@ -103,20 +109,20 @@ public class GeodeticComputationStrategyTest {
// Test WGS84 // Test WGS84
/* /*
* TODO: Since the example values are computed using a spherical earth approximation, * Note: Since the example values are computed using a spherical earth approximation,
* the WGS84 method will have significantly larger errors. The tolerance should be * the WGS84 method will have significantly larger errors. A tolerance of 1% accommodates
* increased correspondingly. * 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); 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 Lat: " + Math.abs(finalLatitude - result.getLatitudeDeg()));
System.out.println("Difference Lon: " + Math.abs(finalLongitude - result.getLongitudeDeg())); System.out.println("Difference Lon: " + Math.abs(finalLongitude - result.getLongitudeDeg()));
// FIXME: Re-enable these when they function assertEquals(finalLatitude, result.getLatitudeDeg(), tolerance);
// assertEquals(finalLatitude, result.getLatitudeDeg(), tolerance); assertEquals(finalLongitude, result.getLongitudeDeg(), tolerance);
// assertEquals(finalLongitude, result.getLongitudeDeg(), tolerance); assertEquals(1000.0, result.getAltitude(), 0.0);
// assertEquals(1000.0, result.getAltitude(), 0.0);
// Test FLAT // Test FLAT

View File

@ -80,21 +80,33 @@ header("Content-type: text/plain");
$version = $_GET["version"]; $version = $_GET["version"];
$updates = ""; $updates = "";
$unstable = "1.1.8"; $unstable = "1.1.9";
$stable = "1.0.0"; $stable = "1.0.0";
if (preg_match("/^1\.1\.7/", $version)) { if (preg_match("/^1\.1\.8/", $version)) {
$updates = "Version: " . $unstable . "\n" . $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" . "4: Bug fixes\n" .
""; "";
} else if (preg_match("/^1\.1\.6/", $version)) { } else if (preg_match("/^1\.1\.6/", $version)) {
$updates = "Version: " . $unstable . "\n" . $updates = "Version: " . $unstable . "\n" .
"8: Automatic rocket design optimization\n" . "8: Automatic rocket design optimization\n" .
"6: Additional template printing\n" .
"5: Geodetic computations\n" .
""; "";
} else if (preg_match("/^1\.1\.5/", $version)) { } else if (preg_match("/^1\.1\.5/", $version)) {
$updates = "Version: " . $unstable . "\n" . $updates = "Version: " . $unstable . "\n" .
"8: Automatic rocket design optimization\n" . "8: Automatic rocket design optimization\n" .
"6: Initial localization support\n" . "6: Initial localization support\n" .
"6: Additional template printing\n" .
"5: Geodetic computations\n" .
"5: Scaling support\n" . "5: Scaling support\n" .
"4: Bug fixes\n" . "4: Bug fixes\n" .
""; "";

View File

@ -48,6 +48,18 @@
<div class="content"> <div class="content">
<div class="news"> <div class="news">
<h2>Recent news:</h2> <h2>Recent news:</h2>
<p><span class="date">24.11.2011:</span> Version 1.1.9 is
<a href="download.html">released</a>!</p>
<p>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 <em>Geodetic calculations</em> option in the simulation
options. It's not <em>(yet)</em> a full spherical computation model, but
should be accurate enough for almost all sub-orbital needs.</p>
<p>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.</p>
<p><span class="date">25.8.2011:</span> Version 1.1.8 is <p><span class="date">25.8.2011:</span> Version 1.1.8 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
<p>This release contains bug fixes to the optimization methods. <p>This release contains bug fixes to the optimization methods.
@ -66,16 +78,6 @@
easy to optimize against particulars of the simulation methods, easy to optimize against particulars of the simulation methods,
instead of true physical phenomena. Always keep common sense at instead of true physical phenomena. Always keep common sense at
hand and take the results with a grain of salt.</p> hand and take the results with a grain of salt.</p>
<p><span class="date">22.7.2011:</span> Version 1.1.6 is
<a href="download.html">released</a>!</p>
<p>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.</p>
<p>The release also includes design scaling support and numerous bug
fixes.</p>
</div> </div>
<div class="contentholder"> <div class="contentholder">
<h2>Ready packages</h2> <h2>Ready packages</h2>
@ -94,13 +96,13 @@
<a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a> <a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a>
</div> </div>
<div class="downloadbox"> <div class="downloadbox">
<a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.8/OpenRocket-1.1.8.jar/download"> <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.9/OpenRocket-1.1.9.jar/download">
<strong>Download now!</strong> <strong>Download now!</strong>
<span>OpenRocket-1.1.8.jar</span> <span>OpenRocket-1.1.9.jar</span>
</a> </a>
<span class="alternative"> <span class="alternative">
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.8/ReleaseNotes/view">Release notes</a> | <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.9/ReleaseNotes/view">Release notes</a> |
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.8/OpenRocket-1.1.8-src.zip/download">Source code</a> <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.9/OpenRocket-1.1.9-src.zip/download">Source code</a>
</span> </span>
</div> </div>
<h3>Stable release</h3> <h3>Stable release</h3>
@ -117,7 +119,7 @@
Windows) by double-clicking the package icon. No installation is Windows) by double-clicking the package icon. No installation is
required.</p> required.</p>
<p>From the command line OpenRocket can be started by <p>From the command line OpenRocket can be started by
<span class="command">java -jar OpenRocket-1.1.8.jar</span></p> <span class="command">java -jar OpenRocket-1.1.9.jar</span></p>
</div> </div>
<div class="clear"></div> <div class="clear"></div>

View File

@ -49,12 +49,12 @@
<h2>Introduction</h2> <h2>Introduction</h2>
<div class="rightpane"> <div class="rightpane">
<div class="downloadbox"> <div class="downloadbox">
<a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.8/OpenRocket-1.1.8.jar/download"> <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.9/OpenRocket-1.1.9.jar/download">
<strong>Download now!</strong> <strong>Download now!</strong>
<span>OpenRocket-1.1.8.jar</span> <span>OpenRocket-1.1.9.jar</span>
</a> </a>
<span class="alternative"> <span class="alternative">
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.8/ReleaseNotes/view">Release notes</a> | <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.9/ReleaseNotes/view">Release notes</a> |
<a href="download.html">Other versions</a> <a href="download.html">Other versions</a>
</span> </span>
</div> </div>
@ -68,7 +68,7 @@
<a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /> </a> <a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /> </a>
</div> </div>
</div> </div>
<p><strong>OpenRocket</strong> is an free, fully featured model <p><strong>OpenRocket</strong> is a free, fully featured model
rocket simulator that allows you to design and simulate your rocket simulator that allows you to design and simulate your
rockets before actually building and flying them.</p> rockets before actually building and flying them.</p>
<p>The main features include:</p> <p>The main features include:</p>
@ -96,6 +96,18 @@
<div class="clear"></div> <div class="clear"></div>
<div class="news"> <div class="news">
<h2>News</h2> <h2>News</h2>
<p><span class="date">24.11.2011:</span> Version 1.1.9 is
<a href="download.html">released</a>!</p>
<p>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 <em>Geodetic calculations</em> option in the simulation
options. It's not <em>(yet)</em> a full spherical computation model, but
should be accurate enough for almost all sub-orbital needs.</p>
<p>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.</p>
<p><span class="date">25.8.2011:</span> Version 1.1.8 is <p><span class="date">25.8.2011:</span> Version 1.1.8 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
<p>This release contains bug fixes to the optimization methods. <p>This release contains bug fixes to the optimization methods.

View File

@ -1,5 +1,5 @@
<set stableversion="1.0.0"> <set stableversion="1.0.0">
<set developmentversion="1.1.8"> <set developmentversion="1.1.9">
<set version="${developmentversion}"> <set version="${developmentversion}">
<def name="downloadbox"> <def name="downloadbox">

View File

@ -9,6 +9,21 @@
<!--- Remember to move the position of "onlyrecent" below! ---> <!--- Remember to move the position of "onlyrecent" below! --->
<p><span class="date">24.11.2011:</span> Version 1.1.9 is
<a href="download.html">released</a>!</p>
<p>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 <em>Geodetic calculations</em> option in the simulation
options. It's not <em>(yet)</em> a full spherical computation model, but
should be accurate enough for almost all sub-orbital needs.</p>
<p>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.</p>
<p><span class="date">25.8.2011:</span> Version 1.1.8 is <p><span class="date">25.8.2011:</span> Version 1.1.8 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
@ -33,6 +48,10 @@
instead of true physical phenomena. Always keep common sense at instead of true physical phenomena. Always keep common sense at
hand and take the results with a grain of salt.</p> hand and take the results with a grain of salt.</p>
<if not onlyrecent><!--- Older items not shown on download page: --->
<p><span class="date">22.7.2011:</span> Version 1.1.6 is <p><span class="date">22.7.2011:</span> Version 1.1.6 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
@ -46,10 +65,6 @@
<p>The release also includes design scaling support and numerous bug <p>The release also includes design scaling support and numerous bug
fixes.</p> fixes.</p>
<if not onlyrecent><!--- Older items not shown on download page: --->
<p><span class="date">10.6.2011:</span> Version 1.1.5 is <p><span class="date">10.6.2011:</span> Version 1.1.5 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>