by Rahel Lüthy

March 22, 2015

I have no experience in 3D programming whatsoever. Last week, I took my first steps in JavaFX 3D, but hit a wall when I wanted to draw a line between two points: There is no `Line`

shape! The only out-of-the-box `Shape3D`

classes are `Box`

, `Cylinder`

, `Sphere`

, and `MeshView`

– wow…

Well, it shouldn’t be too difficult to connect the points with a slender cylinder, right?

I was wrong, it took me an *embarrassingly* long time to get the trigonometry right :-)

Here’s my magic crutch:

```
public Cylinder createConnection(Point3D origin, Point3D target) {
Point3D yAxis = new Point3D(0, 1, 0);
Point3D diff = target.subtract(origin);
double height = diff.magnitude();
Point3D mid = target.midpoint(origin);
Translate moveToMidpoint = new Translate(mid.getX(), mid.getY(), mid.getZ());
Point3D axisOfRotation = diff.crossProduct(yAxis);
double angle = Math.acos(diff.normalize().dotProduct(yAxis));
Rotate rotateAroundCenter = new Rotate(-Math.toDegrees(angle), axisOfRotation);
Cylinder line = new Cylinder(1, height);
line.getTransforms().addAll(moveToMidpoint, rotateAroundCenter);
return line;
}
```

To illustrate what’s going on, I created a 2D representation of all individual steps, starting off with the creation of the cylinder. By default, its center is placed at the origin:

The `moveToMidpoint`

transformation moves its center to the final location (the yellow midpoint in the above image):

And finally, the `rotateAroundCenter`

transformation corrects the cylinder’s direction:

Obviously, the tricky part is finding the proper axis and angle of rotation. Both are calculated relative to the `yAxis`

because of the cylinder’s initial direction. The `axisOfRotation`

must be perpendicular to the plane defined by the `yAxis`

and the `diff`

vector. To find such a perpendicular vector, we can (by definition) calculate the cross product of the two vectors. In the 2D case, the result is equivalent to the z-axis, but in 3D it may be tilted.

The angle is calculated based on the dot product (aka scalar product) of the two vectors, which is defined by

`A • B = |A| |B| cos(alpha)`

If `A`

and `B`

are both unit vectors, this becomes

`A • B = cos(alpha)`

which we can resolve to

`alpha = acos(A • B)`

That’s it!