Node:Declaring and Initializing Paths, Next:, Previous:Paths, Up:Paths



Declaring and Initializing Paths

There are various ways of declaring and initializing Paths. The simplest is to use the constructor taking two Point arguments:

     Point A;
     Point B(2, 2);
     Path p(A, B);
     p.draw();
     


[Figure 9. Not displayed.]

Fig. 9.

Paths created in this way are important, because they are guaranteed to be linear, as long as no operations are performed on them that cause them to become non-linear. Linear Paths can be used to find intersections. See Path Intersections.

Paths can be declared and initialized using a single connector and an arbitrary number of Points. The first argument is a string specifying the connector. It is followed by a bool, indicating whether the Path is cyclical or not. Then, an arbitrary number of pointers to Point follow. The last argument must be 0.1

     Point p[3];
     p[0].shift(1);
     p[1].set(1, 2, 2);
     p[2].set(1, 0, 2);
     Path pa("--", true, &p[0], &p[1], &p[2], 0);
     pa.draw();
     


[Figure 10. Not displayed.]

Fig. 10.

Another constructor must be used for Paths with more than one connector and an arbitrary number of Points. The argument list starts with a pointer to Point, followed by string for the first connector. Then, pointer to Point arguments alternate with string arguments for the connectors. Again, the list of arguments ends in 0. There is no need for a bool to indicate whether the Path is cyclical or not; if it is, the last non-zero argument will be a connector, otherwise, it will be a pointer to Point.

     Point p[8];
     p[0].set(-2);
     p[1].set(2);
     p[2].set(0, 0, -2);
     p[3].set(0, 0, 2);
     p[4] = p[0].mediate(p[2]);
     p[5] = p[2].mediate(p[1]);
     p[6] = p[1].mediate(p[3]);
     p[7] = p[3].mediate(p[0]);
     p[4] *= p[5] *= p[6] *= p[7].shift(0, 1);
     Path pa(&p[0], "..", &p[4], "...", &p[2],
             "..", &p[5], "...", &p[1], "..", &p[6],
             "...", &p[3], "..", &p[7], "...", 0);
     pa.draw();
     


[Figure 11. Not displayed.]

Fig. 11.

As mentioned above (see Accuracy), specifying connectors is problematic for three-dimensional Paths, because MetaPost ultimately calculates the "most pleasing curve" based on the two-dimensional points in the MetaPost code written by 3DLDF.2 For this reason, it's advisable to avoid specifying curl, dir, tension or control points in connectors. The more Points a (3DLDF) Path or other object contains, the less freedom MetaPost has to determine the (MetaPost) path through them. So a three-dimensional Path or other object in 3DLDF should have enough Points to ensure satisfactory results. The Path in [the previous figure] does not really have enough Points. It may require some trial and error to determine what a sufficient number of Points is in a given case.

Paths are very flexible, but not always convenient. 3DLDF provides a number of classes representing common geometric Shapes, which will be described in subsequent sections, and I intend to add more in the course of time.


Footnotes

  1. It's easy to forget to use Point* arguments, rather than plain Point arguments, and to forget to end the list of arguments with 0. If plain Point arguments are used, compilation fails with GCC. With the DEC compiler, compilation succeeds, but a memory fault error occurs at run-time. If the argument list doesn't end in 0, neither compiler signals an error, but a memory fault error always occurs at run-time.

  2. Knuth, The METAFONTbook, Chapter 14, p. 127.