[Feature] Implemented RailButton Shapes (2D only)

RailButtons loaded, edited, and displayed (in 2d, and 3d)
This commit is contained in:
Daniel_M_Williams 2015-11-23 14:40:57 -05:00
parent 82e3a7ff1c
commit 1ce452265c
5 changed files with 162 additions and 137 deletions

View File

@ -977,7 +977,7 @@ LaunchLugCfg.tab.Generalprop = General properties
! LaunchLugConfig
RailBtnCfg.lbl.OuterDiam = Outer Diameter:
RailBtnCfg.lbl.Height = Height
RailBtnCfg.lbl.TotalHeight = Total Height
RailBtnCfg.lbl.Angle = Angular Position:
RailBtnCfg.lbl.PosRelativeTo = Position relative to:
RailBtnCfg.lbl.Plus = plus
@ -1389,7 +1389,7 @@ RocketComponent.Position.ABSOLUTE = Tip of the nose cone
! LaunchLug
LaunchLug.Launchlug = Launch Lug
! LaunchButton
LaunchButton.LaunchButton = Launch Button
RailButton.RailButton = Rail Button
! NoseCone
NoseCone.NoseCone = Nose cone
! Transition

View File

@ -28,24 +28,22 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
/*
* Rail Button Dimensions (side view)
*
* <= outer dia =>
* v
* > outer dia <
* | | v
* ^ [[[[[[]]]]]] flangeHeight
* total >||||||<= inner dia ^
* height |||||| v
* v [[[[[[]]]]]] standoff == baseHeight
* ================ ^
* total >||||||<= inner dia ^
* height |||||| v
* v [[[[[[]]]]]] standoff == baseHeight
* ================== ^
* (body)
*
*/
// Note: the reference point for Rail Button Components is in the center bottom of the button.
protected double outerDiameter_m;
protected double height_m;
protected double totalHeight_m;
protected double innerDiameter_m;
protected double flangeHeight_m;
// Standoff is defined as the distance from the body surface to this components reference point
// Note: the reference point for Rail Button Components is in the center bottom of the button.
protected double standoff;
protected double standoff_m;
protected final static double MINIMUM_STANDOFF= 0.001;
@ -57,10 +55,10 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
public RailButton(){
super(Position.MIDDLE);
this.outerDiameter_m = 0;
this.height_m = 0;
this.totalHeight_m = 0;
this.innerDiameter_m = 0;
this.flangeHeight_m = 0;
this.setStandoff( 0);
this.flangeHeight_m = 0.002;
this.setStandoff( 0.002);
this.setInstanceSeparation( 1.0);
}
@ -70,10 +68,10 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
this.setTotalHeight( ht);
}
public RailButton( final double od, final double id, final double h, final double _thickness, final double _standoff ) {
public RailButton( final double od, final double id, final double ht, final double _thickness, final double _standoff ) {
super(Position.MIDDLE);
this.outerDiameter_m = od;
this.height_m = h-_standoff;
this.totalHeight_m = ht;
this.innerDiameter_m = id;
this.flangeHeight_m = _thickness;
this.setStandoff( _standoff);
@ -109,9 +107,13 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
}
public double getStandoff(){
return this.standoff;
return this.standoff_m;
}
public double getBaseHeight(){
return this.getStandoff();
}
public double getOuterDiameter() {
return this.outerDiameter_m;
}
@ -121,23 +123,20 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
}
public double getInnerHeight() {
return (this.height_m - this.flangeHeight_m);
return (this.totalHeight_m - this.flangeHeight_m - this.standoff_m);
}
public double getTotalHeight() {
return this.height_m+this.standoff;
return this.totalHeight_m;
}
public double getFlangeHeight() {
return this.flangeHeight_m;
}
public double getBaseHeight(){
return this.getStandoff();
}
public void setStandoff( final double newStandoff){
this.standoff = Math.max( newStandoff, RailButton.MINIMUM_STANDOFF );
this.standoff_m = Math.max( newStandoff, RailButton.MINIMUM_STANDOFF );
}
public void setInnerDiameter( final double newID ){
@ -148,25 +147,21 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
public void setOuterDiameter( final double newOD ){
this.outerDiameter_m = newOD;
if( 0 == this.innerDiameter_m){
this.innerDiameter_m = this.outerDiameter_m*0.8;
}
if( 0 == this.instanceSeparation ){
this.instanceSeparation = newOD*8;
}
// devel
this.innerDiameter_m = newOD*0.8;
this.setInstanceSeparation( newOD*6);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
public void setTotalHeight( final double newHeight ) {
if( 0 == this.flangeHeight_m){
this.flangeHeight_m = newHeight*0.25;
}
if( 0 == this.standoff){
this.height_m = newHeight*0.75;
this.offset = newHeight*0.25;
}else{
this.height_m = newHeight-this.standoff;
}
this.totalHeight_m = newHeight;
// devel
this.flangeHeight_m = newHeight*0.25;
this.setStandoff( newHeight*0.25);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@ -201,7 +196,7 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
//
// @Override
// public void setPositionValue(double value) {
// super.setPositionValue(value);
@ -224,41 +219,11 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
return toReturn;
}
// @Override
// protected void loadFromPreset(ComponentPreset preset) {
// if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
// double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
// this.radius = outerDiameter / 2.0;
// if (preset.has(ComponentPreset.INNER_DIAMETER)) {
// double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
// this.thickness = (outerDiameter - innerDiameter) / 2.0;
// }
// }
//
// super.loadFromPreset(preset);
//
// fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
// }
//
@Override
public Type getPresetType() {
return ComponentPreset.Type.LAUNCH_LUG;
}
// @Override
// protected Coordinate[] shiftCoordinates(Coordinate[] array) {
// array = super.shiftCoordinates(array);
//
// for (int i = 0; i < array.length; i++) {
// array[i] = array[i].add(0, shiftY, shiftZ);
// }
//
// return array;
// }
@Override
public void componentChanged(ComponentChangeEvent e) {
super.componentChanged(e);
@ -278,14 +243,12 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
@Override
public double getComponentVolume() {
final double volOuter = Math.PI*Math.pow( outerDiameter_m/2, 2)*flangeHeight_m;
final double volInner = Math.PI*Math.pow( innerDiameter_m/2, 2)*(height_m - flangeHeight_m - standoff);
final double volStandoff = Math.PI*Math.pow( outerDiameter_m/2, 2)*standoff;
final double volInner = Math.PI*Math.pow( innerDiameter_m/2, 2)*getInnerHeight();
final double volStandoff = Math.PI*Math.pow( outerDiameter_m/2, 2)*standoff_m;
return (volOuter+
volInner+
volStandoff);
}
@Override
public double getInstanceSeparation(){
@ -322,14 +285,14 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
@Override
public Coordinate getComponentCG() {
// Math.PI and density are assumed constant through calcualtion, and thus may be factored out.
final double volumeInner = Math.pow( innerDiameter_m/2, 2)*(height_m - flangeHeight_m - standoff);
final double volumeOuter = Math.pow( outerDiameter_m/2, 2)*flangeHeight_m;
final double volumeStandoff = Math.pow( outerDiameter_m/2, 2)*standoff;
final double totalVolume = volumeInner + volumeOuter + volumeStandoff;
final double heightCM = (volumeInner*( this.height_m - this.flangeHeight_m/2) + volumeOuter*( this.height_m-this.flangeHeight_m)/2 - volumeStandoff*(this.standoff/2))/totalVolume;
// Math.PI and density are assumed constant through calculation, and thus may be factored out.
final double volumeFlange = Math.pow( outerDiameter_m/2, 2)*flangeHeight_m;
final double volumeInner = Math.pow( innerDiameter_m/2, 2)*(getInnerHeight());
final double volumeStandoff = Math.pow( outerDiameter_m/2, 2)*this.standoff_m;
final double totalVolume = volumeFlange + volumeInner + volumeStandoff;
final double heightCM = (volumeFlange*( this.totalHeight_m-getFlangeHeight()/2) + volumeInner*( this.standoff_m + this.getInnerHeight()/2) + volumeStandoff*(this.standoff_m/2))/totalVolume;
if( heightCM > this.height_m ){
if( heightCM > this.totalHeight_m ){
throw new BugException(" bug found while computing the CG of a RailButton: "+this.getName()+"\n height of CG: "+heightCM);
}
@ -341,8 +304,7 @@ public class RailButton extends ExternalComponent implements LineInstanceable {
@Override
public String getComponentName() {
// Launch Button
return trans.get("LaunchButton.LaunchButton");
return trans.get("RailButton.RailButton");
}
@Override

View File

@ -57,7 +57,7 @@ public class RailButtonConfig extends RocketComponentConfig {
panel.add(new BasicSlider(ODModel.getSliderModel(0, 0.001, 0.02)), "w 100lp, wrap para");
}
{ //// Height
panel.add(new JLabel(trans.get("RailBtnCfg.lbl.Height")));
panel.add(new JLabel(trans.get("RailBtnCfg.lbl.TotalHeight")));
DoubleModel heightModel = new DoubleModel(component, "TotalHeight", UnitGroup.UNITS_LENGTH, 0);
JSpinner heightSpinner = new JSpinner(heightModel.getSpinnerModel());
heightSpinner.setEditor(new SpinnerEditor(heightSpinner));

View File

@ -50,6 +50,7 @@ import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.Parachute;
import net.sf.openrocket.rocketcomponent.ParallelStage;
import net.sf.openrocket.rocketcomponent.PodSet;
import net.sf.openrocket.rocketcomponent.RailButton;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.ShockCord;
@ -134,8 +135,8 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
new FinButton(FreeformFinSet.class, trans.get("compaddbuttons.Freeform")),
//// Freeform
new FinButton(TubeFinSet.class, trans.get("compaddbuttons.Tubefin")),
// //// Rail Button // TODO: implement drawing graphics for the component
// new FinButton( RailButton.class, trans.get("compaddbuttons.RailButton")),
//// Rail Button // TODO: implement drawing graphics for the component
new FinButton( RailButton.class, trans.get("compaddbuttons.RailButton")),
//// Launch lug
new FinButton(LaunchLug.class, trans.get("compaddbuttons.Launchlug")));
row++;

View File

@ -1,7 +1,10 @@
package net.sf.openrocket.gui.rocketfigure;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.Transformation;
@ -16,50 +19,67 @@ public class RailButtonShapes extends RocketComponentShape {
net.sf.openrocket.rocketcomponent.RailButton btn = (net.sf.openrocket.rocketcomponent.RailButton)component;
final double rotation_rad = btn.getAngularOffset();
final double baseHeight = btn.getStandoff();
final double innerHeight = btn.getInnerHeight();
final double flangeHeight = btn.getFlangeHeight();
final double outerDiameter = btn.getOuterDiameter();
final double outerRadius = outerDiameter/2;
final double baseHeight = btn.getStandoff();
final double flangeHeight = btn.getFlangeHeight();
final double innerDiameter = btn.getInnerDiameter();
final double innerRadius = innerDiameter/2;
final double innerHeight = btn.getTotalHeight();
final double rotation_rad = btn.getAngularOffset();
Coordinate[] inst = transformation.transform( btn.getLocations());
//if( MathUtil.EPSILON < Math.abs(rotation)){
Shape[] s = new Shape[inst.length*3];
for (int i=0; i < inst.length; i+=3 ) {
// needs MUCH debugging. :P
// System.err.println("?? Drawing RailButton shapes at: "+inst[i].toString());
// System.err.println(" heights = "+baseHeight+", "+innerHeight+", "+flangeHeight);
// System.err.println(" dias = "+outerDiameter+", "+innerDiameter);
{// base
s[i] = new Rectangle2D.Double(
(inst[i].x-outerRadius)*S,(inst[i].y)*S,
(outerDiameter)*S, baseHeight*S);
}
{// inner
s[i+1] = new Rectangle2D.Double(
(inst[i].x-innerRadius)*S,(inst[i].y+baseHeight)*S,
(innerDiameter)*S, innerHeight*S);
}
{ // outer flange
s[i+2] = new Rectangle2D.Double(
(inst[i].x-outerRadius)*S,(inst[i].y+baseHeight+innerHeight)*S,
(outerDiameter)*S, flangeHeight*S);
}
}
// }else{
// Shape[] s = new Shape[inst.length];
// for (int i=0; i < inst.length; i++) {
// s[i] = new Rectangle2D.Double(inst[i].x*S,(inst[i].y-radius)*S,
// length*S,2*radius*S);
// }
// }
Shape[] s = new Shape[inst.length];
final double sinr = Math.abs(Math.sin(rotation_rad));
final double cosr = Math.cos(rotation_rad);
final double baseHeightcos = baseHeight*cosr;
final double innerHeightcos = innerHeight*cosr;
final double flangeHeightcos = flangeHeight*cosr;
for (int i=0; i < inst.length; i++) {
Path2D.Double compound = new Path2D.Double();
s[i] = compound;
{// base
final double drawWidth = outerDiameter;
final double drawHeight = outerDiameter*sinr;
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y);
Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+baseHeightcos)*S ), false);
compound.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+baseHeightcos)*S ), false);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+baseHeightcos)*S, drawWidth*S, drawHeight*S), false);
}
{// inner
final double drawWidth = innerDiameter;
final double drawHeight = innerDiameter*sinr;
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y+baseHeightcos);
final Point2D.Double lowerLeft = new Point2D.Double( center.x - innerRadius, center.y-innerRadius*sinr);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+innerHeightcos)*S ), false);
compound.append( new Line2D.Double( (center.x+innerRadius)*S, center.y*S, (center.x+innerRadius)*S, (center.y+innerHeightcos)*S ), false);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+innerHeightcos)*S, drawWidth*S, drawHeight*S), false);
}
{// outer flange
final double drawWidth = outerDiameter;
final double drawHeight = outerDiameter*sinr;
final Point2D.Double center = new Point2D.Double( inst[i].x, inst[i].y+(baseHeightcos+innerHeightcos));
final Point2D.Double lowerLeft = new Point2D.Double( center.x - outerRadius, center.y-outerRadius*sinr);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, lowerLeft.y*S, drawWidth*S, drawHeight*S), false);
compound.append( new Line2D.Double( lowerLeft.x*S, center.y*S, lowerLeft.x*S, (center.y+flangeHeightcos)*S ), false);
compound.append( new Line2D.Double( (center.x+outerRadius)*S, center.y*S, (center.x+outerRadius)*S, (center.y+flangeHeightcos)*S ), false);
compound.append( new Ellipse2D.Double( lowerLeft.x*S, (lowerLeft.y+flangeHeightcos)*S, drawWidth*S, drawHeight*S), false);
}
}
return RocketComponentShape.toArray(s, component);
}
@ -69,18 +89,60 @@ public class RailButtonShapes extends RocketComponentShape {
Transformation transformation,
Coordinate instanceOffset) {
net.sf.openrocket.rocketcomponent.RailButton lug = (net.sf.openrocket.rocketcomponent.RailButton)component;
//
// double or = lug.getOuterRadius();
//
// Coordinate[] start = transformation.transform( lug.getLocations());
//
// Shape[] s = new Shape[start.length];
// for (int i=0; i < start.length; i++) {
// s[i] = new Ellipse2D.Double((start[i].z-or)*S,(start[i].y-or)*S,2*or*S,2*or*S);
// }
//
Shape[] s = new Shape[0];
net.sf.openrocket.rocketcomponent.RailButton btn = (net.sf.openrocket.rocketcomponent.RailButton)component;
final double rotation_rad = btn.getAngularOffset();
final double sinr = Math.sin(rotation_rad);
final double cosr = Math.cos(rotation_rad);
final double baseHeight = btn.getStandoff();
final double innerHeight = btn.getInnerHeight();
final double flangeHeight = btn.getFlangeHeight();
final double outerDiameter = btn.getOuterDiameter();
final double outerRadius = outerDiameter/2;
final double innerDiameter = btn.getInnerDiameter();
final double innerRadius = innerDiameter/2;
Coordinate[] inst = transformation.transform( btn.getLocations());
Shape[] s = new Shape[inst.length];
for (int i=0; i < inst.length; i++) {
Path2D.Double compound = new Path2D.Double();
s[i] = compound;
// base
compound.append( getRotatedRectangle( inst[i].z, inst[i].y, outerRadius, baseHeight, rotation_rad), false );
{// inner
final double delta_r = baseHeight;
final double delta_y = delta_r*cosr;
final double delta_z = delta_r*sinr;
compound.append( getRotatedRectangle( inst[i].z+delta_z, inst[i].y+delta_y, innerRadius, innerHeight, rotation_rad ), false);
}
{// outer flange
final double delta_r = baseHeight + innerHeight;
final double delta_y = delta_r*cosr;
final double delta_z = delta_r*sinr;
compound.append( getRotatedRectangle( inst[i].z+delta_z, inst[i].y+delta_y, outerRadius, flangeHeight, rotation_rad ), false);
}
}
return RocketComponentShape.toArray(s, component);
}
public static Shape getRotatedRectangle( final double x, final double y, final double radius, final double height, final double angle_rad ){
Path2D.Double rect = new Path2D.Double();
final double sinr = Math.sin(angle_rad);
final double cosr = Math.cos(angle_rad);
rect.moveTo( (x-radius*cosr)*S, (y+radius*sinr)*S);
rect.lineTo( (x-radius*cosr+height*sinr)*S, (y+radius*sinr+height*cosr)*S);
rect.lineTo( (x+radius*cosr+height*sinr)*S, (y-radius*sinr+height*cosr)*S);
rect.lineTo( (x+radius*cosr)*S, (y-radius*sinr)*S);
rect.closePath();
// add points
return rect;
}
}