[#2463] Fix shoulder radius scaling issue when smaller than 1
This commit is contained in:
parent
803935fc06
commit
31fd57131e
core/src/main/java/info/openrocket/core/rocketcomponent
swing/src/main/java
@ -130,6 +130,19 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
||||
return isFlipped ? getForeShoulderRadius() : getAftShoulderRadius();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shoulder radius (independent of whether the nose cone is flipped or not).
|
||||
* @param radius the new shoulder radius
|
||||
* @param doClamping whether to clamp the shoulder radius to the nose cone radius
|
||||
*/
|
||||
public void setShoulderRadius(double radius, boolean doClamping) {
|
||||
if (isFlipped) {
|
||||
setForeShoulderRadius(radius, doClamping);
|
||||
} else {
|
||||
setAftShoulderRadius(radius, doClamping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shoulder radius (independent of whether the nose cone is flipped or
|
||||
* not).
|
||||
|
@ -47,6 +47,7 @@ import info.openrocket.core.rocketcomponent.SymmetricComponent;
|
||||
import info.openrocket.core.rocketcomponent.ThicknessRingComponent;
|
||||
import info.openrocket.core.rocketcomponent.Transition;
|
||||
import info.openrocket.core.rocketcomponent.TrapezoidFinSet;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -107,18 +108,18 @@ public class ScaleDialog extends JDialog {
|
||||
addScaler(SymmetricComponent.class, "Thickness", "isFilled", SCALERS_NO_OFFSET);
|
||||
|
||||
// Transition
|
||||
addScaler(Transition.class, "ForeRadius", "isForeRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "AftRadius", "isAftRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "ForeShoulderRadius", SCALERS_NO_OFFSET);
|
||||
list = new ArrayList<>(1);
|
||||
list.add(new TransitionScaler());
|
||||
SCALERS_NO_OFFSET.put(Transition.class, list);
|
||||
addScaler(Transition.class, "ForeShoulderThickness", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "ForeShoulderLength", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "AftShoulderRadius", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "AftShoulderThickness", SCALERS_NO_OFFSET);
|
||||
addScaler(Transition.class, "AftShoulderLength", SCALERS_NO_OFFSET);
|
||||
|
||||
// Nose cone
|
||||
addScaler(NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||
addScaler(NoseCone.class, "ShoulderRadius", SCALERS_NO_OFFSET);
|
||||
list = new ArrayList<>(1);
|
||||
list.add(new NoseConeScaler());
|
||||
SCALERS_NO_OFFSET.put(NoseCone.class, list);
|
||||
addScaler(NoseCone.class, "ShoulderThickness", SCALERS_NO_OFFSET);
|
||||
addScaler(NoseCone.class, "ShoulderLength", SCALERS_NO_OFFSET);
|
||||
|
||||
@ -198,14 +199,14 @@ public class ScaleDialog extends JDialog {
|
||||
}
|
||||
|
||||
private static void addScaler(Class<? extends RocketComponent> componentClass, String methodName,
|
||||
Map<Class<? extends RocketComponent>, List<Scaler>> scaler) {
|
||||
addScaler(componentClass, methodName, null, scaler);
|
||||
Map<Class<? extends RocketComponent>, List<Scaler>> scaler, Object... arguments) {
|
||||
addScaler(componentClass, methodName, null, scaler, arguments);
|
||||
}
|
||||
|
||||
private static void addScaler(Class<? extends RocketComponent> componentClass, String methodName, String autoMethodName,
|
||||
Map<Class<? extends RocketComponent>, List<Scaler>> scaler) {
|
||||
Map<Class<? extends RocketComponent>, List<Scaler>> scaler, Object... arguments) {
|
||||
List<Scaler> list = scaler.computeIfAbsent(componentClass, k -> new ArrayList<>());
|
||||
list.add(new GeneralScaler(componentClass, methodName, autoMethodName));
|
||||
list.add(new GeneralScaler(componentClass, methodName, autoMethodName, arguments));
|
||||
}
|
||||
|
||||
|
||||
@ -658,7 +659,7 @@ public class ScaleDialog extends JDialog {
|
||||
* Interface for scaling a specific component/value.
|
||||
*/
|
||||
private interface Scaler {
|
||||
public void scale(RocketComponent c, double multiplier, boolean scaleMass);
|
||||
void scale(RocketComponent c, double multiplier, boolean scaleMass);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -669,34 +670,52 @@ public class ScaleDialog extends JDialog {
|
||||
private final Method getter;
|
||||
private final Method setter;
|
||||
private final Method autoMethod;
|
||||
private final Object[] arguments;
|
||||
|
||||
public GeneralScaler(Class<? extends RocketComponent> componentClass, String methodName, String autoMethodName) {
|
||||
|
||||
getter = Reflection.findMethod(componentClass, "get" + methodName);
|
||||
setter = Reflection.findMethod(componentClass, "set" + methodName, double.class);
|
||||
if (autoMethodName != null) {
|
||||
autoMethod = Reflection.findMethod(componentClass, autoMethodName);
|
||||
public GeneralScaler(Class<? extends RocketComponent> componentClass, String methodName, String autoMethodName,
|
||||
Object... arguments) {
|
||||
|
||||
this.getter = Reflection.findMethod(componentClass, "get" + methodName);
|
||||
if (arguments == null || arguments.length == 0) {
|
||||
this.setter = Reflection.findMethod(componentClass, "set" + methodName, double.class);
|
||||
} else {
|
||||
autoMethod = null;
|
||||
Class<?>[] argumentClasses = new Class<?>[arguments.length + 1];
|
||||
argumentClasses[0] = double.class;
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
argumentClasses[i+1] = ClassUtils.wrapperToPrimitive(arguments[i].getClass());
|
||||
}
|
||||
this.setter = Reflection.findMethod(componentClass, "set" + methodName, argumentClasses);
|
||||
}
|
||||
this.arguments = arguments;
|
||||
if (autoMethodName != null) {
|
||||
this.autoMethod = Reflection.findMethod(componentClass, autoMethodName);
|
||||
} else {
|
||||
this.autoMethod = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scale(RocketComponent c, double multiplier, boolean scaleMass) {
|
||||
|
||||
// Do not scale if set to automatic
|
||||
if (autoMethod != null) {
|
||||
boolean auto = (Boolean) autoMethod.invoke(c);
|
||||
if (this.autoMethod != null) {
|
||||
boolean auto = (Boolean) this.autoMethod.invoke(c);
|
||||
if (auto) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale value
|
||||
double value = (Double) getter.invoke(c);
|
||||
double value = (Double) this.getter.invoke(c);
|
||||
value = value * multiplier;
|
||||
setter.invoke(c, value);
|
||||
if (this.arguments == null || this.arguments.length == 0) {
|
||||
this.setter.invoke(c, value);
|
||||
} else {
|
||||
Object[] parameters = new Object[this.arguments.length + 1];
|
||||
parameters[0] = value;
|
||||
System.arraycopy(this.arguments, 0, parameters, 1, this.arguments.length);
|
||||
this.setter.invoke(c, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -723,6 +742,56 @@ public class ScaleDialog extends JDialog {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TransitionScaler implements Scaler {
|
||||
|
||||
@Override
|
||||
public void scale(RocketComponent component, double multiplier, boolean scaleMass) {
|
||||
final Map<Class<? extends RocketComponent>, List<Scaler>> scalers = new HashMap<>();
|
||||
|
||||
// If the multiplier is larger than 1, the fore/aft radius is scaled first
|
||||
// to prevent the fore/aft shoulder radius from becoming larger than the fore/aft radius
|
||||
if (multiplier >= 1) {
|
||||
addScaler(Transition.class, "ForeRadius", "isForeRadiusAutomatic", scalers);
|
||||
addScaler(Transition.class, "AftRadius", "isForeRadiusAutomatic", scalers);
|
||||
addScaler(Transition.class, "ForeShoulderRadius", scalers, false);
|
||||
addScaler(Transition.class, "AftShoulderRadius", scalers, false);
|
||||
}
|
||||
// If the multiplier is smaller than 1, the fore/aft shoulder radius is scaled first
|
||||
// to prevent the fore/aft radius from becoming larger than the fore/aft shoulder radius
|
||||
else {
|
||||
addScaler(Transition.class, "ForeShoulderRadius", scalers, false);
|
||||
addScaler(Transition.class, "AftShoulderRadius", scalers, false);
|
||||
addScaler(Transition.class, "ForeRadius", "isForeRadiusAutomatic", scalers);
|
||||
addScaler(Transition.class, "AftRadius", "isForeRadiusAutomatic", scalers);
|
||||
}
|
||||
|
||||
performIterativeScaling(scalers, component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoseConeScaler implements Scaler {
|
||||
|
||||
@Override
|
||||
public void scale(RocketComponent component, double multiplier, boolean scaleMass) {
|
||||
final Map<Class<? extends RocketComponent>, List<Scaler>> scalers = new HashMap<>();
|
||||
|
||||
// If the multiplier is larger than 1, the base radius is scaled first
|
||||
// to prevent the shoulder radius from becoming larger than the base radius
|
||||
if (multiplier >= 1) {
|
||||
addScaler(NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic", scalers);
|
||||
addScaler(NoseCone.class, "ShoulderRadius", scalers);
|
||||
}
|
||||
// If the multiplier is smaller than 1, the shoulder radius is scaled first
|
||||
// to prevent the base radius from becoming larger than the shoulder radius
|
||||
else {
|
||||
addScaler(NoseCone.class, "ShoulderRadius", scalers);
|
||||
addScaler(NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic", scalers);
|
||||
}
|
||||
|
||||
performIterativeScaling(scalers, component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MassComponentScaler implements Scaler {
|
||||
|
||||
@ -768,11 +837,7 @@ public class ScaleDialog extends JDialog {
|
||||
addScaler(RadiusRingComponent.class, "OuterRadius", "isOuterRadiusAutomatic", scalers);
|
||||
}
|
||||
|
||||
for (List<Scaler> foo : scalers.values()) {
|
||||
for (Scaler s : foo) {
|
||||
s.scale(component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
performIterativeScaling(scalers, component, multiplier, scaleMass);
|
||||
}
|
||||
|
||||
}
|
||||
@ -790,11 +855,7 @@ public class ScaleDialog extends JDialog {
|
||||
addScaler(ThicknessRingComponent.class, "OuterRadius", "isOuterRadiusAutomatic", scalers);
|
||||
}
|
||||
|
||||
for (List<Scaler> foo : scalers.values()) {
|
||||
for (Scaler s : foo) {
|
||||
s.scale(component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
performIterativeScaling(scalers, component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
|
||||
@ -817,10 +878,15 @@ public class ScaleDialog extends JDialog {
|
||||
addScaler(RailButton.class, "TotalHeight", scalers);
|
||||
}
|
||||
|
||||
for (List<Scaler> foo : scalers.values()) {
|
||||
for (Scaler s : foo) {
|
||||
s.scale(component, multiplier, scaleMass);
|
||||
}
|
||||
performIterativeScaling(scalers, component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
|
||||
private static void performIterativeScaling(Map<Class<? extends RocketComponent>, List<Scaler>> scalers,
|
||||
RocketComponent component, double multiplier, boolean scaleMass) {
|
||||
for (List<Scaler> foo : scalers.values()) {
|
||||
for (Scaler s : foo) {
|
||||
s.scale(component, multiplier, scaleMass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ open module info.openrocket.swing {
|
||||
requires com.formdev.flatlaf.extras;
|
||||
requires com.formdev.flatlaf.intellijthemes;
|
||||
requires org.checkerframework.checker.qual;
|
||||
requires org.apache.commons.lang3;
|
||||
|
||||
// Service providers
|
||||
// Also edit swing/src/main/resources/META-INF/services !! (until gradle-modules-plugin supports service
|
||||
|
Loading…
x
Reference in New Issue
Block a user