1

I am creating a JavaFx project and would like to be able to draw connecting lines in a 3D model. I see simple shapes offered like cylinder, sphere, and rectangles, but no 3D lines. Is there a simple way to add lines in three dimensions instead of two dimensions in JavaFX without using a 3rd party API?

I came across this answer while researching this issue and you don't need any additional 3rd party APIs. The object passed into the method contains two Point3D objects used for the start and end points of your line. This method creates cylinders and then rotates them to the correct orientation in 3D and is based on trigonometry:


    static public Cylinder createCylinder(Segment segment) {
        // x axis vector is <1,0,0>
        // y axis vector is <0,1,0>
        // z axis vector is <0,0,1>
        // angle = arccos((P*Q)/(|P|*|Q|))
        // define a point representing the Y axis
        Point3D yAxis = new Point3D(0,1,0);
        // define a point based on the difference of our end point from the start point of our segment
        Point3D seg = segment.getEnd().subtract(segment.getStart());
        // determine the length of our line or the height of our cylinder object
        double height = seg.magnitude();
        // get the midpoint of our line segment
        Point3D midpoint = segment.getEnd().midpoint(segment.getStart());
        // set up a translate transform to move to our cylinder to the midpoint
        Translate moveToMidpoint = new Translate(midpoint.getX(), midpoint.getY(), midpoint.getZ());
        // get the axis about which we want to rotate our object
        Point3D axisOfRotation = seg.crossProduct(yAxis);
        // get the angle we want to rotate our cylinder
        double angle = Math.acos(seg.normalize().dotProduct(yAxis));
        // create our rotating transform for our cylinder object
        Rotate rotateAroundCenter = new Rotate(-Math.toDegrees(angle), axisOfRotation);
        // create our cylinder object representing our line
        Cylinder line = new Cylinder(1, height);
        // add our two transfroms to our cylinder object
        line.getTransforms().addAll(moveToMidpoint, rotateAroundCenter);
        // return our cylinder for use      
        return line;
    } // end of the createCylinder method
  • 1
    And what is your question? – José Pereda May 22 '19 at 15:44
  • I updated my question since it wasn't quite clear in the title. –  May 22 '19 at 16:10
  • It’s perfectly fine to answer your own question, but make the answer an actual Stack Overflow answer; do not answer the issue in the text of the question. – VGR May 22 '19 at 16:11
  • 1
    I'd say this is a duplicate of this [question](https://stackoverflow.com/questions/38799322/javafx-3d-transforming-cylinder-to-defined-start-and-end-points), and the solution contains precisely the original link that haven't been posted. – José Pereda May 22 '19 at 16:16
  • You are correct, but I didn't find the post in my search for an answer. –  May 22 '19 at 16:56
  • Some examples using `javafx.scene.shape.Box` are examined [here](https://stackoverflow.com/q/37075261/230513). – trashgod May 23 '19 at 00:56

1 Answers1

1

You can mess around with cylinders and stuff but you're going to be constantly scaling/rotating while adding a lot of nodes to the scene. Fine for small lines with only a few steps but for non-trivial problems you'll hit performance issues. Plus its a pain in the butt.

That's why we implemented a Polyline3D object in Fxyz3D which takes a list of points and wraps one contiguous mesh throughout the point space.

https://github.com/FXyz/FXyz/blob/master/FXyz-Core/src/main/java/org/fxyz3d/shapes/composites/PolyLine3D.java

This results in a single node added to your scene regardless of the number of points.

Example using it here: https://github.com/FXyz/FXyz/blob/master/FXyz-Samples/src/main/java/org/fxyz3d/samples/shapes/compound/PolyLines3D.java

Birdasaur
  • 736
  • 7
  • 10
  • You should add that in order to have it be a line connecting the points (as opposed to a planes connecting the points) you need to set the DrawMode of the ployline3d meshview to `DrawMode.LINE` since it will be `DrawMode.FILL` by default. The downside to this is that you wont be able to alter the line thickness (to my knowledge). Nor the mesh since its private – Matt Jan 02 '23 at 21:54
  • 1
    actually one of the parameters is a line width and the underlying code tries to construct a Triangle Tube where each point is a sort of centroid in the 3D triangle. So to have variable thickness they should use DrawMode.FILL. – Birdasaur Jan 04 '23 at 00:46
  • 1
    Also while its true the TriangleMesh object is private you can easily access it via the public MeshView object. You'll have to cast it to a TriangleMesh to be useful but its easy... ie... TriangleMesh tm = (TriangleMesh) polyLine3D.meshView.getMesh(); – Birdasaur Jan 05 '23 at 17:58