Merge pull request #869 from teyrana/fix/868/fin-tab-offset

[fixes #868] Fin tabs correctly adjust their location when the fin tab _length_ is changed.
This commit is contained in:
Joe Pfeiffer 2022-01-11 11:24:15 -07:00 committed by GitHub
commit affcc8b51f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 39 deletions

View File

@ -71,7 +71,7 @@ public class EllipticalFinSet extends FinSet {
if (MathUtil.equals(this.length, length)) if (MathUtil.equals(this.length, length))
return; return;
this.length = length; this.length = length;
validateFinTab(); validateFinTabLength();
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
} }

View File

@ -272,7 +272,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
} }
tabHeight = newTabHeight; tabHeight = newTabHeight;
validateFinTabHeight();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
} }
@ -291,9 +291,15 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
tabLength = lengthRequest; tabLength = lengthRequest;
setTabPosition();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
} }
protected void setTabPosition(){
this.tabPosition = this.tabOffsetMethod.getAsPosition(tabOffset, tabLength, length);
}
/** /**
* internally, set the internal offset and optionally validate tab * internally, set the internal offset and optionally validate tab
* *
@ -301,7 +307,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
*/ */
public void setTabOffset( final double offsetRequest) { public void setTabOffset( final double offsetRequest) {
tabOffset = offsetRequest; tabOffset = offsetRequest;
tabPosition = tabOffsetMethod.getAsPosition( tabOffset, tabLength, length); setTabPosition();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
} }
@ -316,7 +322,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
*/ */
public void setTabOffsetMethod(final AxialMethod newPositionMethod) { public void setTabOffsetMethod(final AxialMethod newPositionMethod) {
this.tabOffsetMethod = newPositionMethod; this.tabOffsetMethod = newPositionMethod;
this.tabOffset = tabOffsetMethod.getAsOffset( tabPosition, tabLength, length); this.tabOffset = this.tabOffsetMethod.getAsOffset(tabPosition, tabLength, length);
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
} }
@ -338,25 +345,32 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
return tabPosition + tabLength; return tabPosition + tabLength;
} }
public void validateFinTab(){ public void validateFinTabPosition() {
this.tabPosition = this.tabOffsetMethod.getAsPosition(tabOffset, tabLength, length);
//check front bounds: //check front bounds:
if( tabPosition < 0){ if (tabPosition < 0) {
this.tabPosition = 0; this.tabPosition = 0;
} }
//check tail bounds: //check tail bounds:
if (this.length < tabPosition ) { if (this.length < tabPosition) {
this.tabPosition = length; this.tabPosition = length;
} }
}
public void validateFinTabLength() {
//System.err.println(String.format(" >> Fin Tab Length: %.6f @ %.6f", tabLength, tabOffset));
final double xTabBack = getTabTrailingEdge(); final double xTabBack = getTabTrailingEdge();
if( this.length < xTabBack ){ if (this.length < xTabBack) {
this.tabLength -= (xTabBack - this.length); this.tabLength -= (xTabBack - this.length);
} }
tabLength = Math.max(0, tabLength); tabLength = Math.max(0, tabLength);
//System.err.println(String.format(" << Fin Tab Length: %.6f @ %.6f", tabLength, tabOffset));
}
public void validateFinTabHeight(){
// check tab height // check tab height
if( null != getParent() ){ if( null != getParent() ){
// pulls the parent-body radius at the fin-tab reference point. // pulls the parent-body radius at the fin-tab reference point.
@ -791,6 +805,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
this.totalVolume = Double.NaN; this.totalVolume = Double.NaN;
this.cantRotation = null; this.cantRotation = null;
} }
super.componentChanged(e); super.componentChanged(e);
} }

View File

@ -319,7 +319,7 @@ public class FreeformFinSet extends FinSet {
clampLastPoint(); clampLastPoint();
if (oldLength != this.length) if (oldLength != this.length)
validateFinTab(); validateFinTabLength();
} }
} }

View File

@ -77,8 +77,9 @@ public class TrapezoidFinSet extends FinSet {
if (length == r) if (length == r)
return; return;
length = Math.max(r, 0); length = Math.max(r, 0);
validateFinTab(); setTabPosition();
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
fireComponentChangeEvent(ComponentChangeEvent.AEROMASS_CHANGE);
} }
public double getTipChord() { public double getTipChord() {

View File

@ -3,6 +3,7 @@ package net.sf.openrocket.rocketcomponent;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import net.sf.openrocket.material.Material; import net.sf.openrocket.material.Material;
import net.sf.openrocket.util.TestRockets;
import org.junit.Test; import org.junit.Test;
import net.sf.openrocket.rocketcomponent.position.*; import net.sf.openrocket.rocketcomponent.position.*;
@ -92,36 +93,72 @@ public class FinSetTest extends BaseTestCase {
fins.setTabOffsetMethod( methods[caseIndex]); fins.setTabOffsetMethod( methods[caseIndex]);
//query //query
double actShift = fins.getTabOffset(); final double actShift = fins.getTabOffset();
assertEquals(String.format("Offset doesn't match for: %s \n", methods[caseIndex].name()), expShift[caseIndex], actShift, EPSILON); assertEquals(String.format("Offset doesn't match for: %s \n", methods[caseIndex].name()), expShift[caseIndex], actShift, EPSILON);
} }
} }
@Test @Test
public void testTabGetAs(){ public void testTabGetAs() {
final FinSet fins = FinSetTest.createSimpleFin(); final FinSet fins = FinSetTest.createSimpleFin();
assertEquals("incorrect fin length:", 0.06, fins.getLength(), EPSILON); assertEquals("incorrect fin length:", 0.06, fins.getLength(), EPSILON);
assertEquals("incorrect fin tab length:", 0.02, fins.getTabLength(), EPSILON); assertEquals("incorrect fin tab length:", 0.02, fins.getTabLength(), EPSILON);
// TOP -> native(TOP) { // TOP -> native(TOP)
fins.setTabOffsetMethod(AxialMethod.TOP); fins.setTabOffsetMethod(AxialMethod.TOP);
fins.setTabOffset(0.0); fins.setTabOffset(0.0);
assertEquals("Setting by TOP method failed!", 0.0, fins.getTabFrontEdge(), EPSILON); assertEquals("Setting by TOP method failed!", 0.0, fins.getTabFrontEdge(), EPSILON);
assertEquals("Setting by TOP method failed!", 0.0, fins.getTabOffset(), EPSILON); assertEquals("Setting by TOP method failed!", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Setting by TOP method failed!", 0.02, fins.getTabLength(), EPSILON);
// MIDDLE -> native }
{ // MIDDLE -> native
fins.setTabOffsetMethod(AxialMethod.MIDDLE); fins.setTabOffsetMethod(AxialMethod.MIDDLE);
fins.setTabOffset(0.0); fins.setTabOffset(0.0);
assertEquals("Setting by TOP method failed!", 0.02, fins.getTabFrontEdge(), EPSILON); assertEquals("Setting by MIDDLE method failed!", 0.02, fins.getTabFrontEdge(), EPSILON);
assertEquals("Setting by TOP method failed!", 0.0, fins.getTabOffset(), EPSILON); assertEquals("Setting by MIDDLE method failed!", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Setting by MIDDLE method failed!", 0.02, fins.getTabLength(), EPSILON);
// BOTTOM -> native }
{// BOTTOM -> native
fins.setTabOffsetMethod(AxialMethod.BOTTOM); fins.setTabOffsetMethod(AxialMethod.BOTTOM);
fins.setTabOffset(0.0); fins.setTabOffset(0.0);
assertEquals("Setting by TOP method failed!", 0.04, fins.getTabFrontEdge(), EPSILON); assertEquals("Setting by BOTTOM method failed!", 0.04, fins.getTabFrontEdge(), EPSILON);
assertEquals("Setting by TOP method failed!", 0.0, fins.getTabOffset(), EPSILON); assertEquals("Setting by BOTTOM method failed!", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Setting by BOTTOM method failed!", 0.02, fins.getTabLength(), EPSILON);
}
}
@Test
public void testTabSetLength() {
final Rocket rocket = TestRockets.makeEstesAlphaIII();
final BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
assertEquals("incorrect body tube length:", 0.20, body.getLength(), EPSILON);
final FinSet fins = (FinSet)body.getChild(0);
fins.setTabHeight(0.01);
fins.setTabLength(0.02);
assertEquals("incorrect fin length:", 0.05, fins.getLength(), EPSILON);
assertEquals("incorrect fin tab height:", 0.01, fins.getTabHeight(), EPSILON);
assertEquals("incorrect fin tab length:", 0.02, fins.getTabLength(), EPSILON);
assertEquals("incorrect fin location", 0.015, fins.getTabFrontEdge(), EPSILON);
{ // MIDDLE -> native
fins.setTabOffsetMethod(AxialMethod.MIDDLE);
fins.setTabOffset(0.0);
assertEquals("Setting by MIDDLE method failed!", 0.015, fins.getTabFrontEdge(), EPSILON);
assertEquals("Setting by MIDDLE method failed!", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Setting by MIDDLE method failed!", 0.02, fins.getTabLength(), EPSILON);
fins.setTabLength(0.04);
assertEquals("Setting by MIDDLE method failed!", 0.005, fins.getTabFrontEdge(), EPSILON);
assertEquals("Setting by MIDDLE method failed!", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Setting by MIDDLE method failed!", 0.04, fins.getTabLength(), EPSILON);
}
} }
@Test @Test
@ -139,8 +176,8 @@ public class FinSetTest extends BaseTestCase {
((TrapezoidFinSet)fins).setRootChord(0.08); ((TrapezoidFinSet)fins).setRootChord(0.08);
assertEquals("Front edge doesn't match after adjusting root chord...", 0.03, fins.getTabFrontEdge(), EPSILON);
assertEquals("Offset doesn't match after adjusting root chord....", 0.0, fins.getTabOffset(), EPSILON); assertEquals("Offset doesn't match after adjusting root chord....", 0.0, fins.getTabOffset(), EPSILON);
assertEquals("Front edge doesn't match after adjusting root chord...", 0.03, fins.getTabFrontEdge(), EPSILON);
} }
@Test @Test