Points

A point is a 2D or 3D object that has a location, but no surface, or volume. An OrientedPoint is a point with an orientation. This orientation describes the rotations, relative to the reference orientation of the object, that must be applied to draw an object at its location.

In the code examples below, please note that the djutils Point2d class is written with a lower-case d; unlike the Point2D class in java.awt.geom.

To create a 2D point and print it write:

    Point2d point2d = new Point2d(123.45, 234.56);
    System.out.println(point2d);

This outputs:

Point2d [x=123.450000, y=234.560000]

The individual coordinates can be retrieved by calling the getX and getY methods, but they are also directly accessible as point2d.x and point2d.y. The latter ways are not significantly better or faster, but your source code tends to be shorter and more readable and, when debugging the code, the debugger will not have to step into those getters.

Like all Drawable objects the Point2d class also implements the getPoints method which creates an Iterator<Point2d> that generates all points of the object in sequence. For a Point that Iterator will only provide one object. The Point2d object also implements the getBounds method that creates a Bounds2d object.

There are three constructors for Point2d objects:

    Point2d point1 = new Point2d(123.45, 234.56);
    System.out.println(point1);
    double[] coordinates = new double[] { 123.45, 234.56 };
    Point2d point2 = new Point2d(coordinates);
    System.out.println(point2);
    java.awt.geom.Point2D awtPoint2D = new java.awt.geom.Point2D.Double(123.45, 234.56);
    Point2d point3 = new Point2d(awtPoint2D);
    System.out.println(point3);
    java.awt.geom.Point2D awtPoint2DCopy = point3.toPoint2D();
    System.out.println(awtPoint2DCopy);

Outputs:

Point2d [x=123.450000, y=234.560000]
Point2d [x=123.450000, y=234.560000]
Point2d [x=123.450000, y=234.560000]

That last example created a djutils Point2d object from a java.awt.geom.Point2D object. The inverse is also possible:

    java.awt.geom.Point2D awtPoint2DCopy = point2d.toPoint2D();

Which outputs:

Point2D.Double[123.45, 234.56]

With two Point2d objects many operations become possible:

    Point2d point2d = new Point2d(123.45, 234.56);
    Point2d secondPoint2d = new Point2d(234.56, 345.78);
    System.out.println("Direction to: " + point2d.directionTo(secondPoint2d));
    System.out.println("Distance: " + point2d.distance(secondPoint2d));
    System.out.println("Distance squared " + point2d.distanceSquared(secondPoint2d));
    System.out.println("Interpolation at fraction 0.3: " + point2d.interpolate(secondPoint2d, 0.3));

This outputs:

Direction to: 0.7858929233984577
Distance: 157.21106990285384
Distance squared 24715.320499999994
Interpolation at fraction 0.3: Point2d [x=156.783000, y=267.926000]

The direction is in radians where the X-axis direction is 0, and the Y-axis direction is π/2; etc. The distance is computed using the Math.hypot method; this suffers less from loss of precision problems than taking the square root of the squares of the x-difference and the y-difference. The distanceSquared is the sum of the squares of the differences in x and y. The interpolate method can just as easy perform extrapolation. When the fraction (0.3 in the example) is 0.0; a new Point2d at the same location the existing Point2d is created. fraction 1.0 returns a new Point2d at the location of secondPoint2d. Fraction -1.0 creates a new Point2d that is the distance between the points before point2d; etc.

Computations with double precision coordinates generally leads to rounding errors. In some cases it is necessary to compare points allowing for some loss of precision. This can be done with the epsilonEquals method:

    Point2d point1 = new Point2d(123.45, 234.56);
    System.out.println("Almost equals to another Point2d: " + point1.epsilonEquals(new Point2d(123, 235), 0.5));

This example prints:

Almost equals to another Point2d: true

A Point can not be modified (it is immutable), but there are various methods that create a translated, normalized, or scaled version of a Point.

    System.out.println("The point: " + point1);
    System.out.println("The point translated over 10, -20: " + point1.translate(10, -20));
    System.out.println("The point scaled by 2: " + point1.scale(2.0));
    System.out.println("The point negated: " + point1.neg());
    System.out.println("The point normalized: " + point1.normalize());
    System.out.println("The point with absolute values: " + point1.abs());
    System.out.println("The point negated, then absolute: " + point1.neg().abs());

Output:

The point: Point2d [x=123.450000, y=234.560000]
The point translated over 10, -20: Point2d [x=133.450000, y=214.560000]
The point scaled by 2: Point2d [x=246.900000, y=469.120000]
The point negated: Point2d [x=-123.450000, y=-234.560000]
The point normalized: Point2d [x=0.465739, y=0.884922]
The point with absolute values: Point2d [x=123.450000, y=234.560000]
The point negated, then absolute: Point2d [x=123.450000, y=234.560000]

A Point2d has two directly accessible fields: x and y. There are also getters for these: getX() and getY(). Using the former access method leads to slightly shorter code with fewer parenthesis. When stepping through code with a debugger, using the former makes life a bit easier. With modern compilers, we do not believe there is a runtime speed advantage in using the fields directly.

A Point3d is a Point with three coordinates (x, y, z). A Point3d is very similar to a Point2d. The main difference is that everything is done with three coordinates. The directionTo method does not make much sense. It is replaced by two methods: horizontalDirection (the angle from the X-axis) and verticalDirection (the angle from the Z-axis). The z coordinate can be accessed directly as the z field, or with the getZ() getter method.

An OrientedPoint2d is a Point2d with an direction value. This direction is a rotation from the X-axis. The X-axis has rotation 0, the Y-axis has rotation π/2, etc.. The rotation of the OrientedPoint2d is totally independent of the x and y values. The rotation can be retrieved by directly accessing the dirZ field, or calling the getDirZ() method. An OrientedPoint2d can be used to describe the position and rotation of an object in 2D-space.

    OrientedPoint2d orientedPoint2d = new OrientedPoint2d(123.45, 234.56, -0.2);
    System.out.println(orientedPoint2d);

Prints

OrientedPoint2d [x=123.450000, y=234.560000, rot=-0.200000]

There is also an OrientedPoint3d class. This object stores x, y, z, dirX, dirY, dirZ. The dirZ property is exactly like the dirZ property of an OrientedPoint2d. The dir values can be interpreted as roll, pitch and jaw. There are several such naming conventions depending on the field of use: see Wikipedia It is important to understand that combining rotations is not commutative. The OriendedPoint3d class does not define the order in which these rotations are to be applied. When you use Oriented points in a project, you should clearly document the ordering that your project uses.