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
* 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

View File

@ -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

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):
-------------------------------

View File

@ -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

View File

@ -30,7 +30,8 @@ public class AboutDialog extends JDialog {
"<font size=\"+1\"><b>OpenRocket has been developed by:</b></font><br><br>" +
"Sampo Niskanen (main developer)<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>" +
"Tripoli France (French)<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();
// FIXME: NPE if FlightDataType has disappeared
public SimulationEditDialog(Window parent, Simulation s) {
this(parent, s, 0);
}

View File

@ -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") + " "));

View File

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

View File

@ -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<Double> 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<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.
@ -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<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 {
/**
* Constructor.
*
* @param configuration the configuration
*/
public PrintFigure (final Configuration configuration) {
super(configuration);
}
/**
* Constructor.
*
* @param configuration the configuration
*/
public PrintFigure(final Configuration configuration) {
super(configuration);
}
protected double computeTy (int heightPx) {
super.computeTy(heightPx);
return 0;
}
@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();
}
public void setScale(final double theScale) {
this.scale = theScale; //dpi/0.0254*scaling;
updateFigure();
}
}

View File

@ -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<PrintableContext>, Iterable<PrintableContext> {
/**
* The stage number. May be null for printables that have no stage meaning.
*/
private Set<Integer> stageNumber;
/**
* The stage number. May be null for printables that have no stage meaning.
*/
private Set<Integer> stageNumber;
/**
* The type of thing to be printed.
*/
private OpenRocketPrintable printable;
/**
* 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<OpenRocketPrintable, Set<Integer>> previous = new TreeMap<OpenRocketPrintable, Set<Integer>>();
/**
* Sort of a reverse map that tracks each type of printable item and the stages for which that item is to be printed.
*/
private final Map<OpenRocketPrintable, Set<Integer>> previous = new TreeMap<OpenRocketPrintable, Set<Integer>>();
/**
* Constructor.
*/
public PrintableContext () {
}
/**
* 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<Integer> 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;
}
/**
* 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<Integer> 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<Integer> stages = previous.get(thePrintable);
if (stages == null) {
stages = new TreeSet<Integer>();
previous.put(thePrintable, stages);
}
if (theStageNumber != null) {
stages.add(theStageNumber);
}
}
/**
* Add a type of printable to a stage (number).
*
* @param theStageNumber the stage number
* @param thePrintable the printable to associate with the stage
*/
public void add(final Integer theStageNumber, final OpenRocketPrintable thePrintable) {
Set<Integer> stages = previous.get(thePrintable);
if (stages == null) {
stages = new TreeSet<Integer>();
previous.put(thePrintable, stages);
}
if (theStageNumber != null) {
stages.add(theStageNumber);
}
}
/** PrintableContext iterator. */
public Iterator<PrintableContext> iterator () {
return new Iterator<PrintableContext>() {
/** PrintableContext iterator. */
@Override
public Iterator<PrintableContext> iterator() {
return new Iterator<PrintableContext>() {
Iterator<OpenRocketPrintable> keyIter = previous.keySet().iterator();
Iterator<OpenRocketPrintable> keyIter = previous.keySet().iterator();
@Override
public boolean hasNext () {
return keyIter.hasNext();
}
@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 PrintableContext next() {
final OpenRocketPrintable key = keyIter.next();
return new PrintableContext(previous.get(key), key);
}
@Override
public void remove () {
}
};
@Override
public void remove() {
}
};
}
}
/**
* Get the stage number, if it's applicable to the printable.
*
* @return the stage number
*/
public Set<Integer> getStageNumber () {
return stageNumber;
}
/**
* Get the stage number, if it's applicable to the printable.
*
* @return the stage number
*/
public Set<Integer> getStageNumber() {
return stageNumber;
}
/**
* Get the printable.
*
* @return the printable
*/
public OpenRocketPrintable getPrintable () {
return printable;
}
/**
* 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();
}
@Override
public int compareTo(final PrintableContext other) {
return this.printable.getPrintOrder() - other.printable.getPrintOrder();
}
}

View File

@ -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;
/**
* 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);
}
/**
* Construct a printable nose cone.
*
* @param noseCone the component to print
*/
public PrintableNoseCone(Transition noseCone) {
super(false, noseCone);
}
@Override
protected void init(Transition component) {
@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);
}
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));
/**
* 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);
}
}
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);
}
}
}

View File

@ -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
@ -19,187 +20,188 @@ import java.awt.geom.Point2D;
*/
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);
/**
* 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 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 glue tab.
*/
private Path2D glueTab1;
/**
* The alignment marks.
*/
private Line2D tick1, tick2;
/**
* The alignment marks.
*/
private Line2D tick1, tick2;
/**
* The x coordinates for the two ticks drawn at theta degrees.
*/
private int tick3X, tick4X;
/**
* The x coordinates for the two ticks drawn at theta degrees.
*/
private int tick3X, tick4X;
/**
* The angle, in degrees.
*/
private float theta;
/**
* The angle, in degrees.
*/
private float theta;
/**
* The x,y coordinates for where the virtual circle center is located.
*/
private int circleCenterX, circleCenterY;
/**
* 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);
}
/**
* Constructor.
*
* @param transition the transition to print
*/
public PrintableTransition(Transition transition) {
super(false, transition);
}
@Override
protected void init(Transition component) {
@Override
protected void init(Transition component) {
double r1 = component.getAftRadius();
double r2 = component.getForeRadius();
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;
//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);
theta = (float) (360d * v / tmp);
int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
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;
int x = marginX;
int tabOffset = 35;
int y = tabOffset + marginY;
Arc2D.Double outerArc = new Arc2D.Double();
Arc2D.Double innerArc = new Arc2D.Double();
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));
}
//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;
circleCenterY = y;
circleCenterX = r2InPoints + x;
//Create the larger arc.
outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
//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 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 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());
//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);
//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 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);
//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;
tick3X = r2InPoints - 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.
*
* @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 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);
/**
* 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);
}
g2.setStroke(dashed);
g2.draw(glueTab1);
}
}

View File

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

View File

@ -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 <sampo.niskanen@iki.fi>
*/
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
*/

View File

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

View File

@ -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

View File

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

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
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

View File

@ -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" .
"";

View File

@ -48,6 +48,18 @@
<div class="content">
<div class="news">
<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
<a href="download.html">released</a>!</p>
<p>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.</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 class="contentholder">
<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>
</div>
<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>
<span>OpenRocket-1.1.8.jar</span>
<span>OpenRocket-1.1.9.jar</span>
</a>
<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.8/OpenRocket-1.1.8-src.zip/download">Source code</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.9/OpenRocket-1.1.9-src.zip/download">Source code</a>
</span>
</div>
<h3>Stable release</h3>
@ -117,7 +119,7 @@
Windows) by double-clicking the package icon. No installation is
required.</p>
<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 class="clear"></div>

View File

@ -49,12 +49,12 @@
<h2>Introduction</h2>
<div class="rightpane">
<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>
<span>OpenRocket-1.1.8.jar</span>
<span>OpenRocket-1.1.9.jar</span>
</a>
<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>
</span>
</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>
</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
rockets before actually building and flying them.</p>
<p>The main features include:</p>
@ -96,6 +96,18 @@
<div class="clear"></div>
<div class="news">
<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
<a href="download.html">released</a>!</p>
<p>This release contains bug fixes to the optimization methods.

View File

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

View File

@ -9,6 +9,21 @@
<!--- 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
<a href="download.html">released</a>!</p>
@ -33,6 +48,10 @@
instead of true physical phenomena. Always keep common sense at
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
<a href="download.html">released</a>!</p>
@ -46,10 +65,6 @@
<p>The release also includes design scaling support and numerous bug
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
<a href="download.html">released</a>!</p>