diff --git a/core/OpenRocket Core.iml b/core/OpenRocket Core.iml index 8a5fd8008..dce24f46b 100644 --- a/core/OpenRocket Core.iml +++ b/core/OpenRocket Core.iml @@ -270,5 +270,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/lib/graal-sdk-22.1.0.1.jar b/core/lib/graal-sdk-22.1.0.1.jar new file mode 100644 index 000000000..a08644e94 Binary files /dev/null and b/core/lib/graal-sdk-22.1.0.1.jar differ diff --git a/core/lib/icu4j-71.1.jar b/core/lib/icu4j-71.1.jar new file mode 100644 index 000000000..7c5cb5064 Binary files /dev/null and b/core/lib/icu4j-71.1.jar differ diff --git a/core/lib/js-22.1.0.1.jar b/core/lib/js-22.1.0.1.jar new file mode 100644 index 000000000..3985e48e9 Binary files /dev/null and b/core/lib/js-22.1.0.1.jar differ diff --git a/core/lib/js-scriptengine-22.1.0.1.jar b/core/lib/js-scriptengine-22.1.0.1.jar new file mode 100644 index 000000000..c9f7332eb Binary files /dev/null and b/core/lib/js-scriptengine-22.1.0.1.jar differ diff --git a/core/lib/truffle-api-22.1.0.1.jar b/core/lib/truffle-api-22.1.0.1.jar new file mode 100644 index 000000000..4f35bd7c7 Binary files /dev/null and b/core/lib/truffle-api-22.1.0.1.jar differ diff --git a/core/lib/yasson-1.0.2.jar b/core/lib/yasson-1.0.2.jar new file mode 100644 index 000000000..ed935f3aa Binary files /dev/null and b/core/lib/yasson-1.0.2.jar differ diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index 93ed781b3..79dc0c4a3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -227,8 +227,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona if (MathUtil.equals(clampedCant, this.cantRadians)) return; this.cantRadians = clampedCant; - - fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + + fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE); } public Transformation getCantRotation() { diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 7bb3cfae3..d8f21cbc9 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +63,7 @@ public class FlightConfiguration implements FlightConfigurableParameter stages = new HashMap(); // Map of stage number to StageFlags of the corresponding stage final protected Map motors = new HashMap(); - final private Collection activeMotors = new ArrayList(); + final private Collection activeMotors = new ConcurrentLinkedQueue(); final private InstanceMap activeInstances = new InstanceMap(); private int boundsModID = -1; @@ -225,8 +226,7 @@ public class FlightConfiguration implements FlightConfigurableParameter * */ -public class InstanceMap extends HashMap> { +public class InstanceMap extends ConcurrentHashMap> { // =========== Public Functions ======================== diff --git a/core/src/net/sf/openrocket/rocketcomponent/Rocket.java b/core/src/net/sf/openrocket/rocketcomponent/Rocket.java index 37d245772..0b85db63d 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Rocket.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Rocket.java @@ -514,9 +514,9 @@ public class Rocket extends ComponentAssembly { // Notify all components first Iterator iterator = this.iterator(true); while (iterator.hasNext()) { - iterator.next().componentChanged(cce); + RocketComponent next = iterator.next(); + next.componentChanged(cce); } - updateConfigurations(); notifyAllListeners(cce); @@ -556,7 +556,6 @@ public class Rocket extends ComponentAssembly { } private void updateConfigurations(){ - this.selectedConfiguration.update(); for( FlightConfiguration config : configSet ){ config.update(); } diff --git a/core/src/net/sf/openrocket/scripting/GraalJSScriptEngineFactory.java b/core/src/net/sf/openrocket/scripting/GraalJSScriptEngineFactory.java new file mode 100644 index 000000000..0b71e8501 --- /dev/null +++ b/core/src/net/sf/openrocket/scripting/GraalJSScriptEngineFactory.java @@ -0,0 +1,101 @@ +package net.sf.openrocket.scripting; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import java.util.*; + +import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.HostAccess; + +public class GraalJSScriptEngineFactory implements ScriptEngineFactory { + private static final String ENGINE_NAME = "Graal.js"; + private static final String LANGUAGE = "ECMAScript"; + private static final String LANGUAGE_VERSION = "ECMAScript 262 Edition 11"; + private static final String[] NAMES = new String[]{"js", "JS", "JavaScript", "javascript", LANGUAGE, LANGUAGE.toLowerCase(), ENGINE_NAME, ENGINE_NAME.toLowerCase(), "Graal-js", "graal-js", "Graal.JS", "Graal-JS", "GraalJS", "GraalJSPolyglot"}; + private static final String[] MIME_TYPES = new String[]{"application/javascript", "application/ecmascript", "text/javascript", "text/ecmascript"}; + private static final String[] EXTENSIONS = new String[]{"js", "mjs"}; + private static final List names; + private static final List mimeTypes; + private static final List extensions; + + public GraalJSScriptEngineFactory() { + } + + public ScriptEngine getScriptEngine() { + // https://github.com/oracle/graaljs/blob/master/docs/user/RunOnJDK.md + // https://github.com/oracle/graaljs/blob/master/docs/user/ScriptEngine.md#setting-options-via-bindings + return GraalJSScriptEngine.create(null, + Context.newBuilder("js") + .allowHostAccess(HostAccess.ALL) + .allowHostClassLookup(s -> true) + .option("js.ecmascript-version", "2021")); + } + + public String getEngineName() { + return ENGINE_NAME; + } + + public String getEngineVersion() { + return ((GraalJSScriptEngine)getScriptEngine()).getPolyglotEngine().getVersion(); + } + + public List getExtensions() { + return extensions; + } + + public String getLanguageVersion() { + return LANGUAGE_VERSION; + } + + public String getLanguageName() { + return LANGUAGE; + } + + public List getMimeTypes() { + return mimeTypes; + } + + public List getNames() { + return names; + } + + public String getMethodCallSyntax(final String obj, final String method, final String... args) { + return null; + } + + public String getOutputStatement(final String toDisplay) { + return "print(" + toDisplay + ")"; + } + + public Object getParameter(String key) { + switch (key) { + case "javax.script.name": + return "javascript"; + case "javax.script.engine": + return this.getEngineName(); + case "javax.script.engine_version": + return this.getEngineVersion(); + case "javax.script.language": + return this.getLanguageName(); + case "javax.script.language_version": + return this.getLanguageVersion(); + default: + return null; + } + } + + public String getProgram(final String... statements) { + return null; + } + + static { + List nameList = Arrays.asList(NAMES); + List mimeTypeList = Arrays.asList(MIME_TYPES); + List extensionList = Arrays.asList(EXTENSIONS); + names = Collections.unmodifiableList(nameList); + mimeTypes = Collections.unmodifiableList(mimeTypeList); + extensions = Collections.unmodifiableList(extensionList); + } +} diff --git a/core/src/net/sf/openrocket/scripting/ScriptEngineManagerRedux.java b/core/src/net/sf/openrocket/scripting/ScriptEngineManagerRedux.java new file mode 100644 index 000000000..42566c8a1 --- /dev/null +++ b/core/src/net/sf/openrocket/scripting/ScriptEngineManagerRedux.java @@ -0,0 +1,300 @@ +/* + * This is a replacement for the ScriptEngineManager which gets around and issue with the sun.misc.ServiceConfigurationError + * which has been removed in Java 9+. If using the ScriptEngineManager from the script-api*.jar then the sun.misc throws + * a ClassNotFoundException. + */ + +/* + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package net.sf.openrocket.scripting; + +import javax.script.*; +import java.util.*; +import java.security.*; +import java.util.ServiceLoader; +import java.util.ServiceConfigurationError; + +/** + * The ScriptEngineManager implements a discovery and instantiation + * mechanism for ScriptEngine classes and also maintains a + * collection of key/value pairs storing state shared by all engines created + * by the Manager. This class uses the service provider mechanism described in the + * {@link java.util.ServiceLoader} class to enumerate all the + * implementations of ScriptEngineFactory.

+ * The ScriptEngineManager provides a method to return a list of all these factories + * as well as utility methods which look up factories on the basis of language name, file extension + * and mime type. + *

+ * The Bindings of key/value pairs, referred to as the "Global Scope" maintained + * by the manager is available to all instances of ScriptEngine created + * by the ScriptEngineManager. The values in the Bindings are + * generally exposed in all scripts. + * + * @author Mike Grogan + * @author A. Sundararajan + * @since 1.6 + */ +public class ScriptEngineManagerRedux { + private static final boolean DEBUG = false; + /** + * The effect of calling this constructor is the same as calling + * ScriptEngineManager(Thread.currentThread().getContextClassLoader()). + * + * @see java.lang.Thread#getContextClassLoader + */ + public ScriptEngineManagerRedux() { + init(Thread.currentThread().getContextClassLoader()); + } + + /** + * This constructor loads the implementations of + * ScriptEngineFactory visible to the given + * ClassLoader using the service provider mechanism.

+ * If loader is null, the script engine factories that are + * bundled with the platform are loaded.
+ * + * @param loader ClassLoader used to discover script engine factories. + */ + public ScriptEngineManagerRedux(ClassLoader loader) { + init(loader); + } + + /** + * Gets the value for the specified key in the Global Scope + * @param key The key whose value is to be returned. + * @return The value for the specified key. + */ + public Object get(String key) { + return _globalScope.get(key); + } + + /** + * getBindings returns the value of the globalScope field. + * ScriptEngineManager sets this Bindings as global bindings for + * ScriptEngine objects created by it. + * + * @return The globalScope field. + */ + public Bindings getBindings() { + return _globalScope; + } + + /** + * Looks up and creates a ScriptEngine for a given name. + * The algorithm first searches for a ScriptEngineFactory that has been + * registered as a handler for the specified name using the registerEngineName + * method. + *

If one is not found, it searches the set of ScriptEngineFactory instances + * stored by the constructor for one with the specified name. If a ScriptEngineFactory + * is found by either method, it is used to create instance of ScriptEngine. + * @param shortName The short name of the ScriptEngine implementation. + * returned by the getNames method of its ScriptEngineFactory. + * @return A ScriptEngine created by the factory located in the search. Returns null + * if no such factory was found. The ScriptEngineManager sets its own globalScope + * Bindings as the GLOBAL_SCOPE Bindings of the newly + * created ScriptEngine. + * @throws NullPointerException if shortName is null. + */ + private Map _factoriesByName = new HashMap<>(); + public synchronized ScriptEngine getEngineByName(String shortName) { + if (shortName == null) { + throw new NullPointerException(); + } + + String key = shortName.toLowerCase(); + if (_factoriesByName.containsKey(key)) { + return getEngineByFactory(_factoriesByName.get(key)); + } + + // Look for registered name first + ScriptEngineFactory factoryNamed; + if (null != (factoryNamed = _nameAssociations.get(key))) { + try { + _factoriesByName.put(key, factoryNamed); + return getEngineByFactory(factoryNamed); + } catch (Exception exp) { + if (DEBUG) { + exp.printStackTrace(); + } + } + } + + Optional factoryName; + List names; + for (ScriptEngineFactory factory : _scriptEngineFactories) { + try { + factoryName = factory.getNames().stream().filter(l -> l.equalsIgnoreCase(shortName)).findFirst(); + if (factoryName.isPresent()) { + _factoriesByName.put(key, factory); + return getEngineByFactory(factory); + } + } catch (Exception exp) { + if (DEBUG) { + exp.printStackTrace(); + } + } + } + + return null; + } + + /** + * Returns a list whose elements are instances of all the ScriptEngineFactory classes + * found by the discovery mechanism. + * @return List of all discovered ScriptEngineFactorys. + */ + public synchronized List getEngineFactories() { + return List.copyOf(_scriptEngineFactories); + } + + /** + * Sets the specified key/value pair in the Global Scope. + * @param key Key to set + * @param value Value to set. + * @throws NullPointerException if key is null. + * @throws IllegalArgumentException if key is empty string. + */ + public void put(String key, Object value) { + _globalScope.put(key, value); + } + + /** + * Registers a ScriptEngineFactory to handle a language + * name. Overrides any such association found using the Discovery mechanism. + * @param name The name to be associated with the ScriptEngineFactory. + * @param factory The class to associate with the given name. + * @throws NullPointerException if any of the parameters is null. + */ + public void registerEngineName(String name, ScriptEngineFactory factory) { + if (name == null || factory == null) { + throw new NullPointerException(); + } + + _nameAssociations.put(name.toLowerCase(), factory); + } + + /** + * setBindings stores the specified Bindings + * in the globalScope field. ScriptEngineManager sets this + * Bindings as global bindings for ScriptEngine + * objects created by it. + * + * @param bindings The specified Bindings + * @throws IllegalArgumentException if bindings is null. + */ + public void setBindings(Bindings bindings) { + if (bindings == null) { + throw new IllegalArgumentException("Global scope cannot be null."); + } + + _globalScope = bindings; + } + + private ScriptEngine getEngineByFactory(ScriptEngineFactory factory) { + if (factory == null) { + return null; + } + + ScriptEngine engine = factory.getScriptEngine(); + engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE); + return engine; + } + + private ServiceLoader getServiceLoader(final ClassLoader loader) { + if (loader != null) { + return ServiceLoader.load(ScriptEngineFactory.class, loader); + } else { + return ServiceLoader.loadInstalled(ScriptEngineFactory.class); + } + } + + private void init(final ClassLoader loader) { + _scriptEngineFactories = new TreeSet<>(Comparator.comparing( + ScriptEngineFactory::getEngineName, + Comparator.nullsLast(Comparator.naturalOrder())) + ); + initEngines(loader); + } + + private void initEngines(final ClassLoader loader) { + Iterator itr; + try { + ServiceLoader loaders = AccessController.doPrivileged( + new PrivilegedAction>() { + @Override + public ServiceLoader run() { + return getServiceLoader(loader); + } + }); + + itr = loaders.iterator(); + } catch (ServiceConfigurationError err) { + // } catch (Exception err) { + System.err.println("Can't find ScriptEngineFactory providers: " + err.getMessage()); + if (DEBUG) { + err.printStackTrace(); + } + // do not throw any exception here. user may want to + // manage his/her own factories using this manager + // by explicit registration (by registerXXX) methods. + return; + } + + try { + while (itr.hasNext()) { + try { + ScriptEngineFactory factory = itr.next(); + _scriptEngineFactories.add(factory); + } catch (ServiceConfigurationError err) { + // } catch (Exception err) { + System.err.println("ScriptEngineManager providers.next(): " + err.getMessage()); + if (DEBUG) { + err.printStackTrace(); + } + // one factory failed, but check other factories... + } + } + } catch (ServiceConfigurationError err) { + // } catch (Exception err) { + System.err.println("ScriptEngineManager providers.hasNext(): " + err.getMessage()); + if (DEBUG) { + err.printStackTrace(); + } + // do not throw any exception here. user may want to + // manage his/her own factories using this manager + // by explicit registratation (by registerXXX) methods. + } + } + + /** Set of script engine factories discovered. */ + private TreeSet _scriptEngineFactories; + + /** Map of engine name to script engine factory. */ + private HashMap _nameAssociations = new HashMap<>(); + + /** Global bindings associated with script engines created by this manager. */ + private Bindings _globalScope = new SimpleBindings(); +} diff --git a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java index 3569d2aae..953543442 100644 --- a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java +++ b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java @@ -2,7 +2,6 @@ package net.sf.openrocket.simulation.extension.impl; import javax.script.Invocable; import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; import javax.script.ScriptException; import net.sf.openrocket.aerodynamics.Warning; @@ -91,8 +90,7 @@ public class ScriptingExtension extends AbstractSimulationExtension { SimulationListener getListener() throws SimulationException { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName(getLanguage()); + ScriptEngine engine = util.getEngineByName(getLanguage()); if (engine == null) { throw new SimulationException("Your JRE does not support the scripting language '" + getLanguage() + "'"); } diff --git a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingUtil.java b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingUtil.java index 7259a9787..ef215ae3e 100644 --- a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingUtil.java +++ b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingUtil.java @@ -4,14 +4,14 @@ import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import java.util.List; import java.util.prefs.BackingStoreException; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; -import javax.script.ScriptEngineManager; +import net.sf.openrocket.scripting.ScriptEngineManagerRedux; +import net.sf.openrocket.scripting.GraalJSScriptEngineFactory; import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.BugException; @@ -22,22 +22,34 @@ import com.google.inject.Inject; * Utility class used by the scripting extension and its configurator. */ public class ScriptingUtil { - static final String NODE_ID = ScriptingExtension.class.getCanonicalName(); - private static final List DEFAULT_TRUSTED_HASHES = Arrays.asList( + private static final List DEFAULT_TRUSTED_HASHES = List.of( // Roll control script in roll control example file: "SHA-256:9bf364ce4d4a75f09b29178bf9d6872b232084f73dae20dc7b5b073e54e95a42" - ); + ); /** The name to be chosen from a list of alternatives. If not found, will use the default name. */ - private static final List PREFERRED_LANGUAGE_NAMES = Arrays.asList("JavaScript"); + private static final List PREFERRED_LANGUAGE_NAMES = List.of("JavaScript"); + + private static ScriptEngineManagerRedux manager; @Inject Preferences prefs; - - - + + public ScriptingUtil() { + if (manager == null) { + // using the ScriptEngineManger from javax.script package pulls in the sun.misc.ServiceConfigurationError + // which is removed in Java 9+ which causes a ClassNotFoundException to be thrown. + manager = new ScriptEngineManagerRedux(); + + manager.registerEngineName("Javascript", new GraalJSScriptEngineFactory()); + } + } + + public ScriptEngine getEngineByName(String shortName) { + return manager.getEngineByName(shortName); + } /** * Return the preferred internal language name based on a script language name. @@ -48,38 +60,23 @@ public class ScriptingUtil { if (language == null) { return null; } - - ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName(language); if (engine == null) { return null; } - return getLanguage(engine.getFactory()); + + return getLanguageByFactory(engine.getFactory()); } - - + public List getLanguages() { - List langs = new ArrayList(); - ScriptEngineManager manager = new ScriptEngineManager(); + List languages = new ArrayList<>(); for (ScriptEngineFactory factory : manager.getEngineFactories()) { - langs.add(getLanguage(factory)); + languages.add(getLanguageByFactory(factory)); } - return langs; + return languages; } - - private String getLanguage(ScriptEngineFactory factory) { - for (String name : factory.getNames()) { - if (PREFERRED_LANGUAGE_NAMES.contains(name)) { - return name; - } - } - - return factory.getLanguageName(); - } - - - /** * Test whether the user has indicated this script to be trusted, * or if it is an internally trusted script. @@ -122,7 +119,16 @@ public class ScriptingUtil { throw new BugException(e); } } - + + private String getLanguageByFactory(ScriptEngineFactory factory) { + for (String name : factory.getNames()) { + if (PREFERRED_LANGUAGE_NAMES.contains(name)) { + return name; + } + } + + return factory.getLanguageName(); + } static String normalize(String script) { return script.replaceAll("\r", "").trim(); @@ -132,10 +138,8 @@ public class ScriptingUtil { /* * NOTE: Hash length must be max 80 chars, the max length of a key in a Properties object. */ - String output; MessageDigest digest; - try { digest = MessageDigest.getInstance("SHA-256"); digest.update(language.getBytes(StandardCharsets.UTF_8)); @@ -152,5 +156,4 @@ public class ScriptingUtil { return digest.getAlgorithm() + ":" + output; } - } diff --git a/core/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java b/core/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java index 55a557d70..5493c4a0d 100644 --- a/core/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java +++ b/core/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java @@ -35,8 +35,7 @@ public class RollControlListener extends AbstractSimulationListener { // Maximum control fin angle (rad) private static final double MAX_ANGLE = 15 * Math.PI / 180; - - + /* * PID parameters * @@ -47,29 +46,22 @@ public class RollControlListener extends AbstractSimulationListener { private static final double KP = 0.007; private static final double KI = 0.2; - - - - private double rollrate; + private double rollRate; private double prevTime = 0; private double intState = 0; private double finPosition = 0; - - - + @Override public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) { // Store the current roll rate for later use - rollrate = flightConditions.getRollRate(); + rollRate = flightConditions.getRollRate(); return null; } - - + @Override public void postStep(SimulationStatus status) throws SimulationException { - // Activate PID controller only after a specific time if (status.getSimulationTime() < START_TIME) { prevTime = status.getSimulationTime(); @@ -87,23 +79,20 @@ public class RollControlListener extends AbstractSimulationListener { if (finset == null) { throw new SimulationException("A fin set with name '" + CONTROL_FIN_NAME + "' was not found"); } - - + // Determine time step double deltaT = status.getSimulationTime() - prevTime; prevTime = status.getSimulationTime(); - - + // PID controller - double error = SETPOINT - rollrate; + double error = SETPOINT - rollRate; double p = KP * error; intState += error * deltaT; double i = KI * intState; double value = p + i; - - + // Clamp the fin angle between -MAX_ANGLE and MAX_ANGLE if (Math.abs(value) > MAX_ANGLE) { System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n", @@ -111,7 +100,6 @@ public class RollControlListener extends AbstractSimulationListener { value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE); } - // Limit the fin turn rate if (finPosition < value) { finPosition = Math.min(finPosition + TURNRATE * deltaT, value); @@ -122,6 +110,5 @@ public class RollControlListener extends AbstractSimulationListener { // Set the control fin cant and store the data finset.setCantAngle(finPosition); status.getFlightData().setValue(FIN_CANT_TYPE, finPosition); - } } diff --git a/swing/OpenRocket Swing.iml b/swing/OpenRocket Swing.iml index a4dcbfdb1..c9df46ca4 100644 --- a/swing/OpenRocket Swing.iml +++ b/swing/OpenRocket Swing.iml @@ -245,5 +245,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/swing/build.xml b/swing/build.xml index ce705b584..578f0994c 100644 --- a/swing/build.xml +++ b/swing/build.xml @@ -99,6 +99,11 @@ + + + + + diff --git a/swing/resources/datafiles/examples/Simulation extensions and scripting.ork b/swing/resources/datafiles/examples/Simulation extensions and scripting.ork index a1592fc11..e84fc0d9d 100644 Binary files a/swing/resources/datafiles/examples/Simulation extensions and scripting.ork and b/swing/resources/datafiles/examples/Simulation extensions and scripting.ork differ diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index 6e4bf9e4b..0fe7cf400 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -282,38 +282,38 @@ public class RocketFigure extends AbstractScaleFigure { Color borderColor = ((SwingPreferences)Application.getPreferences()).getMotorBorderColor(); FlightConfiguration config = rocket.getSelectedConfiguration(); - for( MotorConfiguration curInstance : config.getActiveMotors()){ + for (MotorConfiguration curInstance : config.getActiveMotors()) { MotorMount mount = curInstance.getMount(); Motor motor = curInstance.getMotor(); double motorLength = motor.getLength(); double motorRadius = motor.getDiameter() / 2; RocketComponent mountComponent = ((RocketComponent) mount); - + // .getLocation() will return all the parent instances of this owning component, AND all of it's own instances as well. // so, just draw a motor once for each Coordinate returned... Coordinate[] mountLocations = mount.getLocations(); - + double mountLength = mountComponent.getLength(); // System.err.println("Drawing Motor: "+motor.getDesignation()+" (x"+mountLocations.length+")"); - for ( Coordinate curMountLocation : mountLocations ){ - Coordinate curMotorLocation = curMountLocation.add( mountLength - motorLength + mount.getMotorOverhang(), 0, 0); + for (Coordinate curMountLocation : mountLocations) { + Coordinate curMotorLocation = curMountLocation.add(mountLength - motorLength + mount.getMotorOverhang(), 0, 0); // System.err.println(String.format(" mount instance: %s => %s", curMountLocation.toString(), curMotorLocation.toString() )); - - // rotate by figure's axial rotation: - curMotorLocation = this.axialRotation.transform(curMotorLocation); + + // rotate by figure's axial rotation: + curMotorLocation = this.axialRotation.transform(curMotorLocation); { Shape s; if (currentViewType == RocketPanel.VIEW_TYPE.SideView) { - s = new Rectangle2D.Double( curMotorLocation.x, - (curMotorLocation.y - motorRadius), - motorLength, - 2 * motorRadius); + s = new Rectangle2D.Double(curMotorLocation.x, + (curMotorLocation.y - motorRadius), + motorLength, + 2 * motorRadius); } else { s = new Ellipse2D.Double((curMotorLocation.z - motorRadius), - (curMotorLocation.y - motorRadius), - 2 * motorRadius, - 2 * motorRadius); + (curMotorLocation.y - motorRadius), + 2 * motorRadius, + 2 * motorRadius); } g2.setColor(fillColor); g2.fill(s); @@ -378,8 +378,8 @@ public class RocketFigure extends AbstractScaleFigure { // allShapes is an output buffer -- it stores all the generated shapes allShapes.clear(); - - for(Entry> entry: config.getActiveInstances().entrySet() ) { + + for (Entry> entry : config.getActiveInstances().entrySet()) { final RocketComponent comp = entry.getKey(); // Only draw podsets when they are selected @@ -395,14 +395,14 @@ public class RocketFigure extends AbstractScaleFigure { } if (!selected) continue; } - + final ArrayList contextList = entry.getValue(); - for(InstanceContext context: contextList ) { + for (InstanceContext context : contextList) { final Transformation currentTransform = this.axialRotation.applyTransformation(context.transform); - allShapes = addThisShape( allShapes, this.currentViewType, comp, currentTransform); + allShapes = addThisShape(allShapes, this.currentViewType, comp, currentTransform); } - } + } } /** diff --git a/swing/src/net/sf/openrocket/simulation/extension/impl/ScriptingConfigurator.java b/swing/src/net/sf/openrocket/simulation/extension/impl/ScriptingConfigurator.java index 1fd7c2eae..d49753dac 100644 --- a/swing/src/net/sf/openrocket/simulation/extension/impl/ScriptingConfigurator.java +++ b/swing/src/net/sf/openrocket/simulation/extension/impl/ScriptingConfigurator.java @@ -8,7 +8,6 @@ import java.awt.event.FocusListener; import java.util.Set; import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -33,7 +32,6 @@ import com.google.inject.Inject; @Plugin public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfigurator { - @Inject private ScriptingUtil util; @@ -66,7 +64,6 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi }); panel.add(languageSelector, "wrap para"); - text = new RSyntaxTextArea(extension.getScript(), 20, 80); text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); text.setCodeFoldingEnabled(true); @@ -91,7 +88,6 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi RTextScrollPane scroll = new RTextScrollPane(text); panel.add(scroll, "spanx, grow, wrap para"); - BooleanModel enabled = new BooleanModel(extension, "Enabled"); JCheckBox check = new JCheckBox(enabled); check.setText(trans.get("SimulationExtension.scripting.text.enabled")); @@ -116,7 +112,6 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi }); panel.add(button, "wrap rel"); - StyledLabel label = new StyledLabel(trans.get("SimulationExtension.scripting.text.trusted.msg"), -1, Style.ITALIC); panel.add(label); @@ -130,7 +125,6 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi util.setTrustedScript(extension.getLanguage(), extension.getScript(), trusted.isSelected()); } - private void setLanguage(String language) { if (language == null) { language = ""; @@ -144,8 +138,7 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi } private String findSyntaxLanguage(String language) { - ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName(language); + ScriptEngine engine = util.getEngineByName(language); if (engine != null) { Set supported = TokenMakerFactory.getDefaultInstance().keySet(); @@ -163,5 +156,4 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi return SyntaxConstants.SYNTAX_STYLE_NONE; } - } diff --git a/swing/src/net/sf/openrocket/utils/Scripting.java b/swing/src/net/sf/openrocket/utils/Scripting.java index ca1a2993d..ec347a189 100644 --- a/swing/src/net/sf/openrocket/utils/Scripting.java +++ b/swing/src/net/sf/openrocket/utils/Scripting.java @@ -5,16 +5,17 @@ import java.util.Collections; import java.util.List; import javax.script.ScriptEngineFactory; -import javax.script.ScriptEngineManager; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; +import net.sf.openrocket.scripting.ScriptEngineManagerRedux; + public class Scripting { public static void main(String[] args) { System.out.println("Scripting APIs:"); - ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngineManagerRedux manager = new ScriptEngineManagerRedux(); for (ScriptEngineFactory factory : manager.getEngineFactories()) { System.out.println(" engineName=" + factory.getEngineName() + " engineVersion=" + factory.getEngineVersion() +