Introducing the "module" feature #145
Closed
ricktu288
announced in
Announcements
Replies: 1 comment 2 replies
-
When an object is edited, the corresponding embedded JS code editor immediately shows the updated code for the altered object. I appreciate this "display corresponding source code" feature, as it is similar to LaTeX's click-to-source functionality in PDFs. I'm curious about how this can be implemented with JS :) |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The "module" is a new experimental feature that allows you to combine several objects (optical elements, etc.) into a single reusable "module object" with custom parameters and control points. The objects within a module are defined with a template, which allows math equations and the creation of arrays of objects.
Note: You don't need to clone the repo to make custom modules. Everything happens directly within in the web app.
Examples
Note: This feature is still experimental, so the corresponding items in the Gallery will not be modified until this feature becomes stable.
Tutorial
This tutorial will guide you through the basics of creating a module. It works completely within the web app online, so you don't need to install any development environment.
Note that not all custom control points requires a module. Some simple cases may be achieved by the "handle" feature (see "Group, rotate, and scale objects" section in the help popup at the bottom right corner of the simulator). Since creating a module is much more complicated than using the handle, you should check if your case can be achieved by the "handle" feature before considering building a module. See here for a non-trivial example of a custom control point (moving two plastic bags out of water) without using module.
The built-in JSON editor
This app currently does not have a visual interface for creating modules, so you need to directly edit the JSON of the scene.
You can enable the built-in JSON editor by clicking the "settings" dropdown at the top-right corner of the app, and then check "Show JSON editor". The code editor should appear at the left-hand side of the app, with the JSON code of the current scene. Make sure you have a large enough screen, as this feature does not work well on mobile devices.
As you edit the scene using the usual visual scene editor, the code in the JSON editor will update accordingly, with the changed part highlighted. Conversely, directly editing the code in the JSON editor will update the scene accordingly. If you are not familiar with JSON or any kind of text-based data format, you may wish to play around with it for a while.
In particular, when you add an object to the scene, it is added to the
objs
array. And if you modify some of its properties to a non-default value, they appear as key-value pairs in that object.Basics of a module
Let's look at our first example of a module.
Example 1
You should see four lines of texts. By looking at the JSON editor, you will see that the first two are directly in the top-level
objs
array as usual, but the last two are inmodules.ExampleModule.objs
instead.The
module
is a dictionary where the key is the name of the module (in this caseExampleModule
), and the value is the definition of that module. In particular, themodules.ExampleModule.objs
array describes the (template of) objects within that module, which is different from the top-levelobjs
which describes the objects in the scene.To put the objects within the module to the scene, we need a "module object" in the top-level
objs
array, which isobjs[2]
in this example, whose type isModuleObj
and whosemodule
property is the name of the module.The module definition in the
modules
dictionary is not editable by the visual scene editor. So when you click any of the last two texts in this example, you are just selecting the module object, and not the objects in the module. Since the coordinates of the texts in the module definition in this example are absolute coordinates, the last two texts are not draggable. We will learn how to make them draggable by using control points later.If you select a module object, there is a "Demodulize" button on the object bar. Clicking it will "expand" the module object into its constituent, and
objs
will now contain all the four texts. This operation is not reversible (but of course you can click "undo").The suggested way of creating a module currently is to first create an empty module using the JSON editor, create some objects using the visual scene editor, and then cut and paste the objects from
objs
tomodules.ModuleName.objs
using the JSON editor.Adding parameters
The objects within the module can be defined by a set of parameters. Let’s look at a simple example:
Example 2
Here
modules.ModuleName.params
is an array of strings"name=start:step:end:default"
defining the name of the variables and the range of the sliders. The sliders appear on the object bar when the module object is selected.Within the
modules.ExampleModule.objs
array, any values can be expressed using those parameters. Within a string (such as thetext
property of aTextLabel
), the equations of the variables are enclosed by a pair of backticks. For number parameters (such as thefontSize
property of aTextLabel
), you need to make it a string so that you can use the backtick format in it, so each equation is sandwiched by a pair of backticks and a pair of quotes. The equation are evaluated with math.js (https://mathjs.org/docs/reference/functions/evaluate.html). See there for the available syntax and functions you can use in the equations.The actual values of the parameters are stored in the
params
property of the module object, which, unlike the module definition, can be directly edited by the scene editor using the slider.Adding control points
To make the module object draggable, we need to parametrize the objects within the module using a set of control points. Let’s look at the example:
Example 3
Here
modules.ModuleName.numPoints
defines the number of control points. The coordinates of the control points are (x_1
,y_1
), (x_2
,y_2
), etc, and are used in the same ways as the parameters withinmodules.ExampleModule.objs
as described by the previous section. Note that the index starts from 1.The actual values of the coordinates of the control points are stored in the
points
property of the module object, which, unlike the hard-coded coordinates in Example 1, can be edited by the visual scene editor by dragging the control points, each shown as two concentric gray circles in the scene. If you drag elsewhere in the module object (such as dragging the text labels), all the control points will move together.Since our module object can now move, it is now quite easy to create multiple instances as in usual tools. The name of the module is shown in the Tools -> Other menu, and you can select that and then click two points in the blank space in sequence for the two control points to create another instance of the module. You can also use the “duplicate” button on the object bar.
Arrays and conditionals
More complicated module can be built using arrays and conditionals. Let’s look at the example:
Example 4
Within
modules.ExampleModule.objs
, any objects in an array can have two special keys:"for"
and"if"
. The value of the"for"
key is either a string of the format"name=start:step:end"
defining a loop variable, or an array of several strings of this format describing a multidimensional loop. Such an object in the array is duplicated several times according to the loop variables. The value of the"if"
key is a string representing a math.js expression that evaluates to a boolean, and such an object is included in the array if and only if the boolean is true.To prevent accidental infinite loop, the total number of iteration of each
"for"
loop is limited by themaxLoopLength
property of the module definition, whose default value is 1000. You can set this property to a larger value if needed.Objects with built-in custom equations
For objects that already have custom equation input (such as Mirror -> Custom Equation), the equation property in the JSON is a string representing a LaTeX equation, rather than a math.js expression. To include custom parameters in the equation, you must use the same template syntax as if the LaTeX equation were a regular text. So the part enclosed by the backticks is in math.js expression, while the part outside is in LaTeX. The module parameters can only be accessed in the math.js part, and the independent variables of the custom equation (e.g. ) can only be accessed in the LaTeX part. Here is an example of generating a mirror with equation , where is a module parameter:
Example 5
In the future, there may be a way to unified the equation input.
Objects with built-in shape parametrization
For objects that already support different ways to define its shape (currently only Glass -> Spherical lens). There are special JSON syntax for such objects that can be used within the module definition, even if they are always defined by shape in the top level
objs
array. Here is an example:Example 6
Contributing
Contributing a module
You are welcome to contribute to the list in Tools -> Other -> Import Modules. Please add items to the
modules
folder and open a PR, or send the file to ray-optics@phydemo.app if you are not familiar with GitHub.Expanding the capability of modules
See
ModuleObj.js
for the source code. See #142 and #143 for currently required capabilities which are still not directly possible.Note: The
modulize
branch is not related to this feature; the "module" there refers to the different concept of (slowly) refactoring the code of the app itself towards a modular structure.Possible visual editor?
A graphical editor of modules may be desired for the future, but it will be quite complicated. See #141 (comment) for a possible approach.
Beta Was this translation helpful? Give feedback.
All reactions