From 1ce452265c5dd41af6e73144960766d4ab987385 Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Mon, 23 Nov 2015 14:40:57 -0500 Subject: [PATCH] [Feature] Implemented RailButton Shapes (2D only) RailButtons loaded, edited, and displayed (in 2d, and 3d) --- core/resources/l10n/messages.properties | 4 +- .../rocketcomponent/RailButton.java | 126 +++++--------- .../gui/configdialog/RailButtonConfig.java | 2 +- .../gui/main/ComponentAddButtons.java | 5 +- .../gui/rocketfigure/RailButtonShapes.java | 162 ++++++++++++------ 5 files changed, 162 insertions(+), 137 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 15248f1a7..3fe7b7463 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -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 diff --git a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java index fd533f47f..e6ac818d1 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java @@ -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 diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java index 931e9c583..a8ac1f2d2 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java @@ -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)); diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java index 344ebc099..57f6fe30a 100644 --- a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java +++ b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java @@ -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++; diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/RailButtonShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/RailButtonShapes.java index 2f7243166..0e0611666 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/RailButtonShapes.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/RailButtonShapes.java @@ -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; + } }