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

us.ihmc.scs2.sessionVisualizer.jfx.managers.CameraSensorsManager Maven / Gradle / Ivy

package us.ihmc.scs2.sessionVisualizer.jfx.managers;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.transform.Affine;
import us.ihmc.euclid.exceptions.NotARotationMatrixException;
import us.ihmc.euclid.matrix.RotationMatrix;
import us.ihmc.euclid.referenceFrame.ReferenceFrame;
import us.ihmc.euclid.referenceFrame.tools.ReferenceFrameTools;
import us.ihmc.euclid.transform.RigidBodyTransform;
import us.ihmc.euclid.tuple3D.Vector3D;
import us.ihmc.log.LogTools;
import us.ihmc.mecano.multiBodySystem.interfaces.JointReadOnly;
import us.ihmc.mecano.multiBodySystem.interfaces.RigidBodyReadOnly;
import us.ihmc.mecano.tools.MultiBodySystemTools;
import us.ihmc.messager.javafx.JavaFXMessager;
import us.ihmc.scs2.definition.robot.CameraSensorDefinition;
import us.ihmc.scs2.definition.robot.JointDefinition;
import us.ihmc.scs2.definition.robot.RobotDefinition;
import us.ihmc.scs2.session.Session;
import us.ihmc.scs2.session.SessionMessagerAPI.Sensors.SensorMessage;
import us.ihmc.scs2.sessionVisualizer.jfx.SessionVisualizerTopics;
import us.ihmc.scs2.sessionVisualizer.jfx.tools.JavaFXMissingTools;
import us.ihmc.scs2.sessionVisualizer.jfx.tools.ObservedAnimationTimer;
import us.ihmc.scs2.sessionVisualizer.jfx.tools.SCS2JavaFXMessager;

public class CameraSensorsManager extends ObservedAnimationTimer implements Manager
{
   private final Node mainSceneRoot;
   private final YoRobotFXManager robotFXManager;

   private final List cameras = new ArrayList<>();
   private final Map> robotNameToSensorNameToManagerMap = new HashMap<>();
   private boolean sessionLoaded = false;

   private final JavaFXMessager messager;
   private final SessionVisualizerTopics topics;

   public CameraSensorsManager(Node mainSceneRoot, SCS2JavaFXMessager messager, SessionVisualizerTopics topics, YoRobotFXManager robotFXManager)
   {
      this.mainSceneRoot = mainSceneRoot;
      this.messager = messager;
      this.topics = topics;
      this.robotFXManager = robotFXManager;
      messager.addTopicListener(topics.getCameraSensorDefinitionData(), this::handleCameraSensorDefinitionMessage);
   }

   private void handleCameraSensorDefinitionMessage(SensorMessage message)
   {
      SingleCameraSensorManager manager = robotNameToSensorNameToManagerMap.getOrDefault(message.getRobotName(), Collections.emptyMap())
                                                                           .get(message.getSensorName());

      if (manager == null)
         return;

      manager.configure(message.getMessageContent());
   }

   @Override
   public void handleImpl(long now)
   {
      for (int i = 0; i < cameras.size(); i++)
      {
         cameras.get(i).update(now);
      }
   }

   @Override
   public void startSession(Session session)
   {
      sessionLoaded = false;

      for (RobotDefinition robotDefinition : session.getRobotDefinitions())
      {
         String robotName = robotDefinition.getName();
         Map robotMap = new HashMap<>();

         for (JointDefinition jointDefinition : robotDefinition.getAllJoints())
         {
            List definitions = jointDefinition.getSensorDefinitions(CameraSensorDefinition.class);

            for (CameraSensorDefinition definition : definitions)
            {
               String sensorName = definition.getName();
               RigidBodyReadOnly rootBody = robotFXManager.getRobotRootBody(robotName);
               Objects.requireNonNull(rootBody);
               JointReadOnly parentJoint = MultiBodySystemTools.findJoint(rootBody, jointDefinition.getName());
               Objects.requireNonNull(parentJoint);
               ReferenceFrame sensorFrame = ReferenceFrameTools.constructFrameWithUnchangingTransformToParent(sensorName,
                                                                                                              parentJoint.getFrameAfterJoint(),
                                                                                                              definition.getTransformToJoint());
               SingleCameraSensorManager manager = new SingleCameraSensorManager(robotName, definition, sensorFrame);
               cameras.add(manager);
               robotMap.put(sensorName, manager);
            }
         }

         if (!robotMap.isEmpty())
            robotNameToSensorNameToManagerMap.put(robotName, robotMap);
      }

      start();
      sessionLoaded = true;
   }

   @Override
   public void stopSession()
   {
      stop();
      cameras.clear();
      robotNameToSensorNameToManagerMap.clear();
      sessionLoaded = false;
   }

   @Override
   public boolean isSessionLoaded()
   {
      return sessionLoaded;
   }

   private class SingleCameraSensorManager
   {
      private final String robotName;
      private final String sensorName;
      private final ReferenceFrame sensorFrame;
      private final RotationMatrix cameraViewOrientationOffset = new RotationMatrix();
      private final RigidBodyTransform actualCameraPose = new RigidBodyTransform();
      private long period;

      private boolean enable = false;
      private long lastFrame = -1;

      private final SnapshotParameters snapshotParameters = new SnapshotParameters();
      private final PerspectiveCamera camera = new PerspectiveCamera(true);
      private final Affine cameraTransform = new Affine();

      private WritableImage image = null;
      private BufferedImage bufferedImage;

      private int width, height;

      // Temp variables used to compute the camera orientation offset.
      private final Vector3D xAxis = new Vector3D();
      private final Vector3D yAxis = new Vector3D();
      private final Vector3D zAxis = new Vector3D();

      public SingleCameraSensorManager(String robotName, CameraSensorDefinition definition, ReferenceFrame sensorFrame)
      {
         this.robotName = robotName;
         this.sensorName = definition.getName();
         this.sensorFrame = sensorFrame;

         camera.setVerticalFieldOfView(false);
         camera.getTransforms().add(cameraTransform);
         snapshotParameters.setCamera(camera);
         snapshotParameters.setDepthBuffer(true);
         snapshotParameters.setFill(Color.TRANSPARENT);
         configure(definition);
      }

      public void configure(CameraSensorDefinition definition)
      {
         enable = definition.getEnable();

         if (enable)
         {
            period = TimeUnit.MILLISECONDS.toNanos(definition.getUpdatePeriod());

            Vector3D depthAxis = definition.getDepthAxis();
            Vector3D upAxis = definition.getUpAxis();

            if (depthAxis == null || upAxis == null)
            {
               cameraViewOrientationOffset.setIdentity();
            }
            else
            {
               zAxis.setAndNormalize(depthAxis);
               yAxis.setAndNegate(upAxis);
               yAxis.normalize();
               xAxis.cross(yAxis, zAxis);
               yAxis.cross(zAxis, xAxis);

               try
               {
                  cameraViewOrientationOffset.setColumns(xAxis, yAxis, zAxis);
               }
               catch (NotARotationMatrixException e)
               {
                  LogTools.error("Erro computing the camera view direction. depth-axis: {}, up-axis: {}", depthAxis, upAxis);
                  cameraViewOrientationOffset.setIdentity();
               }
            }

            camera.setFieldOfView(Math.toDegrees(definition.getFieldOfView()));
            camera.setNearClip(definition.getClipNear());
            camera.setFarClip(definition.getClipFar());

            if (bufferedImage == null || width != definition.getImageWidth() || height != definition.getImageHeight())
            {
               width = definition.getImageWidth();
               height = definition.getImageHeight();
               image = null;
               snapshotParameters.setViewport(new Rectangle2D(0, 0, width, height));
               bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            }
         }
         else
         {
            period = -1;
            image = null;
            bufferedImage = null;
         }
      }

      public void update(long now)
      {
         if (!enable)
         {
            lastFrame = -1;
            return;
         }

         if (lastFrame == -1 || now - lastFrame >= period)
         {
            actualCameraPose.set(sensorFrame.getTransformToRoot());
            actualCameraPose.appendOrientation(cameraViewOrientationOffset);
            JavaFXMissingTools.convertRigidBodyTransformToAffine(actualCameraPose, cameraTransform);
            image = mainSceneRoot.snapshot(snapshotParameters, image);
            bufferedImage = SwingFXUtils.fromFXImage(image, bufferedImage);
            messager.submitMessage(topics.getCameraSensorFrame(), new SensorMessage<>(robotName, sensorName, bufferedImage));
            lastFrame = now;
         }
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy