Constraint-based three-dimensional dynamic geometry
Find a file
Glen Whitney ecbbe2068c
All checks were successful
/ test (pull_request) Successful in 3m35s
feat: Point coordinate regulators
Implements regulators for the Euclidean coordinates of Point entities,
  automatically creating all three of them for each added point entity. When
  such a regulator is set, it freezes the corresponding representation
  coordinate to the set point. In addition, if all three coordinates of a
  given Point are set, the coradius coordinate (which holds the norm of the
  point) is frozen as well.

  Note that a PointCoordinateRegulator must be created with a Point as the
  subject. This commit modifies HalfCurvatureRegulator analogously, so that
  it can only be created with a Sphere.

  A couple of prospective issues that should be filed in association with
  this commit:
  * The new coordinate regulators create redundant display information with
    the raw representation coordinates of a point that are already shown in
    the outline view.
  * The optimization status of these regulators together with HalfCurvature
    regulators (i.e., the ones implemented by freezing coordinates) is different
    from InversiveDistance regulators when an Assembly is unrealizable: the
    frozen-coordinate constraints will be "hard" in that they will be forced
    to precisely equal their set point, whereas the distance regulators are
    "soft" in that they can be relaxed from their set points in an effort to
    minimize the loss function of the configuration as compared to the values
    of the constraints. Perhaps at some point we should/will have a mechanism
    to specify the softness/hardness of constraints, but in the meantime,
    there should not be two different categories of constraints. Suppose we
    decide that by default that all constraints are soft. Then the optimizer
    should be able to search changing, for example, the radius of a
    curvature-constrained sphere, so as to minimize the loss function (for a
    loss that would therefore presumably have a term akin to the square of the
    difference between the specified and actual half-curvature of the sphere).
    For example, suppose you specify that the half-curvature of a sphere is 1
    (so it has radius 1/2) but that its distance to a point is -1. These
    constraints cannot be satisfied, so the optimization fails, presumably
    with the point at the sphere center, and the sphere with radius 1/2.
    So all of the loss is concentrated in the difference between the actual
    point-sphere distance being -1/2, not -1. It would be more appropriate
    (in the all-soft constraint regime) to end up at something like a sphere of
    half-curvature 1/√2 with the point at the center, so that the loss is split
    between both the half-curvature and the distance to the sphere being off by
    1 - 1/√2. (At a guess, that would minimize the sum of the squares of the
    two differences.)
2025-09-20 00:51:26 -07:00
.forgejo Refactor: Use pointers to refer to elements and regulators (#84) 2025-05-06 19:17:30 +00:00
app-proto feat: Point coordinate regulators 2025-09-20 00:51:26 -07:00
coffeetest Set up testing with Ava 2019-12-11 12:07:43 -05:00
deploy Write a deployment packaging script (#113) 2025-08-11 03:33:19 +00:00
doc Switch to good old make to reduce redundancies in build 2019-12-12 00:33:59 -05:00
engine-proto Integrate engine into application prototype (#15) 2024-11-12 00:46:16 +00:00
notes Integrate engine into application prototype (#15) 2024-11-12 00:46:16 +00:00
src Adjust lighting and camera for decent initial rendering of polyhedra 2019-12-31 07:20:33 -08:00
tools Write a deployment packaging script (#113) 2025-08-11 03:33:19 +00:00
.gitignore feat: Continuous integration via Forgejo Actions/runners (#75) 2025-04-02 20:31:42 +00:00
LICENSE Initial commit 2019-09-14 19:00:59 +00:00
Makefile First pass at coordinate axes 2019-12-12 02:44:33 -05:00
package-lock.json Adjust lighting and camera for decent initial rendering of polyhedra 2019-12-31 07:20:33 -08:00
package.json Switch to good old make to reduce redundancies in build 2019-12-12 00:33:59 -05:00
README.md Write a deployment packaging script (#113) 2025-08-11 03:33:19 +00:00

dyna3

Abstract

Constraint-based three-dimensional dynamic geometry

Description

From a thorough web search, there does not seem to be a dynamic geometry software package which (a) began its life handling three dimensions, rather than just two, and (b) allows you to express the desired geometric configuration in terms of constraints on the entities (e.g. l and k are parallel, a, b, and c a collinear, etc.) rather than as a construction (e.g. l is the perpendicular bisector of a and b). The goal of the dyna3 project is to close this gap.

Note that currently this is just the barest beginnings of the project, more of a framework for developing dyna3 rather than anything useful.

Implementation goals

  • Comfortable, intuitive UI

  • Able to run in browser (so implemented in WASM-compatible language)

  • Produce scalable graphics of 3D diagrams, and maybe STL files (or other fabricatable file format) as well.

Prototype

The latest prototype is in the folder app-proto. It includes both a user interface and a numerical constraint-solving engine.

Install the prerequisites

  1. Install rustup: the officially recommended Rust toolchain manager
    • It's available on Ubuntu as a Snap
  2. Call rustup default stable to "download the latest stable release of Rust and set it as your default toolchain"
    • If you forget, the rustup help system will remind you
  3. Call rustup target add wasm32-unknown-unknown to add the most generic 32-bit WebAssembly target
  4. Call cargo install wasm-pack to install the WebAssembly toolchain
  5. Call cargo install trunk to install the Trunk web-build tool
  6. Add the .cargo/bin folder in your home directory to your executable search path
    • This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
    • On POSIX systems, the search path is stored in the PATH environment variable

Play with the prototype

  1. From the app-proto folder, call trunk serve --release to build and serve the prototype
    • The crates the prototype depends on will be downloaded and served automatically
    • For a faster build, at the expense of a much slower prototype, you can call trunk serve without the --release flag
    • If you want to stay in the top-level folder, you can call trunk serve --config app-proto [--release] from there instead.
  2. In a web browser, visit one of the URLs listed under the message INFO 📡 server listening at:
    • Touching any file in the app-proto folder will make Trunk rebuild and live-reload the prototype
  3. Press ctrl+C in the shell where Trunk is running to stop serving the prototype

Run the engine on some example problems

  1. Use sh to run the script tools/run-examples.sh
    • The script is location-independent, so you can do this from anywhere in the dyna3 repository

    • The call from the top level of the repository is:

      sh tools/run-examples.sh
      
    • For each example problem, the engine will print the value of the loss function at each optimization step

    • The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into engine-proto/gram-test, launch Julia, and then

      include("irisawa-hexlet.jl")
      for (step, scaled_loss) in enumerate(history_alt.scaled_loss)
        println(rpad(step-1, 4), " | ", scaled_loss)
      end
      

      you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show

Run the automated tests

  1. Go into the app-proto folder
  2. Call cargo test

Deploy the prototype

  1. From the app-proto folder, call trunk build --release
    • Building in release mode produces an executable which is smaller and often much faster, but harder to debug and more time-consuming to build
    • If you want to stay in the top-level folder, you can call trunk build --config app-proto --release from there instead
  2. Use sh to run the packaging script tools/package-for-deployment.sh.
    • The script is location-independent, so you can do this from anywhere in the dyna3 repository
    • The call from the top level of the repository is:
      sh tools/package-for-deployment.sh
      
    • This will overwrite or replace the files in deploy/dyna3
  3. Put the contents of deploy/dyna3 in the folder on your server that the prototype will be served from.
    • To simplify uploading, you might want to combine these files into an archive called deploy/dyna3.zip. Git has been set to ignore this path