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

us.ihmc.javafx.FootstepMeshManager Maven / Gradle / Ivy

package us.ihmc.javafx;

import controller_msgs.msg.dds.FootstepDataMessage;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.shape.Mesh;
import org.apache.commons.lang3.tuple.Pair;
import us.ihmc.euclid.geometry.ConvexPolygon2D;
import us.ihmc.euclid.transform.RigidBodyTransform;
import us.ihmc.euclid.tuple2D.Point2D;
import us.ihmc.javaFXToolkit.shapes.JavaFXMultiColorMeshBuilder;
import us.ihmc.robotics.robotSide.RobotSide;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BooleanSupplier;
import java.util.function.Function;

public class FootstepMeshManager
{
   private static final double POLYGON_THICKNESS = 0.01;

   private final JavaFXMultiColorMeshBuilder meshBuilder;

   private final Function defaultContactPointSupplier;
   private final BooleanSupplier isSelected;
   private final BooleanSupplier ignorePartialFootholds;

   private final MeshHolder meshHolder;
   private final AtomicReference footstepDataMessage = new AtomicReference<>();

   private final RigidBodyTransform transformToWorld = new RigidBodyTransform();
   private final ConvexPolygon2D foothold = new ConvexPolygon2D();

   public FootstepMeshManager(Group root,
                              JavaFXMultiColorMeshBuilder meshBuilder,
                              Function defaultContactPointSupplier,
                              BooleanSupplier isSelected,
                              BooleanSupplier ignorePartialFootholds)
   {
      meshHolder = new MeshHolder(root);
      this.meshBuilder = meshBuilder;
      this.defaultContactPointSupplier = defaultContactPointSupplier;
      this.isSelected = isSelected;
      this.ignorePartialFootholds = ignorePartialFootholds;
   }

   /**
    * Call from any thread
    */
   public void computeMesh()
   {
      if (footstepDataMessage.get() == null)
      {
         return;
      }

      meshBuilder.clear();
      foothold.clear();

      FootstepDataMessage footstepDataMessage = this.footstepDataMessage.get();

      Color footColor = getFootstepColor(footstepDataMessage);
      RobotSide robotSide = RobotSide.fromByte(footstepDataMessage.getRobotSide());

      transformToWorld.set(footstepDataMessage.getOrientation(), footstepDataMessage.getLocation());

      if (ignorePartialFootholds.getAsBoolean() || footstepDataMessage.getPredictedContactPoints2d().isEmpty())
      {
         foothold.set(defaultContactPointSupplier.apply(robotSide));
      }
      else
      {
         footstepDataMessage.getPredictedContactPoints2d().forEach(p -> foothold.addVertex(p.getX(), p.getY()));
         foothold.update();
      }

      Point2D[] vertices = new Point2D[foothold.getNumberOfVertices()];
      for (int j = 0; j < vertices.length; j++)
      {
         vertices[j] = new Point2D(foothold.getVertex(j));
      }

      // Shift halfway so that bottom of perimeter line is flush with ground
      transformToWorld.appendTranslation(0.0, 0.0, 0.5 * POLYGON_THICKNESS);
      meshBuilder.addMultiLine(transformToWorld, vertices, POLYGON_THICKNESS, footColor, true);
      meshBuilder.addPolygon(transformToWorld, foothold, footColor);

      Pair meshMaterialPair = Pair.of(meshBuilder.generateMesh(), meshBuilder.generateMaterial());
      meshHolder.setMeshReference(meshMaterialPair);
   }

   private Color getFootstepColor(FootstepDataMessage footstepDataMessage)
   {
      if (isSelected.getAsBoolean())
      {
         return Color.YELLOW.darker();
      }
      else
      {
         return footstepDataMessage.getRobotSide() == 0 ? Color.RED : Color.GREEN;
      }
   }
   
   public void setFootstepDataMessage(FootstepDataMessage message)
   {
      footstepDataMessage.set(message);
   }
   
   public MeshHolder getMeshHolder()
   {
      return meshHolder;
   }

   /**
    * Call from AnimationTimer.handle
    */
   public void updateMesh()
   {
      meshHolder.update();
   }

   /**
    * Call from AnimationTimer.handle
    */
   public void clear()
   {
      footstepDataMessage.set(null);
      meshHolder.remove();
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy