Write a library module to implement support for planar point coordinate geometry.

Points are represented in the plane by their horizontal and vertical coordinates (x, y). This representation can be rendered in Modula-2 as a one-dimensional array of length two.

TYPEPoint =ARRAY[1 .. 2]OFREAL;

Note that the word *dimension* in this context refers to the array, not to the geometry. There are several useful operations relating to single points. These fall into two main categories:

*Computations*:

Three of these will be considered here; they arise in connection with the line segment joining the point with the origin.

Both the length *r* of this line segment, and also the angle that it makes with the positive x-axis are of interest in various problems. It may also be necessary to construct the rectangular coordinates (x, y) of a point from a knowledge of the length *r* and the angle (also called its polar coordinates). These are expressed as follows:

*Transformations*:

These involve moving the point P according to some determined pattern. The first such patterns involve various *reflections* or *symmetries*. These can be done in the x-axis to yield (x, -y), in the y-axis to yield (-x, y), across the origin yielding (-x, -y), or in the line y = x producing (y, x). The possibilities are indicated in the figure 6.14 below:

The second type of transformation *scales* the point in such a way that the length of the line segment it defines is multiplied by some number, *s* called the *scale factor*. If this is done, the x-coordinate and y-coordinate of the new point Q are also multiplied by the same scale factor, but the angle is unchanged.

A third type of transformation on the point is via the segment it defines and consists of a rotation through an angle ø. The new point obtained is at the same distance r from the origin as the original, but its segment subtends an angle q + ø from the positive x-axis.

The fourth and last transformation is a simple shift or *translation* of the point by *h* units horizontally, and *k* units vertically. That is, the point that starts at (x, y) is transformed to the point (x + h, y + k).

Finally, in order to maintain the integrity of items of type *Point* as an abstract data type, it is necessary to make provision for client programs to assign values to (and obtain values from) the coordinates of a point without directly using the knowledge of its structure as an array. This concern for integrity of the ADT necessitates three more procedures: *assign*, *abscissa*, and *ordinate*.

Thus the abstract data type *Point* and the operations and transformations on it may be defined in Modula-2 as follows:

DEFINITIONMODULEPoints; (* angles are measured in radians counterclockwise from the positive x-axis *)TYPEPoint =ARRAY[1 .. 2]OFREAL;PROCEDUREassign (x, y :REAL) : Point; (* returns the abstract point with coordinates x and y *)PROCEDUREabscissa (p : Point) :REAL; (* returns the first, or x-coordinate of the point *)PROCEDUREordinate (p : Point) :REAL; (* returns the second, or y-coordinate of the point *)PROCEDUREabs (p : Point) :REAL; (* returns the distance from the point to the origin *)PROCEDUREarg (p : Point) :REAL; (* returns the angle to the positive x-axis subtended by a line segment from the origin to the point measured in the range 0 to 2¼lt;¼gt; radians *)PROCEDUREpolarToRect (abs, arg :REAL) : Point; (* returns the point with the given absolute value and argument *)PROCEDUREreflectX (p : Point) : Point; (* returns the reflection of the point in the x-axis *)PROCEDUREreflectY (p: Point ) : Point; (* returns the reflection of the point in the y-axis *)PROCEDUREreflect0 (p : Point) : Point; (* returns the reflection of the point in the origin *)PROCEDUREreflect45 (p : Point) : Point; (* returns the reflection of the point in the line y = x *)PROCEDUREscale (p : Point; scaleFactor :REAL) : Point; (* returns the point with the same argument as p and its absolute value multiplied by the scale factor *)PROCEDURErotate (p : Point; rotAngle :REAL) : Point; (* returns the point with the same absolute value as p and with its argument increased by rotAngle *)PROCEDUREtranslate (p : Point; deltaX, deltaY :REAL) : Point; (* returns the point obtained by shifting the given point deltaX horizontally and deltaY vertically *)ENDPoints.IMPLEMENTATIONMODULEPoints; (* original by R. Sutcliffe corrections by G. Tischer 1995 05 09 *)FROMRealMathIMPORTsqrt, arctan, sin, cos, pi;PROCEDUREassign (x, y :REAL) : Point;VARtemp : Point;BEGINtemp [1] := x; temp [2] := y;RETURNtemp;ENDassign;PROCEDUREabscissa (p : Point) :REAL;BEGINRETURNp [1];ENDabscissa;PROCEDUREordinate (p : Point) :REAL;BEGINRETURNp [2];ENDordinate;PROCEDUREabs (p : Point ) :REAL;BEGINRETURNsqrt (p[1] * p[1] + p[2] * p[2]);ENDabs;PROCEDUREarg (p : Point) :REAL; (* if both coordinates are zero, the angle is not defined, but this procedure will return zero. No errors are generated. *)VARtemp :REAL;BEGINIFp[1] = 0.0THENIFp[2] > 0.0 (* case of point on positive y-axis *)THENRETURNpi / 2.0;ELSIFp[2] < 0.0THENRETURN1.5* pi (* case of point on negative y-axis *)ELSERETURN0.0;END;END; temp:= arctan (p[2]/p[1]); (* returns first and fourth quadrants only *)IFp[1] > 0.0THENIFp[2] >= 0.0THENRETURNtemp;ELSERETURN(2.0 * pi) + temp;END; (*IF*)ELSERETURNpi + temp (* adjust for second and third quadrants *)END;ENDarg;PROCEDUREpolarToRect (abs, arg :REAL) : Point;VARtemp : Point;BEGINtemp [1] := abs * (cos (arg)); temp [2] := abs * (sin (arg));RETURNtemp;ENDpolarToRect;PROCEDUREreflectX (p : Point ) : Point;BEGINRETURNassign (p[1], -p[2]);ENDreflectX;PROCEDUREreflectY (p: Point ) : Point;BEGINRETURNassign (-p[1], p[2]);ENDreflectY;PROCEDUREreflect0 (p : Point) : Point;BEGINRETURNassign (-p[1], -p[2]);ENDreflect0;PROCEDUREreflect45 (p : Point) : Point;BEGINRETURNassign (p[2], p[1]);ENDreflect45;PROCEDUREscale (p : Point; scaleFactor :REAL) : Point;BEGINRETURNassign (scaleFactor * p[1], scaleFactor * p[2]);ENDscale;PROCEDURErotate (p : Point; rotAngle :REAL) : Point;BEGINRETURNpolarToRect (abs (p), arg (p) + rotAngle)ENDrotate;PROCEDUREtranslate (p : Point; deltaX, deltaY :REAL) : Point;BEGINRETURNassign (p [1] + deltaX, p [2] + deltaY);ENDtranslate;ENDPoints.

Write a routine to compute the distance between two points.

This problem can be solved, as suggested in exercise 4.19 using the formula

and employing the coordinates of the points directly. In the context of this discussion, having imported the type *Point* and the procedure *sqrt* into the surrounding module, the requested routine could be expressed as:

PROCEDUREdistance (p1, p2 : Point) :REAL;VARdeltaX, deltaY :REAL;BEGINdeltaX := p2 [1] - p1 [1]; deltaY := p2 [2] - p1 [2];RETURNsqrt (deltaX * deltaX + deltaY * deltaY);ENDdistance;

A second approach is more complicated in some ways, but trades off some additional mathematical steps for a more abstract view of the type *Point* within the procedure. Rather than have the procedure made direct use of the structure of the type *Point* by basing its computations on the coordinates of the point, it can make the calculation by using facilities provided by the module *Points* alone. This approach is consistent with the inclusion in the module of procedures to extract the coordinates without directly using the data structure. In this particular instance the law of cosines is exploited. (A proof of the law of cosines is not presented here).

The Law of Cosines: In any triangle ABC with sides opposite the angles labelled a, b, and c,

Here, the measure of angle C is - ø and the distance between the two points is the length of the third side in a triangle whose other sides are the segments from the origins to the points A and B. Thus one could write

MODULEPointToPoint; (* Written by R.J. Sutcliffe *) (* to test the module Points *) (* using ISO Modula-2 *) (* last revision 1993 03 01 *)FROMPointsIMPORTPoint, arg, abs;FROMRealMathIMPORTcos, sqrt;FROMSTextIOIMPORTWriteString, WriteLn, ReadChar, SkipLine;FROMSRealIOIMPORTReadReal, WriteFixed;FROMSIOResultIMPORTReadResult, ReadResults;PROCEDUREGetReal (VARnumToGet :REAL);VARtempResult : ReadResults;BEGINREPEATWriteString ("Please type in a real number ===> "); ReadReal (numToGet); tempResult := ReadResult (); SkipLine; (* swallow line marker *) WriteLn;UNTILtempResult = allRight;ENDGetReal;PROCEDUREDistByCosines (side1, side2, angle :REAL) :REAL;BEGINRETURNsqrt (side1 * side1 + side2 * side2 - 2.0 * side1 * side2 * cos (angle));ENDDistByCosines;VARpoint1, point2 : Point; a, b, c, C :REAL; key :CHAR;BEGINWriteString ("This program computes the distance "); WriteString ("between two points"); WriteLn; WriteString ("in the coordinate plane."); WriteLn; WriteLn; WriteString ("First point, X coordinate: "); GetReal (point1 [1]); WriteString (" Y coordinate: "); GetReal (point1 [2]); WriteString ("Second point, X coordinate: "); GetReal (point2 [1]); WriteString (" Y coordinate: "); GetReal (point2 [2]); a := abs (point1); b := abs (point2); C := arg (point1) - arg (point2); c := DistByCosines (a, b, C); WriteString ("The distance between the two points is "); WriteFixed (c, 5, 0); WriteString (" units."); WriteLn; WriteString ("Press a key to continue ==>"); ReadChar (key);ENDPointToPoint.

This program computes the distance between two points in the coordinate plane. First point, X coordinate: Please type in a real number ===>1.0Y coordinate: Please type in a real number ===>5.5Second point, X coordinate: Please type in a real number ===>21.0Y coordinate: Please type in a real number ===>26.5The distance between the two points is 29.00000 units.