All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.ihmc.scs2.sessionVisualizer.jfx.controllers.yoGraphic.YoGraphicItemCreatorDialogController Maven / Gradle / Ivy

package us.ihmc.scs2.sessionVisualizer.jfx.controllers.yoGraphic;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.apache.commons.lang3.StringUtils;
import us.ihmc.scs2.definition.robot.RobotDefinition;
import us.ihmc.scs2.definition.terrain.TerrainObjectDefinition;
import us.ihmc.scs2.sessionVisualizer.jfx.SessionVisualizerIOTools;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.ReferenceFrameManager;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.ReferenceFrameWrapper;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.SessionVisualizerToolkit;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.YoManager;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.YoRobotFXManager;
import us.ihmc.scs2.sessionVisualizer.jfx.yoGraphic.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import static us.ihmc.scs2.sessionVisualizer.jfx.controllers.yoGraphic.YoGraphicFXControllerTools.createAvailableYoGraphicFXItemName;

public class YoGraphicItemCreatorDialogController
{
   @FXML
   private Pane mainPane;
   @FXML
   private ToggleButton yoLineFX2DToggleButton, yoPointcloudFX2DToggleButton, yoPointFX2DToggleButton, yoPolygonFX2DToggleButton;
   @FXML
   private ToggleButton yoArrowFX3DToggleButton, yoBoxFX3DToggleButton, yoCapsuleFX3DToggleButton, yoConeFX3DToggleButton, yoCoordinateSystemFX3DToggleButton, yoCylinderFX3DToggleButton, yoEllipsoidFX3DToggleButton, yoPointcloudFX3DToggleButton, yoPointFX3DToggleButton, yoPolygonExtrudedFX3DToggleButton, yoConvexPolytopeFX3DToggleButton, yoPolynomialFX3DToggleButton, yoRampFX3DToggleButton, yoSTPBoxFX3DToggleButton;
   @FXML
   private ToggleButton yoAddRobotFXToggleButton;
   @FXML
   private GridPane miscPane;
   @FXML
   private ToggleButton yoGroupFXToggleButton;
   @FXML
   private TextField itemNameTextField;
   @FXML
   private TextField itemNamespaceTextField;
   @FXML
   private ImageView itemNameValidImageView;
   @FXML
   private Button createItemButton;
   @FXML
   private TitledPane graphics2DTitledPane, graphics3DTitledPane, miscTitledPane;
   @FXML
   private Accordion accordion;

   // These ToggleButtons are created on the fly when start/stop session and added to the miscFlowPane
   private final ObservableList robotCollisionsToggleButtons = FXCollections.observableArrayList();
   private ToggleButton terrainCollisionsToggleButton = null;
   private final ObservableList robotMassPropertiesToggleButtons = FXCollections.observableArrayList();

   private final ToggleGroup toggleGroup = new ToggleGroup();
   private final Stage stage = new Stage(StageStyle.UTILITY);
   private final BooleanProperty itemNameValidityProperty = new SimpleBooleanProperty(this, "itemNameValidity", false);
   private final BooleanProperty userValidatedProperty = new SimpleBooleanProperty(this, "userValidated", false);
   private final Map> buttonToTypeMap = new LinkedHashMap<>();
   private final Map, String> typeToDefaultNameMap = new LinkedHashMap<>();

   private ReferenceFrameWrapper worldFrame;
   private YoRobotFXManager robotFXManager;
   private YoManager yoManager;
   private ReferenceFrameManager referenceFrameManager;
   private ObservableList sessionRobotDefinitions;
   private ObservableList sessionTerrainObjectDefinitions;

   private YoGroupFX parent;

   public void initialize(SessionVisualizerToolkit toolkit)
   {
      accordion.setExpandedPane(graphics2DTitledPane);

      referenceFrameManager = toolkit.getReferenceFrameManager();
      worldFrame = referenceFrameManager.getWorldFrame();
      robotFXManager = toolkit.getYoRobotFXManager();
      yoManager = toolkit.getYoManager();
      sessionRobotDefinitions = toolkit.getSessionRobotDefinitions();
      sessionTerrainObjectDefinitions = toolkit.getSessionTerrainObjectDefinitions();

      // Buttons to types:
      // Graphic 2D:
      buttonToTypeMap.put(yoLineFX2DToggleButton, YoLineFX2D.class);
      buttonToTypeMap.put(yoPointcloudFX2DToggleButton, YoPointcloudFX2D.class);
      buttonToTypeMap.put(yoPointFX2DToggleButton, YoPointFX2D.class);
      buttonToTypeMap.put(yoPolygonFX2DToggleButton, YoPolygonFX2D.class);
      // Graphic 3D:
      buttonToTypeMap.put(yoArrowFX3DToggleButton, YoArrowFX3D.class);
      buttonToTypeMap.put(yoBoxFX3DToggleButton, YoBoxFX3D.class);
      buttonToTypeMap.put(yoCapsuleFX3DToggleButton, YoCapsuleFX3D.class);
      buttonToTypeMap.put(yoConeFX3DToggleButton, YoConeFX3D.class);
      buttonToTypeMap.put(yoCoordinateSystemFX3DToggleButton, YoCoordinateSystemFX3D.class);
      buttonToTypeMap.put(yoCylinderFX3DToggleButton, YoCylinderFX3D.class);
      buttonToTypeMap.put(yoEllipsoidFX3DToggleButton, YoEllipsoidFX3D.class);
      buttonToTypeMap.put(yoPointcloudFX3DToggleButton, YoPointcloudFX3D.class);
      buttonToTypeMap.put(yoPointFX3DToggleButton, YoPointFX3D.class);
      buttonToTypeMap.put(yoPolygonExtrudedFX3DToggleButton, YoPolygonExtrudedFX3D.class);
      buttonToTypeMap.put(yoConvexPolytopeFX3DToggleButton, YoConvexPolytopeFX3D.class);
      buttonToTypeMap.put(yoPolynomialFX3DToggleButton, YoPolynomialFX3D.class);
      buttonToTypeMap.put(yoRampFX3DToggleButton, YoRampFX3D.class);
      buttonToTypeMap.put(yoSTPBoxFX3DToggleButton, YoSTPBoxFX3D.class);
      // Misc.:
      buttonToTypeMap.put(yoGroupFXToggleButton, YoGroupFX.class);
      buttonToTypeMap.put(yoAddRobotFXToggleButton, YoGhostRobotFX.class);

      // Default Names:
      // Graphic 2D:
      typeToDefaultNameMap.put(YoLineFX2D.class, "Line 2D");
      typeToDefaultNameMap.put(YoPointcloudFX2D.class, "Pointcloud 2D");
      typeToDefaultNameMap.put(YoPointFX2D.class, "Point 2D");
      typeToDefaultNameMap.put(YoPolygonFX2D.class, "Polygon 2D");
      // Graphic 3D:
      typeToDefaultNameMap.put(YoArrowFX3D.class, "Arrow 3D");
      typeToDefaultNameMap.put(YoBoxFX3D.class, "Box 3D");
      typeToDefaultNameMap.put(YoCapsuleFX3D.class, "Capsule 3D");
      typeToDefaultNameMap.put(YoConeFX3D.class, "Cone 3D");
      typeToDefaultNameMap.put(YoCoordinateSystemFX3D.class, "Coordinate System 3D");
      typeToDefaultNameMap.put(YoCylinderFX3D.class, "Cylinder 3D");
      typeToDefaultNameMap.put(YoEllipsoidFX3D.class, "Ellipsoid 3D");
      typeToDefaultNameMap.put(YoPointcloudFX3D.class, "Pointcloud 3D");
      typeToDefaultNameMap.put(YoPointFX3D.class, "Point 3D");
      typeToDefaultNameMap.put(YoPolygonExtrudedFX3D.class, "Polygon Extruded 3D");
      typeToDefaultNameMap.put(YoConvexPolytopeFX3D.class, "Convex Polytope 3D");
      typeToDefaultNameMap.put(YoPolynomialFX3D.class, "Polynomial 3D");
      typeToDefaultNameMap.put(YoRampFX3D.class, "Ramp 3D");
      typeToDefaultNameMap.put(YoSTPBoxFX3D.class, "STP Box 3D");
      // Misc.:
      typeToDefaultNameMap.put(YoGroupFX.class, "Group");
      typeToDefaultNameMap.put(YoGhostRobotFX.class, "Ghost Robot");

      buttonToTypeMap.keySet().forEach(button -> button.setToggleGroup(toggleGroup));

      sessionRobotDefinitions.addListener((ListChangeListener) change -> refreshRobotCollisionsToggleButtons());
      refreshRobotCollisionsToggleButtons();
      sessionTerrainObjectDefinitions.addListener((ListChangeListener) change -> refreshTerrainCollisionsToggleButton());
      refreshTerrainCollisionsToggleButton();
      sessionRobotDefinitions.addListener((ListChangeListener) change -> refreshRobotMassPropertiesToggleButtons());
      refreshRobotMassPropertiesToggleButtons();

      toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) ->
                                                       {
                                                          Class newItemType;
                                                          String name;

                                                          if (robotCollisionsToggleButtons.contains(newValue))
                                                          {
                                                             newItemType = YoGroupFX.class;
                                                             name = sessionRobotDefinitions.get(robotCollisionsToggleButtons.indexOf(newValue)).getName()
                                                                    + " collisions";
                                                          }
                                                          else if (terrainCollisionsToggleButton != null && terrainCollisionsToggleButton == newValue)
                                                          {
                                                             newItemType = YoGroupFX.class;
                                                             name = "Terrain collisions";
                                                          }
                                                          else if (robotMassPropertiesToggleButtons.contains(newValue))
                                                          {
                                                             newItemType = YoGroupFX.class;
                                                             name = sessionRobotDefinitions.get(robotMassPropertiesToggleButtons.indexOf(newValue)).getName()
                                                                    + " mass properties";
                                                          }
                                                          else
                                                          {
                                                             newItemType = toItemType(newValue);
                                                             name = typeToDefaultNameMap.get(newItemType);
                                                          }

                                                          name = newItemType == null ? "" : createAvailableYoGraphicFXItemName(parent, name, newItemType);

                                                          itemNameTextField.setText(name);
                                                          itemNameValidityProperty.set(isYoGraphicFXItemNameValid(name, newItemType));
                                                       });

      itemNameTextField.textProperty().addListener((observable, oldValue, newValue) ->
                                                   {
                                                      if (robotCollisionsToggleButtons.contains(toggleGroup.getSelectedToggle()))
                                                         itemNameValidityProperty.set(isYoGraphicFXItemNameValid(newValue, YoGroupFX.class));
                                                      else if (terrainCollisionsToggleButton != null
                                                               && terrainCollisionsToggleButton == toggleGroup.getSelectedToggle())
                                                         itemNameValidityProperty.set(isYoGraphicFXItemNameValid(newValue, YoGroupFX.class));
                                                      else if (robotMassPropertiesToggleButtons.contains(toggleGroup.getSelectedToggle()))
                                                         itemNameValidityProperty.set(isYoGraphicFXItemNameValid(newValue, YoGroupFX.class));
                                                      else
                                                         itemNameValidityProperty.set(isYoGraphicFXItemNameValid(newValue,
                                                                                                                 toItemType(toggleGroup.getSelectedToggle())));
                                                   });
      YoGraphicFXControllerTools.bindValidityImageView(itemNameValidityProperty, itemNameValidImageView);

      createItemButton.disableProperty().bind(itemNameValidityProperty.not());

      stage.initOwner(toolkit.getMainWindow());
      Scene scene = new Scene(mainPane);

      stage.setTitle("YoGraphicFXItem creation");
      SessionVisualizerIOTools.addSCSIconToWindow(stage);
      stage.setScene(scene);
   }

   private void refreshRobotCollisionsToggleButtons()
   {
      miscPane.getChildren().removeAll(robotCollisionsToggleButtons);
      robotCollisionsToggleButtons.forEach(button -> button.setToggleGroup(null));
      cleanupMiscPane();

      robotCollisionsToggleButtons.clear();
      robotCollisionsToggleButtons.addAll(sessionRobotDefinitions.stream().map(this::createRobotCollisionsToggleButton).toList());

      addNodesToMiscPane(robotCollisionsToggleButtons);
      robotCollisionsToggleButtons.forEach(button -> button.setToggleGroup(toggleGroup));
   }

   private void refreshTerrainCollisionsToggleButton()
   {
      if (sessionTerrainObjectDefinitions.isEmpty())
      { // There's no terrain collision, let's remove the button.
         if (terrainCollisionsToggleButton != null)
         {
            terrainCollisionsToggleButton.setToggleGroup(null);
            miscPane.getChildren().remove(terrainCollisionsToggleButton);
            terrainCollisionsToggleButton = null;
            cleanupMiscPane();
         }
      }
      else
      { // There's some terrain, let's add the button.
         if (terrainCollisionsToggleButton == null)
         {
            terrainCollisionsToggleButton = createTerrainCollisionsToggleButton();
            addNodeToMiscPane(terrainCollisionsToggleButton);
            terrainCollisionsToggleButton.setToggleGroup(toggleGroup);
         }
      }
   }

   private void refreshRobotMassPropertiesToggleButtons()
   {
      miscPane.getChildren().removeAll(robotMassPropertiesToggleButtons);
      robotMassPropertiesToggleButtons.forEach(button -> button.setToggleGroup(null));
      cleanupMiscPane();

      robotMassPropertiesToggleButtons.clear();
      robotMassPropertiesToggleButtons.addAll(sessionRobotDefinitions.stream().map(this::createRobotMassPropertiesToggleButton).toList());

      addNodesToMiscPane(robotMassPropertiesToggleButtons);
      robotMassPropertiesToggleButtons.forEach(button -> button.setToggleGroup(toggleGroup));
   }

   private void cleanupMiscPane()
   {
      ArrayList nodes = new ArrayList<>(miscPane.getChildren());
      miscPane.getChildren().clear();
      addNodesToMiscPane(nodes);
   }

   private void addNodesToMiscPane(Collection nodes)
   {
      int numberOfColumns = miscPane.getColumnConstraints().size();
      int row = miscPane.getChildren().size() / numberOfColumns;
      int col = miscPane.getChildren().size() % numberOfColumns;

      for (Node node : nodes)
      {
         miscPane.add(node, col, row);
         col++;
         if (col >= numberOfColumns)
         {
            col = 0;
            row++;
         }
      }
   }

   private void addNodeToMiscPane(Node node)
   {
      int numberOfColumns = miscPane.getColumnConstraints().size();
      int row = miscPane.getChildren().size() / numberOfColumns;
      int col = miscPane.getChildren().size() % numberOfColumns;
      miscPane.add(node, col, row);
   }

   public void setParent(YoGroupFX parent)
   {
      this.parent = parent;
      userValidatedProperty.set(false);
      itemNamespaceTextField.setText(parent.getFullname());
      Class itemType = toItemType(toggleGroup.getSelectedToggle());
      if (itemType != null)
      {
         String name = itemNameTextField.getText();
         if (name.trim().isEmpty())
            name = typeToDefaultNameMap.get(itemType);
         itemNameTextField.setText(createAvailableYoGraphicFXItemName(parent, name, itemType));
      }
      itemNameValidityProperty.set(isYoGraphicFXItemNameValid(itemNameTextField.getText(), itemType));
   }

   public void showAndWait()
   {
      stage.showAndWait();
   }

   public YoGraphicFXItem createItem()
   {
      if (!userValidatedProperty.get())
         return null;
      if (!itemNameValidityProperty.get())
         return null;
      if (toggleGroup.getSelectedToggle() == null)
         return null;

      Class itemType = toItemType(toggleGroup.getSelectedToggle());
      if (itemType == YoGhostRobotFX.class)
      {
         YoGhostRobotFX yoGhostRobotFX = new YoGhostRobotFX(yoManager);
         yoGhostRobotFX.setName(itemNameTextField.getText());
         parent.addYoGraphicFX3D(yoGhostRobotFX);
         return yoGhostRobotFX;
      }
      else if (itemType != null)
      {
         return YoGraphicFXControllerTools.createYoGraphicFXItemAndRegister(worldFrame, parent, itemNameTextField.getText(), itemType);
      }
      else if (robotCollisionsToggleButtons.contains(toggleGroup.getSelectedToggle()))
      {
         RobotDefinition robotDefinition = sessionRobotDefinitions.get(robotCollisionsToggleButtons.indexOf(toggleGroup.getSelectedToggle()));
         YoGroupFX robotCollisionShapeDefinitions = YoGraphicTools.convertRobotCollisionShapeDefinitions(robotFXManager.getRobotRootBody(robotDefinition.getName()),
                                                                                                         robotDefinition,
                                                                                                         referenceFrameManager);
         robotCollisionShapeDefinitions.setName(itemNameTextField.getText());
         boolean success = parent.addChild(robotCollisionShapeDefinitions);
         return success ? robotCollisionShapeDefinitions : null;
      }
      else if (terrainCollisionsToggleButton != null && terrainCollisionsToggleButton == toggleGroup.getSelectedToggle())
      {
         YoGroupFX terrainCollisionShapeDefinitions = YoGraphicTools.convertTerrainObjectsCollisionShapeDefinitions(worldFrame,
                                                                                                                    sessionTerrainObjectDefinitions);
         terrainCollisionShapeDefinitions.setName(itemNameTextField.getText());
         boolean success = parent.addChild(terrainCollisionShapeDefinitions);
         return success ? terrainCollisionShapeDefinitions : null;
      }
      else if (robotMassPropertiesToggleButtons.contains(toggleGroup.getSelectedToggle()))
      {
         RobotDefinition robotDefinition = sessionRobotDefinitions.get(robotMassPropertiesToggleButtons.indexOf(toggleGroup.getSelectedToggle()));
         YoGroupFX robotMassPropertiesShapeDefinitions = YoGraphicTools.convertRobotMassPropertiesShapeDefinitions(robotFXManager.getRobotRootBody(
               robotDefinition.getName()), robotDefinition, referenceFrameManager);
         robotMassPropertiesShapeDefinitions.setName(itemNameTextField.getText());
         boolean success = parent.addChild(robotMassPropertiesShapeDefinitions);
         return success ? robotMassPropertiesShapeDefinitions : null;
      }
      else
      {
         return null;
      }
   }

   private Class toItemType(Toggle toggle)
   {
      if (toggle == null)
         return null;
      return buttonToTypeMap.get(toggle);
   }

   private boolean isYoGraphicFXItemNameValid(String itemName, Class itemClass)
   {
      if (itemName == null || itemName.isEmpty())
         return false;
      if (itemClass == null)
         return false;

      if (YoGroupFX.class.isAssignableFrom(itemClass))
         return isYoGraphicFXGroupNameValid(itemName);
      else if (YoGraphicFX2D.class.isAssignableFrom(itemClass))
         return isYoGraphicFX2DNameValid(itemName);
      else if (YoGraphicFX3D.class.isAssignableFrom(itemClass))
         return isYoGraphicFX3DNameValid(itemName);
      else
         throw new RuntimeException("Unexpected item type: " + itemClass.getSimpleName());
   }

   private boolean isYoGraphicFXGroupNameValid(String itemName)
   {
      return !parent.containsChild(itemName);
   }

   private boolean isYoGraphicFX2DNameValid(String itemName)
   {
      return !parent.containsYoGraphicFX2D(itemName);
   }

   private boolean isYoGraphicFX3DNameValid(String itemName)
   {
      return !parent.containsYoGraphicFX3D(itemName);
   }

   @FXML
   private void cancelAndDispose(ActionEvent event)
   {
      userValidatedProperty.set(false);
      stage.close();
   }

   @FXML
   private void validateItemAndDispose(ActionEvent event)
   {
      userValidatedProperty.set(true);
      stage.close();
   }

   private ToggleButton createRobotCollisionsToggleButton(RobotDefinition robotdefinition)
   {
      FXMLLoader loader = new FXMLLoader(SessionVisualizerIOTools.YO_GRAPHIC_ROBOT_COLLISIONS_BUTTON_URL);
      try
      {
         ToggleButton button = loader.load();
         button.setText(StringUtils.capitalize(robotdefinition.getName()) + " Collisions");
         return button;
      }
      catch (IOException e)
      {
         e.printStackTrace();
         return null;
      }
   }

   private ToggleButton createTerrainCollisionsToggleButton()
   {
      FXMLLoader loader = new FXMLLoader(SessionVisualizerIOTools.YO_GRAPHIC_TERRAIN_COLLISIONS_BUTTON_URL);
      try
      {
         return loader.load();
      }
      catch (IOException e)
      {
         e.printStackTrace();
         return null;
      }
   }

   private ToggleButton createRobotMassPropertiesToggleButton(RobotDefinition robotdefinition)
   {
      FXMLLoader loader = new FXMLLoader(SessionVisualizerIOTools.YO_GRAPHIC_ROBOT_MASS_PROPERTIES_BUTTON_URL);
      try
      {
         ToggleButton button = loader.load();
         button.setText(StringUtils.capitalize(robotdefinition.getName()) + " Mass Properties");
         return button;
      }
      catch (IOException e)
      {
         e.printStackTrace();
         return null;
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy