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

us.ihmc.scs2.sessionVisualizer.jfx.yoGraphic.YoPolynomialFX3D Maven / Gradle / Ivy

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

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.Mesh;
import javafx.scene.shape.MeshView;
import javafx.scene.transform.Affine;
import us.ihmc.euclid.referenceFrame.ReferenceFrame;
import us.ihmc.euclid.tools.EuclidCoreTools;
import us.ihmc.euclid.tuple3D.Point3D;
import us.ihmc.euclid.tuple3D.Vector3D;
import us.ihmc.scs2.definition.visual.SegmentedLine3DTriangleMeshFactory;
import us.ihmc.scs2.sessionVisualizer.jfx.definition.JavaFXTriangleMesh3DDefinitionInterpreter;
import us.ihmc.scs2.sessionVisualizer.jfx.managers.ReferenceFrameWrapper;
import us.ihmc.scs2.sessionVisualizer.jfx.tools.JavaFXMissingTools;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.DoubleConsumer;
import java.util.stream.Stream;

public class YoPolynomialFX3D extends YoGraphicFX3D
{
   private List coefficientsX, coefficientsY, coefficientsZ;
   private IntegerProperty numberOfCoefficientsX, numberOfCoefficientsY, numberOfCoefficientsZ;
   private Property referenceFrame;
   private DoubleProperty startTime = new SimpleDoubleProperty(0.0);
   private DoubleProperty endTime;
   private DoubleProperty size = new SimpleDoubleProperty(0.01);
   private IntegerProperty timeResolution = new SimpleIntegerProperty(50);
   private IntegerProperty numberOfDivisions = new SimpleIntegerProperty(20);

   private final Affine affine = new Affine();
   private final PhongMaterial material = new PhongMaterial();
   private final Group polynomialNode = new Group();

   private Polynomial3DData newPolynomial = null;
   private Polynomial3DData oldPolynomial = null;
   private MeshView[] newMeshViews = null;

   public YoPolynomialFX3D()
   {
      drawModeProperty.addListener((o, oldValue, newValue) ->
                                   {
                                      if (newValue == null)
                                         drawModeProperty.setValue(DrawMode.FILL);
                                      JavaFXMissingTools.setDrawModeRecursive(polynomialNode, newValue);
                                   });
      polynomialNode.getTransforms().add(affine);
      polynomialNode.idProperty().bind(nameProperty());
      polynomialNode.getProperties().put(YO_GRAPHICFX_ITEM_KEY, this);
   }

   public YoPolynomialFX3D(ReferenceFrame worldFrame)
   {
      this();
   }

   @Override
   public void render()
   {
      if (referenceFrame == null || referenceFrame.getValue() == null || referenceFrame.getValue().isRootFrame())
      {
         affine.setToIdentity();
      }
      else
      {
         JavaFXMissingTools.toJavaFX(referenceFrame.getValue().getTransformToRoot(), affine);
      }

      newPolynomial = newPolynomial3D();

      if (color != null)
         material.setDiffuseColor(color.get());

      if (newMeshViews != null)
      {
         polynomialNode.getChildren().clear();
         polynomialNode.getChildren().addAll(newMeshViews);
         newMeshViews = null;
      }
   }

   private Polynomial3DData newPolynomial3D()
   {
      Polynomial3DData polynomial3D = new Polynomial3DData();

      if (YoGraphicTools.isAnyNull(coefficientsX, coefficientsY, coefficientsZ, startTime, endTime, size))
         return polynomial3D;

      if (EuclidCoreTools.epsilonEquals(startTime.get(), endTime.get(), 1.0e-5))
         return polynomial3D;

      polynomial3D.coefficientsX = toDoubleArray(coefficientsX, numberOfCoefficientsX);
      polynomial3D.coefficientsY = toDoubleArray(coefficientsY, numberOfCoefficientsY);
      polynomial3D.coefficientsZ = toDoubleArray(coefficientsZ, numberOfCoefficientsZ);
      polynomial3D.startTime = startTime.get();
      polynomial3D.endTime = endTime.get();
      polynomial3D.size = size.get();

      return polynomial3D;
   }

   @Override
   public void computeBackground()
   {
      Polynomial3DData newPolynomialLocal = newPolynomial;
      newPolynomial = null;

      if (newPolynomialLocal == null)
      {
         return;
      }
      else if (newPolynomialLocal.coefficientsX == null || newPolynomialLocal.coefficientsY == null || newPolynomialLocal.coefficientsZ == null
               || newPolynomialLocal.coefficientsX.length == 0 || newPolynomialLocal.coefficientsY.length == 0 || newPolynomialLocal.coefficientsZ.length == 0
               || newPolynomialLocal.containsNaN())
      {
         newMeshViews = new MeshView[0];
         return;
      }

      if (newPolynomialLocal.equals(oldPolynomial) && !polynomialNode.getChildren().isEmpty())
         return;

      int timeResolution = this.timeResolution.get();
      int numberOfDivisions = this.numberOfDivisions.get();

      Point3D[] positions = new Point3D[timeResolution];
      Vector3D[] velocities = new Vector3D[timeResolution];

      for (int i = 0; i < timeResolution; i++)
      {
         double alpha = (double) i / (timeResolution - 1.0);
         double time = EuclidCoreTools.interpolate(newPolynomialLocal.startTime, newPolynomialLocal.endTime, alpha);
         positions[i] = new Point3D();
         velocities[i] = new Vector3D();

         computeAt(time, positions[i]::setX, velocities[i]::setX, newPolynomialLocal.coefficientsX);
         computeAt(time, positions[i]::setY, velocities[i]::setY, newPolynomialLocal.coefficientsY);
         computeAt(time, positions[i]::setZ, velocities[i]::setZ, newPolynomialLocal.coefficientsZ);
      }

      SegmentedLine3DTriangleMeshFactory meshGenerator = new SegmentedLine3DTriangleMeshFactory(timeResolution, numberOfDivisions, newPolynomialLocal.size);
      meshGenerator.compute(positions, velocities);
      Mesh[] meshes = Stream.of(meshGenerator.getTriangleMesh3DDefinitions())
                            .map(JavaFXTriangleMesh3DDefinitionInterpreter::interpretDefinition)
                            .toArray(Mesh[]::new);

      MeshView[] meshViews = new MeshView[meshes.length];
      DrawMode drawMode = getDrawMode() == null ? DrawMode.FILL : getDrawMode();

      for (int i = 0; i < meshes.length; i++)
      {
         meshViews[i] = new MeshView(meshes[i]);
         meshViews[i].setMaterial(material);
         meshViews[i].setDrawMode(drawMode);
         meshViews[i].idProperty().bind(nameProperty().concat(" (").concat(Integer.toString(i)).concat(")"));
      }

      oldPolynomial = newPolynomialLocal;
      newMeshViews = meshViews;
   }

   private static class Polynomial3DData
   {
      private double[] coefficientsX, coefficientsY, coefficientsZ;
      private double startTime = Double.NaN, endTime = Double.NaN;
      private double size = Double.NaN;

      public boolean containsNaN()
      {
         if (coefficientsX != null)
         {
            for (double coeff : coefficientsX)
            {
               if (Double.isNaN(coeff))
                  return true;
            }
         }

         if (coefficientsY != null)
         {
            for (double coeff : coefficientsY)
            {
               if (Double.isNaN(coeff))
                  return true;
            }
         }

         if (coefficientsZ != null)
         {
            for (double coeff : coefficientsZ)
            {
               if (Double.isNaN(coeff))
                  return true;
            }
         }

         return Double.isNaN(startTime) || Double.isNaN(endTime) || Double.isNaN(size);
      }

      @Override
      public boolean equals(Object object)
      {
         if (object == this)
         {
            return true;
         }
         else if (object instanceof Polynomial3DData)
         {
            Polynomial3DData other = (Polynomial3DData) object;

            if (!Arrays.equals(coefficientsX, other.coefficientsX))
               return false;
            if (!Arrays.equals(coefficientsY, other.coefficientsY))
               return false;
            if (!Arrays.equals(coefficientsZ, other.coefficientsZ))
               return false;
            if (startTime != other.startTime)
               return false;
            if (endTime != other.endTime)
               return false;
            if (size != other.size)
               return false;

            return true;
         }
         else
         {
            return false;
         }
      }
   }

   private static double[] toDoubleArray(List list, IntegerProperty size)
   {
      if (size != null && size.get() < list.size())
         list = list.subList(0, size.get());

      return list.stream().mapToDouble(DoubleProperty::get).toArray();
   }

   private static void computeAt(double time, DoubleConsumer positionConsumer, DoubleConsumer velocityConsumer, double[] coefficients)
   {
      double[] timePowers = computeTimePowers(time, coefficients.length);
      double position = 0.0;
      double velocity = 0.0;

      for (int i = 0; i < coefficients.length; i++)
         position += timePowers[i] * coefficients[i];
      for (int i = 1; i < coefficients.length; i++)
         velocity += i * timePowers[i - 1] * coefficients[i];

      positionConsumer.accept(position);
      velocityConsumer.accept(velocity);
   }

   private static double[] computeTimePowers(double t, int n)
   {
      if (n == 0)
         return new double[0];

      double[] timePowers = new double[n];

      timePowers[0] = 1.0;

      for (int i = 1; i < n; i++)
         timePowers[i] = timePowers[i - 1] * t;

      return timePowers;
   }

   public void setCoefficientsX(List coefficientsX)
   {
      this.coefficientsX = coefficientsX;
   }

   public void setCoefficientsY(List coefficientsY)
   {
      this.coefficientsY = coefficientsY;
   }

   public void setCoefficientsZ(List coefficientsZ)
   {
      this.coefficientsZ = coefficientsZ;
   }

   public void setNumberOfCoefficientsX(IntegerProperty numberOfCoefficientsX)
   {
      this.numberOfCoefficientsX = numberOfCoefficientsX;
   }

   public void setNumberOfCoefficientsX(int numberOfCoefficientsX)
   {
      setNumberOfCoefficientsX(new SimpleIntegerProperty(numberOfCoefficientsX));
   }

   public void setNumberOfCoefficientsY(IntegerProperty numberOfCoefficientsY)
   {
      this.numberOfCoefficientsY = numberOfCoefficientsY;
   }

   public void setNumberOfCoefficientsY(int numberOfCoefficientsY)
   {
      setNumberOfCoefficientsY(new SimpleIntegerProperty(numberOfCoefficientsY));
   }

   public void setNumberOfCoefficientsZ(IntegerProperty numberOfCoefficientsZ)
   {
      this.numberOfCoefficientsZ = numberOfCoefficientsZ;
   }

   public void setNumberOfCoefficientsZ(int numberOfCoefficientsZ)
   {
      setNumberOfCoefficientsZ(new SimpleIntegerProperty(numberOfCoefficientsZ));
   }

   public void setReferenceFrame(ReferenceFrameWrapper referenceFrame)
   {
      setReferenceFrame(new SimpleObjectProperty<>(referenceFrame));
   }

   public void setReferenceFrame(Property referenceFrame)
   {
      this.referenceFrame = referenceFrame;
   }

   public void setStartTime(DoubleProperty startTime)
   {
      this.startTime = startTime;
   }

   public void setStartTime(double startTime)
   {
      setStartTime(new SimpleDoubleProperty(startTime));
   }

   public void setEndTime(DoubleProperty endTime)
   {
      this.endTime = endTime;
   }

   public void setEndTime(double endTime)
   {
      setEndTime(new SimpleDoubleProperty(endTime));
   }

   public void setSize(DoubleProperty size)
   {
      this.size = size;
   }

   public void setSize(double size)
   {
      setSize(new SimpleDoubleProperty(size));
   }

   public void setTimeResolution(int timeResolution)
   {
      setTimeResolution(new SimpleIntegerProperty(timeResolution));
   }

   public void setTimeResolution(IntegerProperty timeResolution)
   {
      this.timeResolution = timeResolution;
   }

   public void setNumberOfDivisions(int numberOfDivisions)
   {
      setNumberOfDivisions(new SimpleIntegerProperty(numberOfDivisions));
   }

   public void setNumberOfDivisions(IntegerProperty numberOfDivisions)
   {
      this.numberOfDivisions = numberOfDivisions;
   }

   @Override
   public void clear()
   {
      coefficientsX = null;
      coefficientsY = null;
      coefficientsZ = null;
      numberOfCoefficientsX = null;
      numberOfCoefficientsY = null;
      numberOfCoefficientsZ = null;
      referenceFrame = null;
      startTime = null;
      endTime = null;
      size = null;
      color = null;
   }

   @Override
   public YoGraphicFX clone()
   {
      YoPolynomialFX3D clone = new YoPolynomialFX3D();
      clone.setName(getName());
      clone.setCoefficientsX(new ArrayList<>(coefficientsX));
      clone.setCoefficientsY(new ArrayList<>(coefficientsY));
      clone.setCoefficientsZ(new ArrayList<>(coefficientsZ));
      clone.setNumberOfCoefficientsX(numberOfCoefficientsX);
      clone.setNumberOfCoefficientsY(numberOfCoefficientsY);
      clone.setNumberOfCoefficientsZ(numberOfCoefficientsZ);
      clone.setReferenceFrame(referenceFrame);
      clone.setStartTime(startTime);
      clone.setEndTime(endTime);
      clone.setSize(size);
      clone.setTimeResolution(timeResolution);
      clone.setNumberOfDivisions(numberOfDivisions);
      clone.setColor(color);
      return clone;
   }

   public List getCoefficientsX()
   {
      return coefficientsX;
   }

   public List getCoefficientsY()
   {
      return coefficientsY;
   }

   public List getCoefficientsZ()
   {
      return coefficientsZ;
   }

   public IntegerProperty getNumberOfCoefficientsX()
   {
      return numberOfCoefficientsX;
   }

   public IntegerProperty getNumberOfCoefficientsY()
   {
      return numberOfCoefficientsY;
   }

   public IntegerProperty getNumberOfCoefficientsZ()
   {
      return numberOfCoefficientsZ;
   }

   public Property getReferenceFrame()
   {
      return referenceFrame;
   }

   public DoubleProperty getStartTime()
   {
      return startTime;
   }

   public DoubleProperty getEndTime()
   {
      return endTime;
   }

   public DoubleProperty getSize()
   {
      return size;
   }

   public IntegerProperty getTimeResolution()
   {
      return timeResolution;
   }

   public IntegerProperty getNumberOfDivisions()
   {
      return numberOfDivisions;
   }

   @Override
   public Node getNode()
   {
      return polynomialNode;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy