From c9dadc10fac9061acea8a34a10c0d8892f89dd16 Mon Sep 17 00:00:00 2001 From: Luiz Victor Linhares Rocha Date: Thu, 13 Oct 2016 15:04:03 -0300 Subject: [PATCH 1/5] adds documentation to aerodynmics package and some refactoring of classes --- .../aerodynamics/AerodynamicForces.java | 120 +++++--- .../aerodynamics/BarrowmanCalculator.java | 281 ++++++++++++------ .../aerodynamics/FlightConditions.java | 51 +++- .../sf/openrocket/aerodynamics/Warning.java | 33 +- .../openrocket/util/AbstractChangeSource.java | 3 + 5 files changed, 309 insertions(+), 179 deletions(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java b/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java index 2bb6d75b1..6bd6d15ad 100644 --- a/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java +++ b/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java @@ -14,7 +14,7 @@ public class AerodynamicForces implements Cloneable, Monitorable { */ private RocketComponent component = null; - + /** CP and CNa. */ private Coordinate cp = null; @@ -25,11 +25,11 @@ public class AerodynamicForces implements Cloneable, Monitorable { * compute CNa directly. */ private double CNa = Double.NaN; - + /** Normal force coefficient. */ private double CN = Double.NaN; - + /** Pitching moment coefficient, relative to the coordinate origin. */ private double Cm = Double.NaN; @@ -48,7 +48,7 @@ public class AerodynamicForces implements Cloneable, Monitorable { /** Roll moment forcing coefficient */ private double CrollForce = Double.NaN; - + /** Axial drag coefficient, CA */ private double Caxial = Double.NaN; @@ -71,160 +71,184 @@ public class AerodynamicForces implements Cloneable, Monitorable { private int modID = 0; + /** + * creates an empty bean of AerodynamicForces with NaN values + */ + public AerodynamicForces() { + //all done in members declarations + } + /** + * initializes an AerodynamicForces already at zero + * @param zero flag to iniatilize value to zero or not + */ + public AerodynamicForces(boolean zero) { + if (zero) + this.zero(); + } + + /** + * gives a new component to be linked with + * changes it's modification id + * @param component The rocket component + */ public void setComponent(RocketComponent component) { this.component = component; modID++; } - + + /** + * + * @return the actual component linked with this + */ public RocketComponent getComponent() { return component; } - + public void setCP(Coordinate cp) { this.cp = cp; modID++; } - + public Coordinate getCP() { return cp; } - + public void setCNa(double cNa) { CNa = cNa; modID++; } - + public double getCNa() { return CNa; } - + public void setCN(double cN) { CN = cN; modID++; } - + public double getCN() { return CN; } - + public void setCm(double cm) { Cm = cm; modID++; } - + public double getCm() { return Cm; } - + public void setCside(double cside) { Cside = cside; modID++; } - + public double getCside() { return Cside; } - + public void setCyaw(double cyaw) { Cyaw = cyaw; modID++; } - + public double getCyaw() { return Cyaw; } - + public void setCroll(double croll) { Croll = croll; modID++; } - + public double getCroll() { return Croll; } - + public void setCrollDamp(double crollDamp) { CrollDamp = crollDamp; modID++; } - + public double getCrollDamp() { return CrollDamp; } - + public void setCrollForce(double crollForce) { CrollForce = crollForce; modID++; } - + public double getCrollForce() { return CrollForce; } - + public void setCaxial(double caxial) { Caxial = caxial; modID++; } - + public double getCaxial() { return Caxial; } - + public void setCD(double cD) { CD = cD; modID++; } - + public double getCD() { return CD; } - + public void setPressureCD(double pressureCD) { this.pressureCD = pressureCD; modID++; } - + public double getPressureCD() { return pressureCD; } - + public void setBaseCD(double baseCD) { this.baseCD = baseCD; modID++; } - + public double getBaseCD() { return baseCD; } - + public void setFrictionCD(double frictionCD) { this.frictionCD = frictionCD; modID++; } - + public double getFrictionCD() { return frictionCD; } - + public void setPitchDampingMoment(double pitchDampingMoment) { this.pitchDampingMoment = pitchDampingMoment; modID++; } - + public double getPitchDampingMoment() { return pitchDampingMoment; } - + public void setYawDampingMoment(double yawDampingMoment) { this.yawDampingMoment = yawDampingMoment; modID++; } - + public double getYawDampingMoment() { return yawDampingMoment; } - + /** @@ -232,7 +256,7 @@ public class AerodynamicForces implements Cloneable, Monitorable { */ public void reset() { setComponent(null); - + setCP(null); setCNa(Double.NaN); setCN(Double.NaN); @@ -253,7 +277,7 @@ public class AerodynamicForces implements Cloneable, Monitorable { */ public void zero() { // component untouched - + setCP(Coordinate.NUL); setCNa(0); setCN(0); @@ -268,12 +292,12 @@ public class AerodynamicForces implements Cloneable, Monitorable { setPitchDampingMoment(0); setYawDampingMoment(0); } - + @Override public AerodynamicForces clone() { try { - return (AerodynamicForces)super.clone(); + return (AerodynamicForces) super.clone(); } catch (CloneNotSupportedException e) { throw new BugException("CloneNotSupportedException?!?"); } @@ -308,13 +332,13 @@ public class AerodynamicForces implements Cloneable, Monitorable { @Override public int hashCode() { - return (int) (1000*(this.getCD()+this.getCaxial()+this.getCNa())) + this.getCP().hashCode(); + return (int) (1000 * (this.getCD() + this.getCaxial() + this.getCNa())) + this.getCP().hashCode(); } @Override public String toString() { - String text="AerodynamicForces["; + String text = "AerodynamicForces["; if (getComponent() != null) text += "component:" + getComponent() + ","; @@ -340,14 +364,14 @@ public class AerodynamicForces implements Cloneable, Monitorable { if (!Double.isNaN(getCD())) text += "CD:" + getCD() + ","; - - if (text.charAt(text.length()-1) == ',') - text = text.substring(0, text.length()-1); + + if (text.charAt(text.length() - 1) == ',') + text = text.substring(0, text.length() - 1); text += "]"; return text; } - + @Override public int getModID() { return modID; diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index be139e147..17fb25a6b 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -32,14 +32,14 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { private static final String BARROWMAN_PACKAGE = "net.sf.openrocket.aerodynamics.barrowman"; private static final String BARROWMAN_SUFFIX = "Calc"; - + private Map calcMap = null; private double cacheDiameter = -1; private double cacheLength = -1; - + public BarrowmanCalculator() { } @@ -62,59 +62,76 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return forces.getCP(); } - - @Override public Map getForceAnalysis(Configuration configuration, FlightConditions conditions, WarningSet warnings) { checkCache(configuration); - AerodynamicForces f; - Map map = - new LinkedHashMap(); + Map map = getComponentsMap(configuration); - // Add all components to the map - for (RocketComponent c : configuration) { - f = new AerodynamicForces(); - f.setComponent(c); - - map.put(c, f); - } - - // Calculate non-axial force data AerodynamicForces total = calculateNonAxialForces(configuration, conditions, map, warnings); - - // Calculate friction data - total.setFrictionCD(calculateFrictionDrag(configuration, conditions, map, warnings)); - total.setPressureCD(calculatePressureDrag(configuration, conditions, map, warnings)); - total.setBaseCD(calculateBaseDrag(configuration, conditions, map, warnings)); + calculateFrictionData(total, configuration, conditions, warnings); total.setComponent(configuration.getRocket()); + map.put(total.getComponent(), total); - - - for (RocketComponent c : map.keySet()) { - f = map.get(c); - if (Double.isNaN(f.getBaseCD()) && Double.isNaN(f.getPressureCD()) && - Double.isNaN(f.getFrictionCD())) - continue; - if (Double.isNaN(f.getBaseCD())) - f.setBaseCD(0); - if (Double.isNaN(f.getPressureCD())) - f.setPressureCD(0); - if (Double.isNaN(f.getFrictionCD())) - f.setFrictionCD(0); - f.setCD(f.getBaseCD() + f.getPressureCD() + f.getFrictionCD()); - f.setCaxial(calculateAxialDrag(conditions, f.getCD())); - } - + checkCDAndApplyFriction(map, conditions); return map; } + /** + * get a map of rocket components with their own Aerodynamic forces bean + * TODO: LOW: maybe transfer the function to Configuration class? + * @param configuration The rocket configuration + * @return the map of rocket configuration with it's + * correspondent aerodynamic forces bean + */ + private Map getComponentsMap(Configuration configuration) { + Map map = new LinkedHashMap(); + // Add all components to the map + for (RocketComponent c : configuration) { + AerodynamicForces f = new AerodynamicForces(); + f.setComponent(c); + map.put(c, f); + } + return map; + } + + /** + * check an analysis to fix possible invalid CDs and apply the actual friction + * + * @param forceAnalysis + * @param conditions + */ + private void checkCDAndApplyFriction(Map forceAnalysis, FlightConditions conditions) { + for (RocketComponent c : forceAnalysis.keySet()) { + checkCDConsistency(forceAnalysis.get(c)); + applyFriction(forceAnalysis.get(c), conditions); + } + } + + /** + * fixes possibles NaN in previous calculation of CDs + * + * @param f + * @param conditions + */ + private void checkCDConsistency(AerodynamicForces f) { + if (Double.isNaN(f.getBaseCD()) && Double.isNaN(f.getPressureCD()) && + Double.isNaN(f.getFrictionCD())) + return; + if (Double.isNaN(f.getBaseCD())) + f.setBaseCD(0); + if (Double.isNaN(f.getPressureCD())) + f.setPressureCD(0); + if (Double.isNaN(f.getFrictionCD())) + f.setFrictionCD(0); + } + + - @Override public AerodynamicForces getAerodynamicForces(Configuration configuration, FlightConditions conditions, WarningSet warnings) { @@ -127,27 +144,53 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { AerodynamicForces total = calculateNonAxialForces(configuration, conditions, null, warnings); // Calculate friction data - total.setFrictionCD(calculateFrictionDrag(configuration, conditions, null, warnings)); - total.setPressureCD(calculatePressureDrag(configuration, conditions, null, warnings)); - total.setBaseCD(calculateBaseDrag(configuration, conditions, null, warnings)); - - total.setCD(total.getFrictionCD() + total.getPressureCD() + total.getBaseCD()); - - total.setCaxial(calculateAxialDrag(conditions, total.getCD())); + calculateFrictionData(total, configuration, conditions, warnings); + applyFriction(total, conditions); // Calculate pitch and yaw damping moments calculateDampingMoments(configuration, conditions, total); - total.setCm(total.getCm() - total.getPitchDampingMoment()); - total.setCyaw(total.getCyaw() - total.getYawDampingMoment()); - - + applyDampingMoments(total); return total; } + /** + * Applies the actual influence of friction in an AerodynamicForces set + * + * @param force the Aerodynamic forces to be applied with friction + * @param conditions the flight conditions in consideration + */ + private void applyFriction(AerodynamicForces force, FlightConditions conditions) { + force.setCD(force.getFrictionCD() + force.getPressureCD() + force.getBaseCD()); + force.setCaxial(calculateAxialDrag(conditions, force.getCD())); + } - - - /* + /** + * does the actual action of damping into an AerodynamicForces set + * + * @param total the AerodynamicForces object to be applied with the damping + */ + private void applyDampingMoments(AerodynamicForces total) { + total.setCm(total.getCm() - total.getPitchDampingMoment()); + total.setCyaw(total.getCyaw() - total.getYawDampingMoment()); + } + + /** + * Will calculate all basic CD from an AerodynamicForces set + * @param total The AerodynamicForces that will be calculated + * @param configuration the Rocket configutarion + * @param conditions Flight conditions in the simulation + * @param warnings Warning set to handle special events + */ + private void calculateFrictionData(AerodynamicForces total, Configuration configuration, FlightConditions conditions, WarningSet warnings) { + total.setFrictionCD(calculateFrictionDrag(configuration, conditions, null, warnings)); + total.setPressureCD(calculatePressureDrag(configuration, conditions, null, warnings)); + total.setBaseCD(calculateBaseDrag(configuration, conditions, null, warnings)); + } + + + + + /** * Perform the actual CP calculation. */ private AerodynamicForces calculateNonAxialForces(Configuration configuration, FlightConditions conditions, @@ -155,8 +198,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { checkCache(configuration); - AerodynamicForces total = new AerodynamicForces(); - total.zero(); + AerodynamicForces total = new AerodynamicForces(true); double radius = 0; // aft radius of previous component double componentX = 0; // aft coordinate of previous component @@ -168,9 +210,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { if (conditions.getAOA() > 17.5 * Math.PI / 180) warnings.add(new Warning.LargeAOA(conditions.getAOA())); - - if (calcMap == null) - buildCalcMap(configuration); + + checkCalcMap(configuration); for (RocketComponent component : configuration) { @@ -207,6 +248,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { forces.setCP(component.toAbsolute(forces.getCP())[0]); forces.setCm(forces.getCN() * forces.getCP().x / conditions.getRefLength()); + //TODO: LOW: Why is it here? was this the todo from above? Vicilu if (map != null) { AerodynamicForces f = map.get(component); @@ -219,6 +261,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { f.setCroll(forces.getCroll()); f.setCrollDamp(forces.getCrollDamp()); f.setCrollForce(forces.getCrollForce()); + map.replace(component, f); //have you forgotten to add this? } total.setCP(total.getCP().average(forces.getCP())); @@ -236,11 +279,19 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } - - - //////////////// DRAG CALCULATIONS //////////////// - + + //////////////// DRAG CALCULATIONS //////////////// + //TODO: LOW: clarify what map is doing here, or use it + /** + * Calculation of drag coefficient due to air friction + * + * @param configuration Rocket configuration + * @param conditions Flight conditions taken into account + * @param map ? + * @param set Set to handle + * @return + */ private double calculateFrictionDrag(Configuration configuration, FlightConditions conditions, Map map, WarningSet set) { double c1 = 1.0, c2 = 1.0; @@ -249,8 +300,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { double Re; double Cf; - if (calcMap == null) - buildCalcMap(configuration); + checkCalcMap(configuration); Re = conditions.getVelocity() * configuration.getLength() / conditions.getAtmosphericConditions().getKinematicViscosity(); @@ -301,7 +351,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { Cf *= c2; } - + } else { // Assume fully turbulent. Roughness-limitation is checked later. @@ -344,8 +394,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { roughnessCorrection = c2 * (mach - 0.9) / 0.2 + c1 * (1.1 - mach) / 0.2; } - - + + /* * Calculate the friction drag coefficient. * @@ -353,7 +403,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { * fineness ratio (calculated in the same iteration). The fins are corrected * for thickness as we go on. */ - + double finFriction = 0; double bodyFriction = 0; double maxR = 0, len = 0; @@ -371,9 +421,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // Calculate the roughness-limited friction coefficient Finish finish = ((ExternalComponent) c).getFinish(); if (Double.isNaN(roughnessLimited[finish.ordinal()])) { - roughnessLimited[finish.ordinal()] = - 0.032 * Math.pow(finish.getRoughnessSize() / configuration.getLength(), 0.2) * - roughnessCorrection; + roughnessLimited[finish.ordinal()] = 0.032 * Math.pow(finish.getRoughnessSize() / configuration.getLength(), 0.2) * + roughnessCorrection; } /* @@ -397,8 +446,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } - - + + // Calculate the friction drag: if (c instanceof SymmetricComponent) { @@ -448,16 +497,32 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return (finFriction + correction * bodyFriction) / conditions.getRefArea(); } + /** + * method to avoid repetition, create the calcMap if null + * @param configuration the rocket configuration + */ + private void checkCalcMap(Configuration configuration) { + if (calcMap == null) + buildCalcMap(configuration); + } - + //TODO: LOW: clarify what map is doing here, or use it + /** + * Calculation of drag coefficient due to pressure + * + * @param configuration Rocket configuration + * @param conditions Flight conditions taken into account + * @param map ? + * @param set Set to handle + * @return + */ private double calculatePressureDrag(Configuration configuration, FlightConditions conditions, Map map, WarningSet warnings) { double stagnation, base, total; double radius = 0; - if (calcMap == null) - buildCalcMap(configuration); + checkCalcMap(configuration); stagnation = calculateStagnationCD(conditions.getMach()); base = calculateBaseCD(conditions.getMach()); @@ -476,7 +541,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { map.get(c).setPressureCD(cd); } - + // Stagnation drag if (c instanceof SymmetricComponent) { SymmetricComponent s = (SymmetricComponent) c; @@ -497,7 +562,16 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return total; } - + //TODO: LOW: clarify what map is doing here, or use it + /** + * Calculation of drag coefficient due to base + * + * @param configuration Rocket configuration + * @param conditions Flight conditions taken into account + * @param map ? + * @param set Set to handle + * @return + */ private double calculateBaseDrag(Configuration configuration, FlightConditions conditions, Map map, WarningSet warnings) { @@ -505,8 +579,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { double radius = 0; RocketComponent prevComponent = null; - if (calcMap == null) - buildCalcMap(configuration); + checkCalcMap(configuration); base = calculateBaseCD(conditions.getMach()); total = 0; @@ -543,7 +616,11 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } - + /** + * gets CD by the speed + * @param m Mach number for calculation + * @return Stagnation CD + */ public static double calculateStagnationCD(double m) { double pressure; if (m <= 1) { @@ -554,7 +631,11 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return 0.85 * pressure; } - + /** + * Calculates base CD + * @param m Mach number for calculation + * @return Base CD + */ public static double calculateBaseCD(double m) { if (m <= 1) { return 0.12 + 0.13 * m * m; @@ -564,21 +645,19 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } - + private static final double[] axialDragPoly1, axialDragPoly2; static { PolyInterpolator interpolator; interpolator = new PolyInterpolator( new double[] { 0, 17 * Math.PI / 180 }, - new double[] { 0, 17 * Math.PI / 180 } - ); + new double[] { 0, 17 * Math.PI / 180 }); axialDragPoly1 = interpolator.interpolator(1, 1.3, 0, 0); interpolator = new PolyInterpolator( new double[] { 17 * Math.PI / 180, Math.PI / 2 }, new double[] { 17 * Math.PI / 180, Math.PI / 2 }, - new double[] { Math.PI / 2 } - ); + new double[] { Math.PI / 2 }); axialDragPoly2 = interpolator.interpolator(1.3, 0, 0, 0, 0); } @@ -597,7 +676,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // double sinaoa = conditions.getSinAOA(); // return cd * (1 + Math.min(sinaoa, 0.25)); - + if (aoa > Math.PI / 2) aoa = Math.PI - aoa; if (aoa < 17 * Math.PI / 180) @@ -611,7 +690,12 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return -mul * cd; } - + /** + * get damping moments from a rocket in a flight + * @param configuration Rocket configuration + * @param conditions flight conditions in consideration + * @param total acting aerodynamic forces + */ private void calculateDampingMoments(Configuration configuration, FlightConditions conditions, AerodynamicForces total) { @@ -632,7 +716,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { // TODO: MEDIUM: Are the rotation etc. being added correctly? sin/cos theta? - + private double getDampingMultiplier(Configuration configuration, FlightConditions conditions, double cgx) { if (cacheDiameter < 0) { @@ -664,9 +748,10 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { FinSet f = (FinSet) c; mul += 0.6 * Math.min(f.getFinCount(), 4) * f.getFinArea() * MathUtil.pow3(Math.abs(f.toAbsolute(new Coordinate( - ((FinSetCalc) calcMap.get(f)).getMidchordPos()))[0].x - - cgx)) / - (conditions.getRefArea() * conditions.getRefLength()); + ((FinSetCalc) calcMap.get(f)).getMidchordPos()))[0].x + - cgx)) + / + (conditions.getRefArea() * conditions.getRefLength()); } } @@ -674,9 +759,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { } - - //////// The calculator map + //////// The calculator map @Override protected void voidAerodynamicCache() { super.voidAerodynamicCache(); @@ -686,7 +770,10 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { cacheLength = -1; } - + /** + * caches the map for aerodynamics calculations + * @param configuration the rocket configuration + */ private void buildCalcMap(Configuration configuration) { Iterator iterator; @@ -711,5 +798,5 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { return 0; } - + } diff --git a/core/src/net/sf/openrocket/aerodynamics/FlightConditions.java b/core/src/net/sf/openrocket/aerodynamics/FlightConditions.java index 7d6a3e470..7fb59e253 100644 --- a/core/src/net/sf/openrocket/aerodynamics/FlightConditions.java +++ b/core/src/net/sf/openrocket/aerodynamics/FlightConditions.java @@ -63,9 +63,12 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** Current roll rate. */ private double rollRate = 0; + /** Current pitch rate. */ private double pitchRate = 0; + /** Current yaw rate. */ private double yawRate = 0; + private Coordinate pitchCenter = Coordinate.NUL; @@ -102,6 +105,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Set the reference length and area. + * fires change event */ public void setRefLength(double length) { refLength = length; @@ -111,7 +115,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { } /** - * Return the reference length. + * @return the reference length. */ public double getRefLength() { return refLength; @@ -119,6 +123,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Set the reference area and length. + * fires change event */ public void setRefArea(double area) { refArea = area; @@ -127,7 +132,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { } /** - * Return the reference area. + * @return the reference area. */ public double getRefArea() { return refArea; @@ -137,7 +142,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Sets the angle of attack. It calculates values also for the methods * {@link #getSinAOA()} and {@link #getSincAOA()}. - * + * fires change event if it's different from previous value * @param aoa the angle of attack. */ public void setAOA(double aoa) { @@ -162,6 +167,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { * to be the sine of aoa for cases in which this value is known. * The AOA must still be specified, as the sine is not unique in the range * of 0..180 degrees. + * fires change event if it's different from previous value * * @param aoa the angle of attack in radians. * @param sinAOA the sine of the angle of attack. @@ -186,21 +192,21 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** - * Return the angle of attack. + * @return the angle of attack. */ public double getAOA() { return aoa; } /** - * Return the sine of the angle of attack. + * @return the sine of the angle of attack. */ public double getSinAOA() { return sinAOA; } /** - * Return the sinc of the angle of attack (sin(AOA) / AOA). This method returns + * @return the sinc of the angle of attack (sin(AOA) / AOA). This method returns * one if the angle of attack is zero. */ public double getSincAOA() { @@ -210,6 +216,8 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Set the direction of the lateral airflow. + * fires change event if it's different from previous value + * */ public void setTheta(double theta) { if (MathUtil.equals(this.theta, theta)) @@ -219,7 +227,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { } /** - * Return the direction of the lateral airflow. + * @return the direction of the lateral airflow. */ public double getTheta() { return theta; @@ -229,6 +237,8 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Set the current Mach speed. This should be (but is not required to be) in * reference to the speed of sound of the atmospheric conditions. + * + * fires change event if it's different from previous value */ public void setMach(double mach) { mach = Math.max(mach, 0); @@ -244,7 +254,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { } /** - * Return the current Mach speed. + * @return the current Mach speed. */ public double getMach() { return mach; @@ -272,7 +282,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** - * Return sqrt(abs(1 - Mach^2)). This is calculated in the setting call and is + * @return sqrt(abs(1 - Mach^2)). This is calculated in the setting call and is * therefore fast. */ public double getBeta() { @@ -281,7 +291,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** - * Return the current roll rate. + * @return the current roll rate. */ public double getRollRate() { return rollRate; @@ -290,6 +300,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** * Set the current roll rate. + * fires change event if it's different from previous */ public void setRollRate(double rate) { if (MathUtil.equals(this.rollRate, rate)) @@ -300,11 +311,19 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { } + /** + * + * @return current pitch rate + */ public double getPitchRate() { return pitchRate; } - + /** + * sets the pitch rate + * fires change event if it's different from previous + * @param pitchRate + */ public void setPitchRate(double pitchRate) { if (MathUtil.equals(this.pitchRate, pitchRate)) return; @@ -312,7 +331,10 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { fireChangeEvent(); } - + /** + * + * @return current yaw rate + */ public double getYawRate() { return yawRate; } @@ -402,7 +424,7 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { /** - * Return a copy of the flight conditions. The copy has no listeners. The + * @return a copy of the flight conditions. The copy has no listeners. The * atmospheric conditions is also cloned. */ @Override @@ -454,6 +476,9 @@ public class FlightConditions implements Cloneable, ChangeSource, Monitorable { listenerList.remove(listener); } + /** + * wake up call to listeners + */ protected void fireChangeEvent() { modID = UniqueID.next(); // Copy the list before iterating to prevent concurrent modification exceptions. diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index 08e7c57de..e22f8c1e1 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -7,10 +7,11 @@ import net.sf.openrocket.unit.UnitGroup; public abstract class Warning { + /** support to multiple languages warning */ private static final Translator trans = Application.getTranslator(); /** - * Return a Warning with the specific text. + * @return a Warning with the specific text. */ public static Warning fromString(String text) { return new Warning.Other(text); @@ -321,43 +322,33 @@ public abstract class Warning { /** A Warning that the body diameter is discontinuous. */ ////Discontinuity in rocket body diameter. - public static final Warning DISCONTINUITY = - new Other(trans.get("Warning.DISCONTINUITY")); + public static final Warning DISCONTINUITY = new Other(trans.get("Warning.DISCONTINUITY")); /** A Warning that the fins are thick compared to the rocket body. */ ////Thick fins may not be modeled accurately. - public static final Warning THICK_FIN = - new Other(trans.get("Warning.THICK_FIN")); + public static final Warning THICK_FIN = new Other(trans.get("Warning.THICK_FIN")); /** A Warning that the fins have jagged edges. */ ////Jagged-edged fin predictions may be inaccurate. - public static final Warning JAGGED_EDGED_FIN = - new Other(trans.get("Warning.JAGGED_EDGED_FIN")); + public static final Warning JAGGED_EDGED_FIN = new Other(trans.get("Warning.JAGGED_EDGED_FIN")); /** A Warning that simulation listeners have affected the simulation */ ////Listeners modified the flight simulation - public static final Warning LISTENERS_AFFECTED = - new Other(trans.get("Warning.LISTENERS_AFFECTED")); + public static final Warning LISTENERS_AFFECTED = new Other(trans.get("Warning.LISTENERS_AFFECTED")); ////Recovery device opened while motor still burning. - public static final Warning RECOVERY_DEPLOYMENT_WHILE_BURNING = - new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING")); + public static final Warning RECOVERY_DEPLOYMENT_WHILE_BURNING = new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING")); //// Invalid parameter encountered, ignoring. - public static final Warning FILE_INVALID_PARAMETER = - new Other(trans.get("Warning.FILE_INVALID_PARAMETER")); + public static final Warning FILE_INVALID_PARAMETER = new Other(trans.get("Warning.FILE_INVALID_PARAMETER")); - public static final Warning PARALLEL_FINS = - new Other(trans.get("Warning.PARALLEL_FINS")); + public static final Warning PARALLEL_FINS = new Other(trans.get("Warning.PARALLEL_FINS")); - public static final Warning SUPERSONIC = - new Other(trans.get("Warning.SUPERSONIC")); + public static final Warning SUPERSONIC = new Other(trans.get("Warning.SUPERSONIC")); - public static final Warning RECOVERY_LAUNCH_ROD = - new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); + public static final Warning RECOVERY_LAUNCH_ROD = new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); - public static final Warning TUMBLE_UNDER_THRUST = - new Other(trans.get("Warning.TUMBLE_UNDER_THRUST")); + public static final Warning TUMBLE_UNDER_THRUST = new Other(trans.get("Warning.TUMBLE_UNDER_THRUST")); } diff --git a/core/src/net/sf/openrocket/util/AbstractChangeSource.java b/core/src/net/sf/openrocket/util/AbstractChangeSource.java index 5d5e0e289..e13722e65 100644 --- a/core/src/net/sf/openrocket/util/AbstractChangeSource.java +++ b/core/src/net/sf/openrocket/util/AbstractChangeSource.java @@ -31,6 +31,9 @@ public class AbstractChangeSource implements ChangeSource { log.trace("Removing change listeners, listener count is now " + listeners.size()); } + /** + * execute a change event from any listeners that are triggered by it + */ public void fireChangeEvent(Object source) { EventObject event = new EventObject(source); // Copy the list before iterating to prevent concurrent modification exceptions. From ecb467db3653a35b4c28c47415de00bccf1b33c7 Mon Sep 17 00:00:00 2001 From: Luiz Victor Linhares Rocha Date: Thu, 13 Oct 2016 15:42:08 -0300 Subject: [PATCH 2/5] fixes little bug found at github build and adds a little more docs --- .../aerodynamics/BarrowmanCalculator.java | 2 +- .../openrocket/aerodynamics/WarningSet.java | 1 + .../aerodynamics/barrowman/FinSetCalc.java | 43 ++++++++++--------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index 17fb25a6b..40ccee30e 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -261,7 +261,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { f.setCroll(forces.getCroll()); f.setCrollDamp(forces.getCrollDamp()); f.setCrollForce(forces.getCrollForce()); - map.replace(component, f); //have you forgotten to add this? + map.put(component, f); } total.setCP(total.getCP().average(forces.getCP())); diff --git a/core/src/net/sf/openrocket/aerodynamics/WarningSet.java b/core/src/net/sf/openrocket/aerodynamics/WarningSet.java index c4e81c628..4873976f3 100644 --- a/core/src/net/sf/openrocket/aerodynamics/WarningSet.java +++ b/core/src/net/sf/openrocket/aerodynamics/WarningSet.java @@ -20,6 +20,7 @@ import net.sf.openrocket.util.Mutable; */ public class WarningSet extends AbstractSet implements Cloneable, Monitorable { + /** the actual array of warnings*/ private ArrayList warnings = new ArrayList(); private Mutable mutable = new Mutable(); diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java index dab8098b0..5c8c12190 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java @@ -5,6 +5,9 @@ import static net.sf.openrocket.util.MathUtil.pow2; import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import net.sf.openrocket.aerodynamics.AerodynamicForces; import net.sf.openrocket.aerodynamics.FlightConditions; import net.sf.openrocket.aerodynamics.Warning; @@ -17,14 +20,13 @@ import net.sf.openrocket.util.LinearInterpolator; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class FinSetCalc extends RocketComponentCalc { + /** logger for debugging*/ private final static Logger logger = LoggerFactory.getLogger(FinSetCalc.class); + /** considers the stall angle as 20º*/ private static final double STALL_ANGLE = (20 * Math.PI / 180); /** Number of divisions in the fin chords. */ @@ -57,25 +59,27 @@ public class FinSetCalc extends RocketComponentCalc { private final double cantAngle; private final FinSet.CrossSection crossSection; - public FinSetCalc(RocketComponent component) { + /** + * builds a calculator of aerodynamic forces a specified fin + * @param component The fin in consideration + */ + ///why is this accepting RocketComponent when it rejects? + ///why not put FinSet in the parameter instead? + public FinSetCalc(FinSet component) { super(component); - if (!(component instanceof FinSet)) { - throw new IllegalArgumentException("Illegal component type " + component); - } - FinSet fin = (FinSet) component; - thickness = fin.getThickness(); - bodyRadius = fin.getBodyRadius(); - finCount = fin.getFinCount(); - baseRotation = fin.getBaseRotation(); - cantAngle = fin.getCantAngle(); - span = fin.getSpan(); - finArea = fin.getFinArea(); - crossSection = fin.getCrossSection(); + thickness = component.getThickness(); + bodyRadius = component.getBodyRadius(); + finCount = component.getFinCount(); + baseRotation = component.getBaseRotation(); + cantAngle = component.getCantAngle(); + span = component.getSpan(); + finArea = component.getFinArea(); + crossSection = component.getCrossSection(); - calculateFinGeometry(fin); + calculateFinGeometry(component); calculatePoly(); - calculateInterferenceFinCount(fin); + calculateInterferenceFinCount(component); } /* @@ -439,8 +443,7 @@ public class FinSetCalc extends RocketComponentCalc { private static final PolyInterpolator cnaInterpolator = new PolyInterpolator( new double[] { CNA_SUBSONIC, CNA_SUPERSONIC }, new double[] { CNA_SUBSONIC, CNA_SUPERSONIC }, - new double[] { CNA_SUBSONIC } - ); + new double[] { CNA_SUBSONIC }); /* Pre-calculate the values for K1, K2 and K3 */ static { // Up to Mach 5 From 38f21e1b05ad2a49070ee2e3525564be966fc688 Mon Sep 17 00:00:00 2001 From: Luiz Victor Linhares Rocha Date: Thu, 13 Oct 2016 15:47:53 -0300 Subject: [PATCH 3/5] fixes build bug by non ASCII character --- .../net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java index 5c8c12190..8b968deff 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java @@ -26,7 +26,7 @@ public class FinSetCalc extends RocketComponentCalc { /** logger for debugging*/ private final static Logger logger = LoggerFactory.getLogger(FinSetCalc.class); - /** considers the stall angle as 20º*/ + /** considers the stall angle as 20 degrees*/ private static final double STALL_ANGLE = (20 * Math.PI / 180); /** Number of divisions in the fin chords. */ From 466619d2963e44ba25bfcdd7521e8ae1482ffd8e Mon Sep 17 00:00:00 2001 From: Vicilu Date: Fri, 14 Oct 2016 11:00:11 -0300 Subject: [PATCH 4/5] Adds documentation to appearance file --- .../sf/openrocket/appearance/Appearance.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/src/net/sf/openrocket/appearance/Appearance.java b/core/src/net/sf/openrocket/appearance/Appearance.java index 385256bb6..6d02c0b22 100644 --- a/core/src/net/sf/openrocket/appearance/Appearance.java +++ b/core/src/net/sf/openrocket/appearance/Appearance.java @@ -16,26 +16,48 @@ public class Appearance { private final double shine; private final Decal texture; + /** + * Main constructor + * + * @param paint the color to be used + * @param shine shine of the appearance, will be clamped between 0 and 1 + * @param texture The appearance texture + */ public Appearance(final Color paint, final double shine, final Decal texture) { this.paint = paint; this.shine = MathUtil.clamp(shine, 0, 1); this.texture = texture; } + /** + * Main constructor + * + * @param paint the color to be used + * @param shine shine of the appearance, will be clamped between 0 and 1 + */ public Appearance(final Color paint, final double shine) { this.paint = paint; this.shine = MathUtil.clamp(shine, 0, 1); this.texture = null; } + /** + * @return colr of the appearance + */ public Color getPaint() { return paint; } + /** + * @return Shine of appearance + */ public double getShine() { return shine; } + /** + * @return Texture used in appearance + */ public Decal getTexture() { return texture; } From 7c5de3f4da7ae756faf9a9a42fad61babecf0120 Mon Sep 17 00:00:00 2001 From: Vicilu Date: Fri, 14 Oct 2016 11:50:58 -0300 Subject: [PATCH 5/5] adds documentation for appearance builder --- .../appearance/AppearanceBuilder.java | 246 ++++++++++++++++-- 1 file changed, 226 insertions(+), 20 deletions(-) diff --git a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java index e65dfdd84..f7becf700 100644 --- a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java +++ b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java @@ -18,25 +18,38 @@ import net.sf.openrocket.util.Coordinate; */ public class AppearanceBuilder extends AbstractChangeSource { - private Color paint; - private double shine; - private double offsetU, offsetV; - private double centerU, centerV; - private double scaleU, scaleV; - private double rotation; + private Color paint; //current cached color + private double shine; //current cached shine + private double offsetU, offsetV;//current offset to be used + private double centerU, centerV;//current values for the center of the appearance + private double scaleU, scaleV; //current values for scaling + private double rotation; // private DecalImage image; private Decal.EdgeMode edgeMode; private boolean batch; + /** + * Default constructor + * Set the builder to make appearance of null values + * + */ public AppearanceBuilder() { resetToDefaults(); } + /** + * Constructor that initializes already with a + * + * @param a the appearance to be copied + */ public AppearanceBuilder(Appearance a) { setAppearance(a); } + /** + * Clears the builder cache and set to build blank appearances + */ private void resetToDefaults() { paint = new Color(0, 0, 0); shine = 0; @@ -46,8 +59,15 @@ public class AppearanceBuilder extends AbstractChangeSource { rotation = 0; image = null; edgeMode = EdgeMode.REPEAT; + fireChangeEvent();//shouldn't this fire change event? } + /** + * Sets the builder to create appearance equals to an existing appearance + * Fires change only once, hence the call to batch + * + * @param a the appearance to be used as the new template + */ public void setAppearance(final Appearance a) { batch(new Runnable() { @Override @@ -56,20 +76,33 @@ public class AppearanceBuilder extends AbstractChangeSource { if (a != null) { setPaint(a.getPaint()); setShine(a.getShine()); - Decal d = a.getTexture(); - if (d != null) { - setOffset(d.getOffset().x, d.getOffset().y); - setCenter(d.getCenter().x, d.getCenter().y); - setScaleUV(d.getScale().x, d.getScale().y); - setRotation(d.getRotation()); - setEdgeMode(d.getEdgeMode()); - setImage(d.getImage()); - } + setDecal(a.getTexture()); } } }); } + /** + * makes a full copy of a decal, including information of offsets, center and scale + * + * @param d The decal + */ + public void setDecal(Decal d){ + if (d != null) { + setOffset(d.getOffset().x, d.getOffset().y); + setCenter(d.getCenter().x, d.getCenter().y); + setScaleUV(d.getScale().x, d.getScale().y); + setRotation(d.getRotation()); + setEdgeMode(d.getEdgeMode()); + setImage(d.getImage()); + } + fireChangeEvent(); + } + + /** + * Method creates another object of Appearance + * @return the created appearance + */ public Appearance getAppearance() { Decal t = null; @@ -88,143 +121,316 @@ public class AppearanceBuilder extends AbstractChangeSource { } - + /** + * get current paint in template + * + * return the color used in the current paint + */ public Color getPaint() { return paint; } + /** + * sets a new paint color to be used + * fires change event + * + * @param paint the new color + */ public void setPaint(Color paint) { this.paint = paint; fireChangeEvent(); + } + /** + * gets the current shine + * + * @return current shine in template + */ public double getShine() { return shine; } + /** + * Sets a new shine for template + * fires change event + * + * @param shine the new shine for template + */ public void setShine(double shine) { this.shine = shine; fireChangeEvent(); } + /** + * gets the current offset axis U used + * + * @return offset in axis U + */ public double getOffsetU() { return offsetU; } + + /** + * sets a new offset in axis U for template + * fires change event + * + * @param offsetU the new offset to be used + */ public void setOffsetU(double offsetU) { this.offsetU = offsetU; fireChangeEvent(); } + /** + * gets the current offset axis V used + * + * @return offset in axis V + */ public double getOffsetV() { return offsetV; } + /** + * sets a new offset in axis V for template + * fires change event + * + * @param offsetV the new offset to be used + */ public void setOffsetV(double offsetV) { this.offsetV = offsetV; fireChangeEvent(); } + /** + * sets a new offset to be used for template + * fires change event + * + * @param u offset in axis u + * @param v offset in axis v + */ public void setOffset(double u, double v) { setOffsetU(u); setOffsetV(v); } + /** + * gets the current center in axis U used in template + * + * @return the current value of U of cente in template + */ public double getCenterU() { return centerU; } + /** + * set a new value for axis U for center in template + * fires change event + * + * @param centerU value of axis U for center + */ public void setCenterU(double centerU) { this.centerU = centerU; fireChangeEvent(); } + /** + * gets the current center in axis V used in template + * + * @return the current value of V of cente in template + */ public double getCenterV() { return centerV; } + /** + * set a new value for axis V for center in template + * fires change event + * + * @param centerU value of axis V for center + */ public void setCenterV(double centerV) { this.centerV = centerV; fireChangeEvent(); } + /** + * sets a new center for template + * fires chenge event + * + * @param u new value for axis u of the center + * @param v new value for axis v of the center + */ public void setCenter(double u, double v) { setCenterU(u); setCenterV(v); } + /** + * gets the current scale value of axis u in template + * + * @return current value for axis u of scale + */ public double getScaleU() { return scaleU; } + /** + * sets a new value of axis U for scaling in the template + * fires change event + * + * @param scaleU new value of scalling in axis U + */ public void setScaleU(double scaleU) { this.scaleU = scaleU; fireChangeEvent(); } + /** + * gets the current scale value of axis V in template + * + * @return current value for axis V of scale + */ public double getScaleV() { return scaleV; } + /** + * sets a new value of axis V for scaling in the template + * fires change event + * + * @param scaleV new value of scalling in axis V + */ public void setScaleV(double scaleV) { this.scaleV = scaleV; fireChangeEvent(); } + /** + * sets a new value of both axis for scaling in the template + * fires change event + * + * @param u new value of scalling in axis U + * @param v new value of scalling in axis v + */ public void setScaleUV(double u, double v) { setScaleU(u); setScaleV(v); } + /** + * gets the current value of X axis for scalling in the template + * + * @return value of scalling in axis x + */ public double getScaleX() { return 1.0 / getScaleU(); } - public void setScaleX(double scaleU) { - setScaleU(1.0 / scaleU); + /** + * sets a new value of axis X for scalling in template + * fires change event + * + * @param scaleX the new value for axis X + */ + public void setScaleX(double scaleX) { + setScaleU(1.0 / scaleX); } + /** + * gets the current value of Y axis for scalling in the template + * + * @return value of scalling in axis Y + */ public double getScaleY() { return 1.0 / getScaleV(); } - public void setScaleY(double scaleV) { - setScaleV(1.0 / scaleV); + /** + * sets a new value of axis Y for scalling in template + * fires change event + * + * @param scaleX the new value for axis Y + */ + public void setScaleY(double scaleY) { + setScaleV(1.0 / scaleY); } + /** + * gets the current value of rotation in template + * + * @return the current rotation in template + */ public double getRotation() { return rotation; } + /** + * sets a new value of rotation in template + * fires chenge event + * + * @param rotation the new value for rotation in template + */ public void setRotation(double rotation) { this.rotation = rotation; fireChangeEvent(); } + /** + * gets the current image in template + * + * @param the current image in template + */ public DecalImage getImage() { return image; } + /** + * sets a new image in template + * fires change event + * + * @param image the new image to be used as template + */ public void setImage(DecalImage image) { this.image = image; fireChangeEvent(); } + /** + * gets the current Edge mode in use + * + * @return the current edge mode in template + */ public Decal.EdgeMode getEdgeMode() { return edgeMode; } + /** + * sets a new edge mode to be used in template + * fires change event + * + * @param edgeMode the new edgeMode to be used + */ public void setEdgeMode(Decal.EdgeMode edgeMode) { this.edgeMode = edgeMode; fireChangeEvent(); } + /** + * only applies change if there is no more changes comming + */ @Override protected void fireChangeEvent() { if (!batch) super.fireChangeEvent(); } + /** + * function that garantees that chenges event only occurs after all changes are made + * + * param r the functor to be executed + */ public void batch(Runnable r) { batch = true; r.run();