From 0d1b9faa8ce45e3782ef0d4e0911a09c227154e8 Mon Sep 17 00:00:00 2001 From: Nick Kitchel <59104880+PotatoPeeler3000@users.noreply.github.com> Date: Tue, 29 Oct 2024 18:56:30 -0500 Subject: [PATCH] Refactor SCS2YoGraphicHolder and SCS2DefinitionMIssingTools into SCS2 (#192) Moved SCS2YoGraphicHolder and SCS2DefinitionMissingTools into SCS2, they live in scs2-definition right next to the graphics they represent --------- Co-authored-by: rgriffin@ihmc.org --- scs2-bullet-simulation/build.gradle.kts | 6 +- scs2-definition/build.gradle.kts | 12 +- .../scs2/definition/SCS2DefinitionTools.java | 52 ++++++++ .../yoGraphic/SCS2YoGraphicHolder.java | 125 ++++++++++++++++++ scs2-session-visualizer-jfx/build.gradle.kts | 8 +- scs2-shared-memory/build.gradle.kts | 6 +- scs2-simulation/build.gradle.kts | 4 +- scs2-symbolic/build.gradle.kts | 6 +- 8 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 scs2-definition/src/main/java/us/ihmc/scs2/definition/SCS2DefinitionTools.java create mode 100644 scs2-definition/src/main/java/us/ihmc/scs2/definition/yoGraphic/SCS2YoGraphicHolder.java diff --git a/scs2-bullet-simulation/build.gradle.kts b/scs2-bullet-simulation/build.gradle.kts index 8746d430..a630b684 100644 --- a/scs2-bullet-simulation/build.gradle.kts +++ b/scs2-bullet-simulation/build.gradle.kts @@ -17,10 +17,10 @@ mainDependencies { api("us.ihmc:scs2-definition:source") api("us.ihmc:scs2-shared-memory:source") api("us.ihmc:scs2-session:source") - api("us.ihmc:euclid-frame-shape:0.21.0") + api("us.ihmc:euclid-frame-shape:0.22.2") api("us.ihmc:ihmc-messager:0.2.0") - api("us.ihmc:ihmc-yovariables:0.12.2") - api("us.ihmc:mecano-yovariables:17-0.18.1") + api("us.ihmc:ihmc-yovariables:0.13.3") + api("us.ihmc:mecano-yovariables:17-0.19.0") apiBytedecoNatives("javacpp") apiBytedecoNatives("bullet", "3.25-") diff --git a/scs2-definition/build.gradle.kts b/scs2-definition/build.gradle.kts index 96c163fe..545552ba 100644 --- a/scs2-definition/build.gradle.kts +++ b/scs2-definition/build.gradle.kts @@ -11,12 +11,12 @@ ihmc { } mainDependencies { - api("us.ihmc:euclid:0.21.0") - api("us.ihmc:euclid-shape:0.21.0") - api("us.ihmc:euclid-frame:0.21.0") - api("us.ihmc:ihmc-commons:0.32.0") - api("us.ihmc:ihmc-yovariables:0.12.2") - api("us.ihmc:mecano:17-0.18.1") + api("us.ihmc:euclid:0.22.2") + api("us.ihmc:euclid-shape:0.22.2") + api("us.ihmc:euclid-frame:0.22.2") + api("us.ihmc:ihmc-commons:0.34.0") + api("us.ihmc:ihmc-yovariables:0.13.3") + api("us.ihmc:mecano:17-0.19.0") } testDependencies { diff --git a/scs2-definition/src/main/java/us/ihmc/scs2/definition/SCS2DefinitionTools.java b/scs2-definition/src/main/java/us/ihmc/scs2/definition/SCS2DefinitionTools.java new file mode 100644 index 00000000..c24ba116 --- /dev/null +++ b/scs2-definition/src/main/java/us/ihmc/scs2/definition/SCS2DefinitionTools.java @@ -0,0 +1,52 @@ +package us.ihmc.scs2.definition; + +import us.ihmc.scs2.definition.collision.CollisionShapeDefinition; +import us.ihmc.scs2.definition.robot.CrossFourBarJointDefinition; +import us.ihmc.scs2.definition.robot.JointDefinition; +import us.ihmc.scs2.definition.robot.RigidBodyDefinition; +import us.ihmc.scs2.definition.robot.RobotDefinition; +import us.ihmc.scs2.definition.visual.MaterialDefinition; +import us.ihmc.scs2.definition.visual.VisualDefinition; + +import java.util.List; +import java.util.function.Consumer; + +public class SCS2DefinitionTools +{ + public static void forEachRigidBodyDefinitionIncludingFourBars(RigidBodyDefinition start, Consumer rigidBodyConsumer) + { + RobotDefinition.forEachRigidBodyDefinition(start, body -> + { + rigidBodyConsumer.accept(body); + for (JointDefinition childrenJoint : body.getChildrenJoints()) + { + if (childrenJoint instanceof CrossFourBarJointDefinition fourBarJointDefinition) + { + rigidBodyConsumer.accept(fourBarJointDefinition.getBodyBC()); + rigidBodyConsumer.accept(fourBarJointDefinition.getBodyDA()); + } + } + }); + } + + public static void addCollisionVisualsToRobot(RobotDefinition robotDefinition, MaterialDefinition material) + { + robotDefinition.forEachRigidBodyDefinition(rigidBody -> addCollisionVisualsToRigidBodyDefinition(rigidBody, material)); + } + + public static void addCollisionVisualsToRigidBodyDefinition(RigidBodyDefinition rigidBodyDefinition, MaterialDefinition material) + { + if (rigidBodyDefinition == null) + return; + List collisionShapeDefinitions = rigidBodyDefinition.getCollisionShapeDefinitions(); + if (collisionShapeDefinitions == null) + return; + + for (CollisionShapeDefinition collisionShapeDefinition : collisionShapeDefinitions) + { + rigidBodyDefinition.addVisualDefinition(new VisualDefinition(collisionShapeDefinition.getOriginPose(), + collisionShapeDefinition.getGeometryDefinition(), + material)); + } + } +} diff --git a/scs2-definition/src/main/java/us/ihmc/scs2/definition/yoGraphic/SCS2YoGraphicHolder.java b/scs2-definition/src/main/java/us/ihmc/scs2/definition/yoGraphic/SCS2YoGraphicHolder.java new file mode 100644 index 00000000..b75c6426 --- /dev/null +++ b/scs2-definition/src/main/java/us/ihmc/scs2/definition/yoGraphic/SCS2YoGraphicHolder.java @@ -0,0 +1,125 @@ +package us.ihmc.scs2.definition.yoGraphic; + +import us.ihmc.yoVariables.registry.YoRegistry; +import us.ihmc.yoVariables.variable.YoVariable; +import us.ihmc.scs2.definition.SCS2DefinitionTools; + +/** + * This interface was initially created to bind classes that can create SCS2 yoGraphics, such that: + *
    + *
  • they're easy to retrieve for refactoring purposes. + *
  • Javadoc added here can spread around the codebase easily. + *
+ *

+ * SCS2 yoGraphic framework differs from SCS1 yoGraphic framework in a few aspects: + *

    + *
  • 2D vs 3D: + *
      + *
    • SCS1 uses {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphic} for 3D graphics and {@link us.ihmc.graphicsDescription.plotting.artifact.Artifact} for 2D graphics. In this + * documentation, we abuse the term "yoGraphic" to refer to both the 2D and 3D types when referring + * to SCS1. + *
    • SCS2 base class {@link YoGraphicDefinition} is extended into 2 branches: + * {@link YoGraphic3DDefinition} for 3D graphics and {@link YoGraphic2DDefinition} for 2D graphics. + *
    + *
  • Listing and grouping: + *
      + *
    • SCS1 uses {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphicsListRegistry} to do both listing and grouping of yoGraphics. + * {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphicsList} to represent a list of {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphic} and {@link us.ihmc.graphicsDescription.yoGraphics.plotting.ArtifactList} for + * {@link us.ihmc.graphicsDescription.plotting.artifact.Artifact}. The grouping per say is done by attributing a name to a list or specifying a + * {@code listName} when registering a yoGraphic to the {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphicsListRegistry}. + *
    • SCS2 yoGraphic list is {@link YoGraphicListDefinition}. It is meant for convenience, because + * it implements {@link YoGraphicDefinition}, it can be passed around the same way a yoGraphic would + * be. For grouping, {@link YoGraphicGroupDefinition} should be used. You can think of it as a + * {@link YoRegistry} for yoGraphics, it has children (both regular graphics and other groups) and + * can be added to a parent group. A tree hierarchy of yoGraphics and groups can be created and will + * be reflected in the SCS2 GUI, see the menu YoGraphic > YoGraphic properties... all the + * yoGraphics will be under the group root:SessionVisualizer. + *
    + *
  • Internal data: + *
      + *
    • SCS1 yoGraphics are internally backed by {@link YoVariable} which makes them harder to + * serialize (so difficult to save to file and send over network) and also thread sensitive + * (yoVariables should not be shared across threads). + *
    • SCS2 yoGraphics are only descriptions telling SCS2 what type of graphic should be created and + * what data (yoVariables or constants for instance) the graphic uses to notably change over time. + * For instance, the radius of a capsule (see {@link YoGraphicCapsule3DDefinition}) is not a + * yoVariable but a {@code String}. The {@code String} can be used to represent a {@code double} + * (constant value), or a yoVariable by setting it to either {@link YoVariable#getFullNameString()} + * or {@link YoVariable#getName()} (note that the former is preferable to account for non-uniqueness + * of yoVariable names), SCS2 then parses the field accordingly. This makes + * {@link YoGraphicDefinition} easier to serialize, save to file, and makes them thread-safe as no + * state is actually held. + *
    + *
  • Graphic handling: + *
      + *
    • SCS1 yoGraphics are queried regularly by the simulation thread to update their state such + * that the actual graphic can be updated. This is a non-trivial operation as yoGraphics often are + * created by a controller that runs on a different thread than the simulation thread, and they + * carry a state that is used by both the controller and simulation. To make things worse, + * {@link us.ihmc.graphicsDescription.plotting.artifact.Artifact} also implement the rendering. + *
    • Because SCS2 yoGraphics do not actually carry any state, there is no such issue. This comes + * as the cost of making it way harder if not to say impossible to hack things around from the user + * side (outside SCS2 codebase). This often prevents implementing a workaround to a missing feature. + *
    + *
  • YoGraphics propagation to the GUI: + *
      + *
    • With SCS1 yoGraphics the typical workflow is: create a new registry + * {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphicsListRegistry} in the main class where SCS is created, pass it down to the + * controller and any module running with the controller such that they can all create and register + * their {@link us.ihmc.graphicsDescription.yoGraphics.YoGraphic}/{@link us.ihmc.graphicsDescription.plotting.artifact.Artifact} to the registry, finally register the registry to SCS1 + * or a {@code YoVariableServer}. In the case where a multithread controller is used, then 1 + * registry per thread must be created and it should not be shared through threads. + *
    • With SCS2 yoGraphics the intended workflow is: each class needing yoGraphics to be visualized + * should declare a getter that creates and returns {@code YoGraphicDefinition}s, the calling class + * then collects these yoGraphics and the yoGraphics of other classes it manages, and so on such + * that the yoGraphics can bubble all the way up to where the simulation is created. The intent + * behind that bubble up approach vs bubble down used for SCS1, is to reduce the number of + * constructor arguments and let classes higher in the hierarchy decide which yoGraphic to + * visualize. + *
    + *
  • Separation layer between yoGraphics and GUI rendering: + *
      + *
    • In SCS1, the yoGraphics are quite tightly connected to the rendered objects, so much that for + * {@link us.ihmc.graphicsDescription.plotting.artifact.Artifact}s the rendering actually happens inside the artifact class. This allows, when + * running simulation locally, for a certain scope of changes done on the yoGraphic to be reflected + * in the GUI even if the change is not reflected through the change in value of any yoVariable. + *
    • In SCS2, the yoGraphics are only used at the initialization phase of the session as templates + * to create the graphical objects. Consequently, any changes done to a yoGraphic at runtime will + * not be reflected in the GUI. + *
    + *
+ *

+ * + * @author Sylvain Bertrand + */ +public interface SCS2YoGraphicHolder +{ + /** + * The intended implementation for this method is: + *
    + *
  • to create and return the yoGraphics to be visualized, + *
  • to collect and return the yoGraphics from the classes managed by the class. + *
+ *

+ * Useful notes: + *

    + *
  • Use {@link YoGraphicGroupDefinition} to gather multiple yoGraphics and other groups into a + * single {@link YoGraphicDefinition}. The group will appear as a named registry in the SCS GUI. + * Including the name of the class in the group being created helps locating yoGraphics in the code. + *
  • Use {@link YoGraphicListDefinition} if you do not want to create a group but still need to + * gather multiple yoGraphics into a single {@link YoGraphicDefinition}. + *
  • Some helper classes: + *
      + *
    • {@link YoGraphicDefinitionFactory}: gather convenience methods to create + * {@link YoGraphicDefinition}s and other types needed to create yoGraphic. + *
    • {@link us.ihmc.graphicsDescription.conversion.YoGraphicConversionTools}: for conversion tools between SCS1 and SCS2. + *
    • {@link SCS2DefinitionTools}: for implementing that method that should have been + * implemented somewhere in {@code scs2-definition}. + *
    + *
+ *

+ * + * @return the yoGraphics to be visualized in the SCS GUI. + */ + YoGraphicDefinition getSCS2YoGraphics(); +} diff --git a/scs2-session-visualizer-jfx/build.gradle.kts b/scs2-session-visualizer-jfx/build.gradle.kts index 88cbd6c2..e47ed48c 100644 --- a/scs2-session-visualizer-jfx/build.gradle.kts +++ b/scs2-session-visualizer-jfx/build.gradle.kts @@ -27,9 +27,9 @@ mainDependencies { api(ihmc.javaFXModule("fxml", javaFXVersion)) api(ihmc.javaFXModule("swing", javaFXVersion)) - api("us.ihmc:euclid:0.21.0") - api("us.ihmc:euclid-shape:0.21.0") - api("us.ihmc:euclid-frame:0.21.0") + api("us.ihmc:euclid:0.22.2") + api("us.ihmc:euclid-shape:0.22.2") + api("us.ihmc:euclid-frame:0.22.2") api("us.ihmc:ihmc-graphics-description:0.25.1") api("us.ihmc:ihmc-video-codecs:2.1.6") api("us.ihmc:ihmc-javafx-extensions:17-0.2.1") @@ -218,4 +218,4 @@ fun addVSyncLinuxHackForJavaFXApp(sourceFolder: String, javafxappname: String) launchScriptFile.delete() launchScriptFile.writeText(originalScript) -} \ No newline at end of file +} diff --git a/scs2-shared-memory/build.gradle.kts b/scs2-shared-memory/build.gradle.kts index 3da76831..07bbe49d 100644 --- a/scs2-shared-memory/build.gradle.kts +++ b/scs2-shared-memory/build.gradle.kts @@ -12,9 +12,9 @@ ihmc { mainDependencies { api("us.ihmc:scs2-definition:source") - api("us.ihmc:euclid:0.21.0") - api("us.ihmc:euclid-frame:0.21.0") - api("us.ihmc:ihmc-yovariables:0.12.2") + api("us.ihmc:euclid:0.22.2") + api("us.ihmc:euclid-frame:0.22.2") + api("us.ihmc:ihmc-yovariables:0.13.3") api("us.hebi.matlab.mat:mfl-core:0.5.7") } diff --git a/scs2-simulation/build.gradle.kts b/scs2-simulation/build.gradle.kts index 72f61fbb..905bd784 100644 --- a/scs2-simulation/build.gradle.kts +++ b/scs2-simulation/build.gradle.kts @@ -14,9 +14,9 @@ mainDependencies { api("us.ihmc:scs2-definition:source") api("us.ihmc:scs2-shared-memory:source") api("us.ihmc:scs2-session:source") - api("us.ihmc:euclid-frame-shape:0.21.0") + api("us.ihmc:euclid-frame-shape:0.22.2") api("us.ihmc:ihmc-messager:0.2.0") - api("us.ihmc:mecano-yovariables:17-0.18.1") + api("us.ihmc:mecano-yovariables:17-0.19.0") } testDependencies { diff --git a/scs2-symbolic/build.gradle.kts b/scs2-symbolic/build.gradle.kts index a6823339..48bf49e8 100644 --- a/scs2-symbolic/build.gradle.kts +++ b/scs2-symbolic/build.gradle.kts @@ -14,9 +14,9 @@ mainDependencies { api("us.ihmc:scs2-definition:source") api("us.ihmc:scs2-shared-memory:source") - api("us.ihmc:euclid:0.21.0") - api("us.ihmc:euclid-frame:0.21.0") - api("us.ihmc:ihmc-yovariables:0.12.2") + api("us.ihmc:euclid:0.22.2") + api("us.ihmc:euclid-frame:0.22.2") + api("us.ihmc:ihmc-yovariables:0.13.3") } testDependencies {