§1  3DLDF-1.1.5.1  COPYRIGHT AND LICENSE 1

1. Copyright and License. Copyright \begin{matrix}c \\ ◯ \end{matrix} 2003, 2004, 2005, 2006, 2007 The Free Software Foundation

See the section ⟨ GNU Free Documentation License 1561 ⟩ for the copying conditions that apply to this document.

The program GNU 3DLDF documented here is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. See the section ⟨ GNU General Public License 1562 ⟩ in this document.

GNU 3DLDF is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with GNU 3DLDF; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

GNU 3DLDF is a GNU package. It is part of the GNU Project of the Free Software Foundation and is published under the GNU General Public License. See the website http://www.gnu.org for more information. GNU 3DLDF is available for downloading from http://www.gnu.org/software/3dldf/LDF.html. It is also available from http://www.dante.de/software/ctan/, the Dante www-server and from

http://wwwuser.gwgd.de/~lfinsto1, the author’s website.

Please send bug reports to:

lfinsto1@gwdg.de

The mailing list help-3DLDF@gnu.org is available for people to ask other users for help. The mailing list info-3DLDF@gnu.org is for sending announcements to users. To subscribe to these mailing lists, send an email with “subscribe ⟨email-address⟩” as the subject.

The author can be contacted at:

Laurence D. Finston

c/o Free Software Foundation, Inc.

51 Franklin St, Fifth Floor

Boston, MA 02110-1301

USA

lfinsto1@gwdg.de

s246794@stud.uni-goettingen.de

  Web site: http:://wwwuser.gwdg.de/~lfinsto1

2. Introduction (3DLDF.web).

This book contains the program code of 3DLDF, along with explanations. For information on using 3DLDF see the 3DLDF User and Reference Manual, which should have been in the distribution along with this book.

3DLDF is a free software package for three-dimensional drawing written by Laurence D. Finston, who is also the author of this manual. It is written in C^{++} using CWEB and it outputs MetaPost code.

In the text sections of the CWEB documentation, I note things about C^{++} that may be of interest even if they are obvious to people with experience.

The various files that make up 3DLDF are ctangled and compiled separately (see the chapter “Compiling” in the 3DLDF User and Reference Manual) and the resulting object files are then linked. However, the file 3DLDF.web, which contains no C^{++} code and is not ctangled, includes the other files, so that cweave processes them as if they were all one file.

2  INTRODUCTION (3DLDF.WEB)  3DLDF-1.1.5.1 §2
To write my  files, I wrote a  for Emacs and a number of Emacs-Lisp functions to go with

it. It is not currently included in the 3DLDF distribution (Version 1.1.5.1), but I may include it in a later version. However, GNU is at work at an official cweb-mode of its own, so you might want to use it instead, if it’s available.

Plurals of types are typeset with the “s” in the same font as the type, e.g., “Points” and not “Points”. It’s not considered good typographical practice to typeset words with letters from different fonts. The second example does have the advantage that it’s somewhat clearer what the actual name of the type is, but I think the first argument is weightier.

See http://www-cs-faculty.stanford.edu/knuth/cweb.html for more information about CWEB. The

WEB (for Pascal) and CWEB packages are available from the CTAN archive, ftp.dante.de and

http:://www.dante.de.

Donald Knuth’s books TEX: The Program and METAFONT: The Program each include a section “How to read a WEB”, which may be helpful.

Log

[LDF 2002.11.18.] Changed name of this file from cweavedriver.web to cwdriver.web. It now has fewer than 8 letters and can be used under DOS.

[LDF 2003.08.16.] Changed name of this file from cwdriver.web to 3DLDF.web sometime since 2002.11.18. Forgot to note it here.

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

3. Formatting commands. cweave formats “ ” as “≡”, “ ” as “≠”, and “ ” as “¬”. Programmers who use these tokens must type them as “ ”, “ , and “!”.

The following formatting commands are for types defined in C^{++} or in the C^{++} Standard Library, but not handled correctly by cweave.

format bitset int
format bool int
format bools bool
format ifstream int
format key type int
format mapped type int
format map int
format ofstream int
format stat int
format stringstream int
format numeric limits int
format pair int
format string char
format tm int
format valarray int
format vector int

§4  3DLDF-1.1.5.1  FORMATTING COMMANDS 3

4. This section contains commands for inputting the CWEB source files, which are invisible in the cweave output.

5. Preprocessor variables and library files (loader.web). [LDF 2002.10.15.] It would, of course, be possible to put this code into a file directly, but it’s convenient to have a CWEB file so that it can be along with the rest of 3DLDF.

[LDF 2003.07.18.] Set the preprocessor macro to 1 in order to compile using gcc version 3.3 20030226 (prerelease) (SuSE Linux). Set it to 0 in order to compile using GCC version 2.95.3 20010315 (SuSE). This can be faster than using GCC 3.3, especially with respect to linking.

Log

[LDF 2003.08.21.] Now including plfmvar.h. It contains #define and #undef preprocessor commands for conditional compilation. There’s a different version of this file in each of the subdirectories used for compiling with a different combination of operating system, compiler, and compiler version.

[LDF 2003.07.25.] Modified the conditional constructions governing compilation slightly.

[LDF 2003.08.14.] Now including getopt.h for the GCC versions under Linux. It’s for processing the command line options.

[LDF 2003.08.14.] Now including streambuf.h, if is defined, otherwise ios. This is for stream formatting.

[LDF 2003.08.29.] Removed getopt.h to main.web, because it’s only used there.

[LDF 2003.09.03.] Added #define in order to be able to conditionally include plfmvar.h. The latter is not included in the version for distribution. Instead, the preprocessor variables are defined or undefined here.

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

⟨ Version control identifier 5 ⟩ ≡

static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

See also sections 13, 53, 63, 76, 93, 164, 241, 250, 307, 635, 659, 696, 982, 1017, 1099, 1141, 1273, 1317, 1331, 1443, 1451, 1470,

1536, and 1543. This code is used in sections 11, 51, 61, 74, 91, 162, 239, 248, 305, 633, 657, 694, 980, 1015, 1097, 1139, 1271, 1315, 1329, 1441,

1449, 1468, 1534, 1541, and 1558.

6. Configuration file. This section includes config.h, which is generated by . This is new in 3DLDF 1.1. The script generated by Autoconf tests whether certain library files are present, and defines preprocessor variables in config.h accordingly. These can be used for conditionally compiling code, so that library files are only included if they are really present. However, it will be necessary to add code for handling the case that they aren’t present. I haven’t done this yet, although I have put in conditional code using these variables in a couple of places. TO DO: Work on this. [LDF 2003.11.12.]

Autoconf does not per default check the version of the compiler that’s used, and I’m not sure whether this would really be sensible. 3DLDF already contains conditionally compiled code based on whether the DEC C^{++} compiler, or the GNU C^{++} compiler (GCC) version 2.95 or version 3.3 is used. If the DEC compiler is used, the preprocessor variables or must be undefined by hand below. It defines itself. If GCC is used, one of them must be defined, and the other undefined. Per default, is defined and is undefined. This is because GCC 3.3 is, in general, an improvement over GCC 2.95. However, I usually use GCC 2.95 myself, because linking is significantly faster on the computer I use. [LDF 2003.11.12.]

4  CONFIGURATION FILE  3DLDF-1.1.5.1 §6

[LDF 2003.12.17.] config.h is now not included if I’m with the DEC C^{++} compiler. This is because because building with Autoconf, etc., doesn’t work on the DEC Alpha machine I’m using.

⟨ Include files 6 ⟩ ≡ #ifndef #include #endif

See also sections 7, 8, 9, 14, 54, 64, 77, 94, 165, 242, 251, 308, 636, 660, 697, 983, 1018, 1100, 1142, 1274, 1318, 1332, 1444,

1452, 1471, 1537, and 1544. This code is used in sections 12, 51, 61, 74, 91, 162, 239, 248, 305, 633, 657, 694, 980, 1015, 1097, 1139, 1271, 1315, 1329, 1441,

1449, 1468, 1534, 1541, and 1558.

7. Library files.

Log

[LDF 2003.12.17.] Changed the conditional in which , , and are defined or undefined. Working on compiling with the DEC C^{++} compiler.

⟨ Include files 6 ⟩ +≡ #define #ifndef #ifndef #define #endif #define #undef #endif #ifdef #define /∗ Needed for ”sstream” below. ∗/ #endif #include #include #include #ifdef #if #include /∗ [LDF 2002.12.13.] Needed for . ∗/ #endif #endif #include #include #include #ifdef /∗ For stream formatting. [LDF 2003.08.14.] ∗/ #include #else #include #endif #include #include #include #ifdef #include #else

§7  3DLDF-1.1.5.1  LIBRARY FILES 5

#ifdef #include #endif #endif #include #include #include #ifdef #include #endif #ifdef #include #elif #include #endif

8. streambuf.h is included above, if is defined, instead of ios, which is included in all other cases. [LDF 2003.08.14.] ⟨ Include files 6 ⟩ +≡ #include #include #include

9.

Log

[LDF 2003.07.18.] Added “using namespace std ”. This is needed with GCC 3.3, but not with GCC 2.95 or the DEC C++ compiler.

⟨ Include files 6 ⟩ +≡ using namespace std;

10. Putting loader together.

11. This is what’s compiled. It’s not necessary to include stdlib.h when using GCC 3.3, but I think it’s safer. [LDF 2004.01.06.]

Log

[LDF 2004.01.06.] Added this section. It simplifies the rules for building the executable if loader.c is compiled.

#ifdef #include #elif #include #endif #include

using namespace std;

⟨ Version control identifier 5 ⟩

6  PUTTING LOADER TOGETHER  3DLDF-1.1.5.1 §12

12. This is what’s written to the loader.h.

Log

[LDF 2004.01.06.] Added this section.

⟨ 12 ⟩ ≡ ⟨ Include files 6 ⟩

13. Global items (pspglb.web). Typedefs, global variables and constants, and some non-class functions. (pspglb.web.)

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

14. Include files. ⟨ Include files 6 ⟩ +≡ #include #ifdef #include #else #ifdef #include #else #ifdef #if #include #endif #endif #endif #endif #include

15. Type definitions. [LDF 2002.10.15.] Currently, all floating point variables are declared as reals. I’ve defined real in order to make it easy to switch between using floats and doubles simply by changing the value of the #if expression.

I try to avoid using preprocessor commands (see Introduction), but this is one of the cases where there’s no better alternative to using the preprocessor (I don’t consider commenting out the unwanted version preferable to using the preprocessor).

Log

[LDF 2002.04.10.] Added formatting commands.

[LDF 2002.04.10.] Added declaration of bool real.

[LDF 2002.12.11.] Added the macros  and  . They’re needed below,
where  and  are declared in the GNU/Linux version (using GCC).

[LDF 2003.06.03.] Added real short . It’s the return type of Plane ::get distance( ).

§15  3DLDF-1.1.5.1  TYPE DEFINITIONS 7
[LDF 2003.12.30.] Now using # define instead of @d for the definitions of  and  .

If @d is used, the definitions are only written to pspglb.c. Using # define, and writing ⟨ Type definitions 15 ⟩ to pspglb.h makes the definitions available to the files that include pspglb.h.

format real float
format real pair real
format bool pair real pair
format real pair real short
format Matrix int

⟨ Type definitions 15 ⟩ ≡ #define 1 #define 0 #if

typedef float real; #elif

typedef double real; #else /∗ Default. LDF 2003.12.17. ∗/

typedef float real; #endif

typedef real Matrix[4][4]; typedef pair⟨real, real⟩ real pair; typedef pair⟨real, signed short⟩ real short; typedef pair⟨bool, bool⟩ bool pair; typedef pair⟨bool, real⟩ bool real;

See also sections 312, 313, 315, and 317. This code is cited in section 15. This code is used in sections 51, 52, 633, and 634.

16. Utility classes. ⟨ Utility classes 16 ⟩ ≡

struct real triple { real first ; real second ; real third ; real triple( ) : first (0), second (0), third (0) { } real triple(real a, real b, real c) : first (a), second (b), third (c) { }

};

This code is used in sections 51 and 52.

17. Global variables.

18. For compilation. [LDF 2003.08.25.] GCC 2.95 doesn’t have the numeric limits template, and GCC 3.3 doesn’t seem to have it either.

Log

[LDF 2002.12.11.] BUG FIX: Discovered that the way this was before,  =  −
real limits .epsilon( ) caused  and  to be equal! I didn’t notice the problem until

8  FOR COMPILATION  3DLDF-1.1.5.1 §18
I started to port 3DLDF to GNU/Linux. It also doesn’t work to use  =  −

real limits .min( ).

⟨ Global variables 18 ⟩ ≡

valarray⟨real⟩ null coordinates (4);

See also sections 19, 20, 78, 234, 302, and 630. This code is cited in section 25. This code is used in sections 51, 91, 239, 305, and 633.

19.  is the second largest real value.  is convenient to have for testing when

computing distances.

!! KLUDGE: Using the macros or because the numeric limits template doesn’t seem to be available under GNU/Linux using GCC, at least not on the computer I’m using. [LDF 2002.12.11.]

Log

[LDF 2003.12.08.] Changed the definition of . Previously, it was calculated using .00000003 ∗ , which was a kludge.

[LDF 2003.12.29.] Changed the way and are declared. They can no longer be const, because the value of is set at the beginning of main( ) using get second largest < Real > ( ). The value of is set after this. Their values should never change after this!

must be initialized here, because it’s used in Point ::magnitude( ). [LDF 2003.12.29.]

⟨ Global variables 18 ⟩ +≡ #ifdef

numeric limits⟨real⟩ real limits ;

extern const real = real limits .max ( ); #else #if

extern const real  =  ;
#else  /∗  , or not specified. LDF 2003.12.08. ∗/
extern const real  =  ;

#endif #endif

real = 0;

real = 0;

20. [LDF 2003.08.14.] is false by default. It is set to true by the command line option “--verbose”. If is true, the local verbose variables in functions are set to true.

Log

[LDF 2003.08.14.] Added  and  .

§21  3DLDF-1.1.5.1  FOR COMPILATION 9

⟨ Global variables 18 ⟩ +≡ bool = false; bool = false; 21. ⟨ Declarations for the header file 21 ⟩ ≡

extern bool ; extern bool ; extern const bool ldf real float ; extern const bool ldf real double; extern real ; extern real ;

See also sections 23, 26, 29, 235, 237, 303, 320, 631, 655, and 692. This code is cited in section 24. This code is used in sections 52, 240, 306, 634, 658, and 695.

22.

Log

[LDF 2003.08.14.] Added  and  .

⟨ Global constants 22 ⟩ ≡ #if

extern const bool ldf real float = 1; extern const bool ldf real double = 0;

#elif extern const bool ldf real float = 0; extern const bool ldf real double = 1;

#else /∗ Defaults. LDF 2003.12.17. ∗/ extern const bool ldf real float = 1; extern const bool ldf real double = 0;

#endif

extern const string  =  ;
extern const string  =  ␣   ␣      ␣    ␣  ␣        ␣   ␣  ;
extern const string  =  ␣     ␣    ␣          ␣  ␣

    ␣       ␣   ␣    ␣    ␣               ␣   ␣      ␣    ␣            ␣   ␣
    ␣  ␣     ␣             ␣  ␣     ␣         ␣   ␣   ␣    ␣          ␣
    ␣  ␣     ␣       ␣                ␣        ␣      ␣    ␣   ␣    ␣
    ␣    ␣   ␣       ␣  ␣   ␣       ␣            ␣␣␣␣                  ␣␣␣␣

    ␣␣␣␣␣␣  ␣                                   ␣     ␣  ;

See also sections 28, 159, 236, and 319. This code is used in sections 51, 162, 239, and 633.

23.

Log

[LDF 2003.11.28.] Changed from a real to a string. This is necessary, because I now have versions with three digits separated by periods.

⟨ Declarations for the header file 21 ⟩ +≡ extern const string ; extern const string ; extern const string ; extern const bool ldf real float ; extern const bool ldf real double; 24. TO DO: Find out why the library version of trunc( ) can’t be found in the version for GCC 2.95 under Linux! [LDF 2002.12.10.]

The problem doesn’t exist for GCC 3.3 under Linux. [LDF 2003.08.14.]

Log

[LDF 2003.08.14.] Put this function declaration in ⟨ Declare utility functions 24 ⟩. Formerly, it was in ⟨ Declarations for the header file 21 ⟩.

Changed the conditional from #ifdef to #ifdef , because the library version of trunc( ) is found when compiling with GCC 3.3 under Linux.

⟨ Declare utility functions 24 ⟩ ≡ #ifdef

double trunc(double d); #endif

See also section 31. This code is cited in section 24. This code is used in section 52.

25.

Log

[LDF 2003.08.14.] Put this function definition into ⟨ Define utility functions 25 ⟩. Formerly, it was in ⟨ Global variables 18 ⟩.

⟨ Define utility functions 25 ⟩ ≡ #ifdef /∗ KLUDGE!! [LDF 2002.12.1.] trunc( ) isn’t available on the Linux machine

gwdg-wb02.gwdg.de! Find out why not! ∗/ double trunc(double d) {

int i;

i = static cast⟨int⟩(d);

return static cast⟨double⟩(i); }

#endif

See also section 32. This code is cited in section 25. This code is used in section 51.

26. For the header file. ⟨ Declarations for the header file 21 ⟩ +≡

extern valarray⟨real⟩ null coordinates ; #ifdef

extern numeric limits⟨real⟩ real limits ; #endif

27. Global constants. is the largest possible real value, where real is either a synonym for float or for double, depending on how it’s defined. Values are set to or functions return it when something has gone wrong. is also used for the real values in and . Another possibility would be to use exception handling, but so far I’ve found it convenient to use instead. Since the largest float is so large, and epsilon( ) for floats is so small, the loss of the largest possible valid value is insignificant. Using exception handling has its advantages, and if it turns out to be useful, I’ll put in exception handling code, but using an otherwise valid value to signal exceptional conditions or errors does have the advantage of simplifying the path of execution through the program code. [LDF 2002.10.16.] Modified [LDF 2002.10.20.]

Log

[LDF 2002.09.25.] Added this section. Previously, I declared and initialized my global constants in the header file. This meant that each compilation unit that loaded pspglb.h had its own version of , , etc. I didn’t know that consts had internal linkage by default and that I could make their linkage external by using extern in the declaration with the initialization, and put a second declaration, also with extern, in the header file. This is what I’ve done now.

[LDF 2003.06.03.] Added .

28. For compilation. ⟨ Global constants 22 ⟩ +≡

extern const real = 4.0 ∗ atan(1.0);

extern const real pair  (  ,  );
extern const real short  (  , 0);

12  FOR THE HEADER FILE  3DLDF-1.1.5.1 §29

29. For the header file. ⟨ Declarations for the header file 21 ⟩ +≡

extern const real ;

extern const real ;

extern const real pair ;

extern const real short ;

30. Utility functions.

31. Solve quadratic equation. [LDF 2002.09.03.] TO DO: Maybe add functions for solving cubic and quartic equations, if this is practicable.

Log

[LDF 2003.06.1.] Changed return type from pair⟨real, real⟩ to real pair, which is equivalent.

⟨ Declare utility functions 24 ⟩ +≡ real pair solve quadratic(real a, real b, real c);

§32  3DLDF-1.1.5.1  SOLVE QUADRATIC EQUATION 13

32. ⟨ Define utility functions 25 ⟩ +≡

real pair solve quadratic(real a, real b, real c) {

real pair p; try {

p.first = (−b + sqrt ((b ∗ b) − (4 ∗ a ∗ c)))/(2 ∗ a); } catch( …) {

p.first = ; } try {

p.second = (−b − sqrt ((b ∗ b) − (4 ∗ a ∗ c)))/(2 ∗ a); } catch( …) {

p.second = ; } return p;

}

33. System information.

Log

[LDF 2003.12.29.] Added this section.

34. Declare namespace System.

Log

[LDF 2003.12.29.] Added this section.

⟨ Declare namespace System 34 ⟩ ≡

namespace System {

⟨ Declare System functions 36 ⟩ }

See also section 65. This code is used in sections 51, 52, 74, and 75.

35. Endianness.

Log

[LDF 2003.12.29.] Added this section.

14  GET ENDIANNESS  3DLDF-1.1.5.1 §36

36. Get endianness. get endianness ( ) returns the following values: 0 if the processor is little-endian. 1 if the processor is big-endian. -1 if the endianness cannot be determined.

It is called by is little endian( ) and is big endian( ). [LDF 2003.12.21.]

This function has been adapted from Harbison, Samuel P., and Guy L. Steele Jr. C, A Reference Manual, pp. 163–164. [LDF 2003.12.29.]

Log

[LDF 2003.12.29.] Added this function.

⟨ Declare System functions 36 ⟩ ≡

signed short get endianness (const bool verbose = false);

See also sections 38, 40, 43, 45, 47, 66, 71, and 72. This code is used in sections 34, 52, 65, and 75.

37. ⟨ Define System functions 37 ⟩ ≡

signed short System ::get endianness (const bool verbose)

{

union { long Long ; char Char [sizeof (long)];

} u;

u.Long = 1;

if (u.Char [0] ≡ 1) { if (verbose) cout ≪ ␣ ␣ ≪ endl ≪ endl ≪ flush; return 0;

}

else if (u.Char [sizeof (long) − 1] ≡ 1) { if (verbose) cout ≪ ␣ ␣ ≪ endl ≪ endl ≪ flush; return 1;

} else {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; return −1;

} }

See also sections 39, 41, 44, 46, 48, 67, and 68. This code is used in sections 51, 74, and 75.

38. Is big endian.

Log

[LDF 2003.12.29.] Added this function.

⟨ Declare System functions 36 ⟩ +≡ bool is big endian(const bool verbose = false);

§39  3DLDF-1.1.5.1  IS BIG ENDIAN 15

39. ⟨ Define System functions 37 ⟩ +≡

bool System ::is big endian(const bool verbose) {

return (get endianness (verbose) ≡ 1); }

40. Is little endian.

Log

[LDF 2003.12.29.] Added this function.

⟨ Declare System functions 36 ⟩ +≡ bool is little endian(const bool verbose = false);

41. ⟨ Define System functions 37 ⟩ +≡

bool System ::is little endian(const bool verbose) {

return (get endianness (verbose) ≡ 0); }

42. Register width.

Log

[LDF 2003.12.29.] Added this section.

43. Get register width.

Log

[LDF 2003.12.29.] Added this function. [LDF 2004.1.2.] Changed the name of this function from get processor size( ) to get register width( ).

⟨ Declare System functions 36 ⟩ +≡ unsigned short get register width( );

44. ⟨ Define System functions 37 ⟩ +≡

unsigned short System ::get register width( ) {

return (sizeof (void ∗) ∗ ); }

45. Is 32 bit.

Log

[LDF 2003.12.29.] Added this function.

⟨ Declare System functions 36 ⟩ +≡ bool is 32 bit ( );

16  IS 32 BIT  3DLDF-1.1.5.1 §46

46. ⟨ Define System functions 37 ⟩ +≡

bool System ::is 32 bit ( ) {

return (get register width( ) ≡ 32); }

47. Is 64 bit.

Log

[LDF 2003.12.29.] Added this function.

⟨ Declare System functions 36 ⟩ +≡ bool is 64 bit ( );

48. ⟨ Define System functions 37 ⟩ +≡

bool System ::is 64 bit ( ) {

return (get register width( ) ≡ 64); }

49. Forward declarations. [LDF 2002.10.16.] In the files that are compiled first, some classes refer to other classes that haven’t been defined yet. Forward declarations make it possible to do this. TO DO: GET CITATION from Stroustrup.

Log

[LDF 2002.04.10.] Added the forward declaration of bool real point. It’s needed because it’s used as the return value of Point ::intersection point ( ), which is, of course, declared within the declaration of class Point. However, bool real point can only be defined after Point is defined. This forward declaration solves the problem.

[LDF 2003.07.16.] Added forward declaration of Ellipse. It’s needed, because I’ve declared Ellipse to be a friend of Path. Formerly, Circle was a friend of Path, but now it must be Ellipse, because I’ve made the “segment” functions segment ( ), half ( ), and quarter ( ) members of Ellipse instead of Circle.

⟨ Forward declarations 49 ⟩ ≡ struct bool point; struct bool real point; class Circle; class Ellipse; struct Focus; struct Line; class Path; class Picture; struct Plane; class Point;

This code is used in sections 51 and 52.

50. Putting pspglb together.

§51  3DLDF-1.1.5.1  PUTTING PSPGLB TOGETHER 17

51. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Type definitions 15 ⟩ ⟨ Utility classes 16 ⟩ ⟨ Global variables 18 ⟩ ⟨ Global constants 22 ⟩ ⟨ Define utility functions 25 ⟩ ⟨ Declare namespace System 34 ⟩ ⟨ Define System functions 37 ⟩ ⟨ Forward declarations 49 ⟩

52. This is what’s written to the pspglb.h. ⟨ 52 ⟩ ≡

⟨ Type definitions 15 ⟩ ⟨ Utility classes 16 ⟩ ⟨ Declarations for the header file 21 ⟩ ⟨ Declare namespace System 34 ⟩

/∗ This doesn’t work, apparently because it’s incompatible with the use of sstream. ∗/ #if 0 #ifdef /∗ Using the DEC C^{++} Compiler. ∗/

const real = ; #endif #endif

⟨ Declare utility functions 24 ⟩ ⟨ Forward declarations 49 ⟩ ⟨ Declare System functions 36 ⟩

53. Dynamic allocation for Shapes.

Log

[LDF 2003.12.29.] Added this template function. [LDF 2004.1.2.] Moved the code in this file from pspglb.web to creatnew.web.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

54. Include files. ⟨ Include files 6 ⟩ +≡ #include #include

55. Dynamic allocation for Shapes.

56. Pointer argument. ⟨ Declare create new ( ) 56 ⟩ ≡

template⟨class C⟩ C∗create new (const C∗arg );

See also section 58.

18  POINTER ARGUMENT  3DLDF-1.1.5.1 §57

57. ⟨ Define create new ( ) 57 ⟩ ≡

template⟨class C⟩ C∗create new (const C∗arg )

{ C ∗ obj = new(C); obj set on free store( ); if (arg ≠ 0) ∗obj = ∗arg ; return obj ;

}

See also section 59. This code is used in sections 61 and 62.

58. Reference argument. ⟨ Declare create new ( ) 56 ⟩ +≡

template⟨class C⟩ C∗create new (const C&arg );

59. ⟨ Define create new ( ) 57 ⟩ +≡

template⟨class C⟩ C∗create new (const C&arg )

{ C ∗ obj = new(C); obj set on free store( ); ∗obj = arg ; return obj ;

}

60. Putting creatnew together.

61. This is what’s compiled. I don’t really need to compile the definition of create new ( ) here, because it must be included in all of the files that instantiate it, anyway. However, that may become unnecessary later, in which case it will have to be compiled here. In addition, if there’s something wrong with the definition, it may be helpful to catch the error here. [LDF 2004.1.2.]

⟨ Include files 6 ⟩

⟨ Version control identifier 5 ⟩

⟨ Define create new ( ) 57 ⟩

§62  3DLDF-1.1.5.1  PUTTING CREATNEW TOGETHER 19

62. This is what’s written to the creatnew.h. The file creatnew.h must be included by all files that define specializations of create new ( ). [LDF 2003.12.29.] ⟨ 62 ⟩ ≡

⟨ Define create new ( ) 57 ⟩

63. Get second-largest real value. ⟨ Version control identifier 5 ⟩ +≡

static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

64. Include files. ⟨ Include files 6 ⟩ +≡ #include #include

65. Declare namespace System.

Log

[LDF 2004.1.2.] Added this section.

⟨ Declare namespace System 34 ⟩ +≡

namespace System {

⟨ Declare System functions 36 ⟩ }

66. Get second largest. This function calculates the second-largest real value. It should be called using float or double as a parameter, e.g., get second largest < float > ( ) or get second largest < double > ( ). or must be passed as an argument. On systems with the numeric limits template, real limits .max ( ) could be used instead. [LDF 2003.12.29.]

get second largest ( ) determines which unsigned integral type has the same size as the template parameter Real . The locally declared type i type is defined to be a synonym for this type using typedef . ip is a pointer to i type. It is assigned a value by casting a pointer to to the type of ip, i.e., a pointer to i type. Then, 1 is subtracted from ∗ip, and the ip is cast back to a pointer to Real . This is the second largest Real value. [LDF 2003.12.29.]

This algorithm works on all of the machines I’ve tested. It doesn’t matter whether they are big or littleendian, whether they have 32 or 64-bit processors. If the exponent of a floating point type is stored in its low order byte or bytes, then this will fail. I haven’t run into this problem yet, though. The commented-out code in ⟨ Loop for testing bits 70 ⟩ may help in finding the second-largest Real value in this case. [LDF 2003.12.29.]

Log

[LDF 2003.12.29.] Added this function.

[LDF 2004.1.2.] Moved this section from pspglb.web to creatnew.web.

⟨ Declare System functions 36 ⟩ +≡ template⟨class Real ⟩ Real get second largest (Real , bool verbose = false); float get second largest (float, bool); double get second largest (double, bool);

67. ⟨ Define System functions 37 ⟩ +≡

20  GET SECOND LARGEST  3DLDF-1.1.5.1 §68

68. ⟨ Define System functions 37 ⟩ +≡

template⟨class Real ⟩Real System ::get second largest (Real , bool verbose) {

const unsigned short = sizeof (unsigned short); const unsigned short = sizeof (unsigned int); const unsigned short = sizeof (unsigned long); const unsigned short = sizeof (unsigned long long); const unsigned short Real SIZE = sizeof (Real ); const unsigned short = sizeof (float); const unsigned short = sizeof (double); const unsigned short = sizeof (long double); const bool Real EQ USHORT = (Real SIZE ≡ ); const bool Real EQ UINT = (Real SIZE ≡ ); const bool Real EQ ULONG = (Real SIZE ≡ ); const bool Real EQ ULONG LONG = (Real SIZE ≡ ); if (verbose) {

cout ≪  ␣␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣␣  ␣ ≪  ≪ endl ≪ flush;
cout ≪  ␣␣  ␣ ≪  ≪ endl ≪ flush;

cout ≪ ␣␣ ␣ ≪ Real SIZE ≪ endl ≪ flush; } Real ∗ rp; if (Real EQ USHORT ) {

if (verbose) cout ≪ ;

typedef unsigned short i type;

⟨ Calculate second-largest Real 69 ⟩ } else if (Real EQ UINT ) {

if (verbose) cout ≪ ␣ ;

typedef unsigned int i type;

⟨ Calculate second-largest Real 69 ⟩ } else if (Real EQ ULONG ) {

if (verbose) cout ≪ ␣ ;

typedef unsigned long i type;

⟨ Calculate second-largest Real 69 ⟩ } else if (Real EQ ULONG LONG ) {

if (verbose) cout ≪ ;

typedef unsigned long long i type;

⟨ Calculate second-largest Real 69 ⟩ } else {

§68  3DLDF-1.1.5.1  GET SECOND LARGEST 21

    cerr ≪  ␣  ␣  ≪  ␣    ␣        ␣    ␣   ␣    ␣     ␣ ≪

        ␣   ␣        ␣        ␣  ≪  ␣    ␣  ␣    ␣  ≪

␣ ␣ ␣ ␣ ≪ flush;

return −1; } if (verbose) {

cout .precision(25);

cout ≪  ␣  ␣ ≪  ≪ endl ≪  ␣  ␣ ≪ ∗rp ≪ endl ≪
␣  ␣    ␣   ␣ ≪ (  ≡ ∗rp) ≪ endl ≪  ␣ ␣    ␣  ␣ ≪
(  − ∗rp) ≪ endl ≪  ␣ ␣   ␣  ␣ ≪ (  > ∗rp) ≪ endl ≪

␣ ␣ ␣ ␣ ≪ ( < ∗rp) ≪ endl ≪ flush; } if ( ≡ ∗rp) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; exit (1);

}

else if ( < ∗rp) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; exit (1);

}

return ∗rp; }

69. Calculate second-largest Real. ⟨ Calculate second-largest Real 69 ⟩ ≡

{ i type ∗ip = reinterpret cast⟨i type ∗⟩(& ); if (verbose) cout ≪ ␣ ␣ ≪ ∗ip ≪ endl ≪ flush; i type bit pattern i type; i type result ; bit pattern i type = 1; bitset⟨sizeof (i type) ∗ ⟩ b; b = ∗ip; if (verbose) cout ≪ ␣ ␣ ␣ ≪ b ≪ endl ≪ flush; b = bit pattern i type; if (verbose) cout ≪ ␣ ␣ ␣ ≪ b ≪ endl ≪ flush; result = bit pattern i type ⊕ ∗ip; if (verbose) cout ≪ ␣ ␣ ≪ result ≪ endl ≪ flush; b = result ; if (verbose) cout ≪ ␣ ␣ ␣ ≪ b ≪ endl ≪ flush; rp = reinterpret cast ⟨ Real ∗> (&result ); if (verbose) cout ≪ ␣ ␣ ≪ ∗rp ≪ endl ≪ flush; }

This code is used in section 68.

22  LOOP FOR TESTING BITS  3DLDF-1.1.5.1 §70

70. Loop for testing bits. ⟨ Loop for testing bits 70 ⟩ ≡ #if 0

int counter ; for (int i = 0; i < (sizeof (Real ) ∗ ); ^{++}i) { if (verbose) cout ≪ ␣ ␣ ≪ i ≪ endl ≪ flush; /∗ This has only been needed on the DEC Alpha,

so far. ∗/ /∗ This is the case that the highest-order bit of the ∗/ /∗ mantissa is 1, and all of the other bits (in particular, ∗/ /∗ all the bits of the exponent) are 0. In this case, ∗rp ∗/ /∗ is not a number (NAN). The GNU compiler copes with this, ∗/ /∗ the DEC compiler signals a floating point error and dumps ∗/ /∗ core (I believe). I wasn’t able to catch the error with

∗/  /∗ try and catch. ∗/  /∗ START HERE. Change (8 + 1) to (  + 1), except ∗/
/∗  ∗/  /∗ isn’t the right name. Find it, and put here. This ∗/

/∗ assumes the exponent is at the left, which may not be ∗/ /∗ true. Skipping this bit pattern

is necessary on the DEC ∗/ /∗ ALPHA, because the float is not a number. ∗/ /∗ It must be 23 for float, and 52 for double. ∗/

if (i ≡ (sizeof (Real ) ∗ ) − (12)) { if (verbose) cout ≪ ␣ ␣ ≪ i ≪ ␣␣ ␣ ␣ ␣␣ ≪ flush; continue;

} bit pattern i type = 1; bit pattern i type ≪= i; if (verbose)

cout ≪ ␣ ␣ ␣ ≪ i ≪ ␣ ␣ ≪ bit pattern i type ≪ endl ≪ flush; b = bit pattern i type; if (verbose) cout ≪ ␣ ␣ ␣ ≪ b ≪ endl ≪ flush; result = bit pattern i type ⊕ ∗ip; if (verbose) cout ≪ ␣ ␣ ≪ result ≪ endl ≪ flush; b = result ; if (verbose) cout ≪ ␣ ␣ ␣ ≪ b ≪ endl ≪ flush; rp = reinterpret cast ⟨ Real ∗> (&result ); if (verbose) cout ≪ ␣ ␣ ≪ ∗rp ≪ endl ≪ flush; if (∗rp ≤ 0) {

if (verbose) cout ≪ ␣ ␣ ≪ flush;

continue; } else if (∗rp ≥ ) {

if (verbose) cout ≪ ␣ ␣␣ ≪ endl ≪ flush;

continue; } else if (second largest real ≥ ∗rp) {

if (verbose) cout ≪ ␣ ␣ ≪ ≪ flush; continue;

} else if (∗rp > second largest real ∧ ∗rp < ) {

if (verbose) cout ≪  ␣ ␣                   ␣  ␣ ≪  ␣ ␣  ≪ endl ≪
␣                   ␣  ␣  ≪ ␣   ␣       ␣  ␣ ␣ ≪ i ≪  ≪ flush;

second largest real = ∗rp;

counter = i; } else {

if (verbose) cout ≪ ␣ ␣ ␣ ;

continue; }

§70  3DLDF-1.1.5.1  LOOP FOR TESTING BITS 23

} /∗ for ∗/ #endif

This code is cited in section 66.

71. Template function instantiations.

Log

[LDF 2003.12.29.] Added this section.

⟨ Declare System functions 36 ⟩ +≡ float get second largest (float , bool verbose);

72. ⟨ Declare System functions 36 ⟩ +≡

double get second largest (double , bool verbose);

73. Putting gsltmplt together.

74. This is what’s compiled. I don’t really need to compile the definition of get second largest ( ) here, because it must be included in all of the files that instantiate it, anyway. However, that may become unnecessary later, in which case it will have to be compiled here. In addition, if there’s something wrong with the definition, it may be helpful to catch the error here. [LDF 2004.1.2.]

⟨ Include files 6 ⟩

⟨ Version control identifier 5 ⟩

⟨ Declare namespace System 34 ⟩

⟨ Define System functions 37 ⟩

24  PUTTING GSLTMPLT TOGETHER  3DLDF-1.1.5.1 §75

75. This is what’s written to the gsltmplt.h. The file gsltmplt.h must be included by all files that define specializations of get second largest ( ). [LDF 2003.12.29.] ⟨ 75 ⟩ ≡

⟨ Declare namespace System 34 ⟩

⟨ Declare System functions 36 ⟩

⟨ Define System functions 37 ⟩

76. I/O (io.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

77. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include

78. Global variables. [LDF 2002.10.16.] in stream is an input stream attached to a file with user code for input. Currently, it is used, but it fulfills no useful function, because I haven’t defined an input routine yet. out stream is an output stream attached to the file of METAPOST code that 3DLDF currently produces as its output. tex stream is an output stream attached to a file of TEX code. The user can write TEX code to this file and load it into persp.tex or use it for some other purpose. 3DLDF makes no use of it itself.

Log

[LDF 2002.08.30.] Added tex stream so that I can include TEX code in my user code. Code written by 3DLDF to tex stream will be loaded by persp.tex, or whatever TEX file includes the PostScript file generated by METAPOST from the output of 3DLDF. User code is currently in main.web. In production versions user code will be in user.web.

[LDF 2003.07.16.] Added fig num.

format ifstream int
format ofstream int

⟨ Global variables 18 ⟩ +≡ ifstream in stream; ofstream out stream; ofstream tex stream; unsigned short fig num;

§79  3DLDF-1.1.5.1  GLOBAL VARIABLES 25

79. extern declarations for the global variables. ⟨ extern variable declarations 79 ⟩ ≡

extern ifstream in stream;

extern ofstream out stream;

extern ofstream tex stream;

extern unsigned short fig num;

This code is used in section 92.

80. I/O functions.

81. Initialize I/O.

Log

[LDF 2003.08.29.] Changed, so that in stream isn’t opened.

⟨ Declare I/O functions 81 ⟩ ≡

void initialize io(string in stream name, string out stream name, string tex stream name, char

∗program name);

See also sections 84, 86, and 88. This code is used in section 92.

82. ⟨ Define I/O functions 82 ⟩ ≡

void initialize io(string in stream name, string out stream name, string tex stream name, char

∗program name){ time t tt ; tm ∗lt ; tt = time(0); lt = localtime(&tt ); string datestamp(asctime(lt )); datestamp.erase(datestamp.size( ) − 1); /∗ Remove terminal line-feed. ∗/

See also sections 83, 85, 87, and 89. This code is used in section 91.

26  INITIALIZE I/O  3DLDF-1.1.5.1 §83

83. Open out stream and tex stream. in stream is currently not opened. [LDF 2003.08.29.] ⟨ Define I/O functions 82 ⟩ +≡ #if 0

in stream.open(in stream name.c str ( )); #endif

out stream.open(out stream name.c str ( )); #ifdef

out stream.setf (ios base ::fixed , ios base ::floatfield ); #else #ifdef

out stream.setf (ios ::fixed , ios ::floatfield ); #endif #endif

tex stream.open(tex stream name.c str ( )); /∗ Write datestamp to out stream. ∗/

out stream ≪  ␣    ␣  ␣ ≪ out stream name ≪  ≪ endl ≪  ␣         ␣  ␣ ≪
datestamp ≪ ␣    ␣ ≪ program name ≪  ;  /∗ Write datestamp to tex stream. ∗/
tex stream ≪  ␣    ␣  ␣ ≪ tex stream name ≪  ≪ endl ≪  ␣         ␣  ␣ ≪

datestamp ≪ ␣ ␣ ≪ program name ≪ ; }

84. Write footers. [LDF 2002.10.16.] Footers can be written to output stream and tex stream. I use them for Local Variables lists for Emacs. Other users may not want this, which is why this code is commented out here. ⟨ Declare I/O functions 81 ⟩ +≡

void write footers ( );

§85  3DLDF-1.1.5.1  WRITE FOOTERS 27

85. ⟨ Define I/O functions 82 ⟩ +≡

void write footers ( ) {

#if 0

out stream ≪ endl ≪ endl ≪ ␣ ≪ ␣ ≪ endl ≪ ␣ ≪ endl ≪ ␣ ␣ ␣ ␣ ␣ ≪

endl ≪  ␣                   ␣  ≪ endl ≪
␣                   ␣    ␣  ≪ endl ≪ ␣  ≪
endl ≪  ␣  ≪ endl ≪
␣  ≪ endl ≪ ␣  ≪

endl ≪ ␣ ≪ endl ≪ endl ;

tex stream ≪  ␣ ≪  ␣  ≪  ␣  ≪

␣                   ␣    ␣  ≪ ␣  ≪
␣  ≪ ␣  ≪
␣  ≪ ␣  ;

#endif

return; }

86. Begin figure.

Log

[LDF 2003.07.16.] Added silent argument, and a message printed conditionally to stdout , saying which figure is being started. This should help in finding where errors occur.

[LDF 2003.07.16.] Made non-inline. [LDF 2003.08.17.] Made silent non-const. Setting it to true, if is true.

⟨ Declare I/O functions 81 ⟩ +≡ void beginfig (unsigned short i, bool silent = false);

28  BEGIN FIGURE  3DLDF-1.1.5.1 §87

87. ⟨ Define I/O functions 82 ⟩ +≡

void beginfig (unsigned short i, bool silent ) {

if ( ) silent = true;

fig num = i;

out stream ≪  ≪ fig num ≪  ;
if (¬silent ) cout ≪  ␣      ␣ ≪ fig num ≪  ≪ endl ≪ flush;

return; }

88. End figure. The unsigned short argument is “syntactic sugar”. It’s ignored by endfig ( ), but may be convenient for a user for keeping track of what figure is being ended.

Log

[LDF 2003.07.16.] Added silent argument, and a message printed conditionally to stdout , saying which figure is being ended. This should help in finding where errors occur.

[LDF 2003.07.16.] Made non-inline. [LDF 2003.08.17.] Made silent non-const. Setting it to true, if is true.

⟨ Declare I/O functions 81 ⟩ +≡ void endfig (unsigned short i = 0, bool silent = false);

89. ⟨ Define I/O functions 82 ⟩ +≡

void endfig (unsigned short i, bool silent ) {

if ( ) silent = true;

out stream ≪  ≪  ;
if (¬silent ) cout ≪  ␣      ␣ ≪ fig num ≪  ≪ endl ≪ endl ≪ flush;

return; }

90. Putting I/O together.

91. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Global variables 18 ⟩ ⟨ Define I/O functions 82 ⟩

§92  3DLDF-1.1.5.1  PUTTING I/O TOGETHER 29

92. This is what’s written to io.h. ⟨ 92 ⟩ ≡

⟨ extern variable declarations 79 ⟩

⟨ Declare I/O functions 81 ⟩

93. Color (colors.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

94. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include

95. Color class definition. [LDF 2002.09.25.] !! Remember to change the constructors, setting functions, and assignment operator if I add or change anything here!!

Log

[LDF 2002.10.06.] Added. on free store.

⟨ Define class Color 95 ⟩ ≡

class Color { string name; bool use name; bool on free store; real red part ; real green part ; real blue part ;

public: ⟨ Declare Color functions 97 ⟩

};

This code is used in sections 162 and 163.

96. Constructors and setting functions.

97. Default constructor. [LDF 2002.10.06.] Added code to definition. Previously, it was empty. ⟨ Declare Color functions 97 ⟩ ≡

Color( );

and 151. This code is used in section 95.

See also sections 99, 102, 104, 107, 109, 114, 116, 118, 121, 123, 125, 127, 129, 131, 133, 135, 138, 141, 142, 143, 144, 146, 149,

30  DEFAULT CONSTRUCTOR  3DLDF-1.1.5.1 §98

98. ⟨ Define Color functions 98 ⟩ ≡

Color ::Color( ) {

red part = green part = blue part = 0.0; name = ; use name = false; on free store = false;

}

See also sections 100, 103, 105, 108, 110, 115, 117, 119, 122, 124, 126, 128, 130, 132, 134, 136, 139, 145, 150, and 152. This code is used in section 162.

99. Copy constructor. !! Remember to add or change code here if I add or change anything in the class definition!!

Log

[LDF 2002.09.25.] Added this function.

⟨ Declare Color functions 97 ⟩ +≡ Color(const Color &c, const string n = , const bool u = true);

100. ⟨ Define Color functions 98 ⟩ +≡

Color ::Color(const Color &c, const string n, const bool u) {

name = n; red part = c.get red part ( ); green part = c.get green part ( ); blue part = c.get blue part ( ); if (n ≠ ∧ u ≡ true) {

use name = true; } else use name = false; on free store = false; /∗ LDF 2002.10.06. Added. ∗/ return;

}

101. Name and unsigned short arguments.

102. Constructor. ⟨ Declare Color functions 97 ⟩ +≡

§103  3DLDF-1.1.5.1  CONSTRUCTOR 31

Color(const string n, const unsigned short r, const unsigned short g, const unsigned short b, const bool u = true); 103. ⟨ Define Color functions 98 ⟩ +≡

Color ::Color(const string n, const unsigned short r, const unsigned short g, const unsigned

short b, const bool u)

: name(n) { name = n; if (n ≠ ∧ u ≡ true) { use name = true;

}

else use name = false;

on free store = false; /∗ LDF 2002.10.06. Added. ∗/ red part = r/255.0; green part = g/255.0; blue part = b/255.0;

}

104. Setting function. ⟨ Declare Color functions 97 ⟩ +≡

void set (const string n, const unsigned short r, const unsigned short g, const unsigned short b, const bool u = false);

105. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set (const string n, const unsigned short r, const unsigned short g, const unsigned

short b, const bool u)

{ name = n; if (n ≠ ∧ u ≡ true) { use name = true;

}

else use name = false; red part = r/255.0; green part = g/255.0; blue part = b/255.0;

}

106. Three real arguments. [LDF 2002.10.09.] Added the following constructor and setting function. They are for unnamed Colors. The DEC compiler can’t distinguish between real and unsigned short arguments, so the overloaded functions must differ in another way. In this case, these versions have no name argument. I believe that users are most likely to declare Colors using real arguments when they plan to modify them, in which case the output ( ) function should write the red, green and blue values to out stream rather than name. If it turns out to be necessary, more constructors can be added or the existing ones can be changed.

107. Constructor. ⟨ Declare Color functions 97 ⟩ +≡

32  CONSTRUCTOR  3DLDF-1.1.5.1 §108

Color(const real r, const real g, const real b); 108. ⟨ Define Color functions 98 ⟩ +≡

Color ::Color(const real r, const real g, const real b) {

name = ; use name = false; on free store = false; if (r < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣        ␣  ␣  ;

red part = 0; } else if (r > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣        ␣  ␣  ;

red part = 1; } else red part = r; if (g < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣ ␣  ␣␣       ␣          ␣  ␣  ;

green part = 0; } else if (g > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣ ␣  ␣␣       ␣          ␣  ␣  ;

green part = 1; } else green part = g; if (b < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣         ␣  ␣  ;

blue part = 0; } else if (b > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣         ␣  ␣  ;

blue part = 1; } else blue part = b; return;

}

109. Setting function. ⟨ Declare Color functions 97 ⟩ +≡

§110  3DLDF-1.1.5.1  SETTING FUNCTION 33

void set (const real r, const real g, const real b); 110. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set (const real r, const real g, const real b) {

name = ; use name = false; on free store = false; if (r < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣        ␣  ␣  ;

red part = 0; } else if (r > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣        ␣  ␣  ;

red part = 1; } else red part = r; if (g < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣ ␣  ␣␣       ␣          ␣  ␣  ;

green part = 0; } else if (g > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣ ␣  ␣␣       ␣          ␣  ␣  ;

green part = 1; } else green part = g; if (b < 0) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣         ␣  ␣  ;

blue part = 0; } else if (b > 1) {

cerr ≪  ␣  ␣              ␣      ␣    ␣  ≪

      ␣    ␣        ␣  ␣  ␣␣       ␣         ␣  ␣  ;

blue part = 1; } else blue part = b;

}

111. Pseudo-constructor for dynamic allocation.

Log

[LDF 2003.12.30.] Replaced Color ::create new color ( ) with specializations of template⟨class C⟩ C∗create new ( ).

112. Pointer argument. ⟨ Declare non-member template functions for Color 112 ⟩ ≡

Color ∗create new (const Color ∗c);

See also section 113. This code is used in sections 162 and 163.

113. Reference argument.

Log

[LDF 2004.1.2.] Added this declaration.

⟨ Declare non-member template functions for Color 112 ⟩ +≡ Color ∗create new (const Color &c);

114. Assignment. [LDF 2002.09.24.] Added this operator function. ⟨ Declare Color functions 97 ⟩ +≡

void operator=(const Color &c);

115. ⟨ Define Color functions 98 ⟩ +≡

void Color ::operator=(const Color &c)

{ name = ; use name = false; red part = c.red part ; green part = c.green part ; blue part = c.blue part ;

}

116. Equality. [LDF 2002.09.25.] Changed so that only red part , green part and blue part are compared. This way, Colors that differ only in name and/or use name are considered to be equal. [LDF 2002.09.24.] Added this operator function. ⟨ Declare Color functions 97 ⟩ +≡

bool operator≡(const Color &c) const;

117. ⟨ Define Color functions 98 ⟩ +≡

bool Color ::operator≡(const Color &c) const {

return ((red part ≡ c.red part ) ∧ (green part ≡ c.green part ) ∧ (blue part ≡ c.blue part )); }

118. Inequality. [LDF 2002.09.24.] Added this operator function. ⟨ Declare Color functions 97 ⟩ +≡

§119  3DLDF-1.1.5.1  INEQUALITY 35

bool operator≠(const Color &c) const; 119. ⟨ Define Color functions 98 ⟩ +≡

bool Color ::operator≠(const Color &c) const

{

return ¬(∗this ≡ c); }

120. Modifying.

121. Set on free store.

Log

[LDF 2003.12.30.] Added this function.

⟨ Declare Color functions 97 ⟩ +≡ bool set on free store(bool b = true);

122. ⟨ Define Color functions 98 ⟩ +≡

bool Color ::set on free store(bool b)

{ on free store = b; return b;

}

123. Set name. ⟨ Declare Color functions 97 ⟩ +≡

void set name(const string s);

124. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set name(const string s)

{

name = s; }

125. Set use name. ⟨ Declare Color functions 97 ⟩ +≡

void set use name(const bool b);

126. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set use name(const bool b)

{

use name = b; }

127. Modify. ⟨ Declare Color functions 97 ⟩ +≡

void modify (const real r, const real g = 0, const real b = 0);

36  MODIFY  3DLDF-1.1.5.1 §128

128. ⟨ Define Color functions 98 ⟩ +≡

void Color ::modify (const real r, const real g, const real b) {

red part += r; green part += g; blue part += b; if (red part > 1) {

cerr ≪  ␣  ␣  ≪  ␣  ␣        ␣    ␣  ␣ ≪ red part ≪
endl ≪  ␣        ␣   ␣  ;

red part = 1; } else if (red part < 0) {

cerr ≪  ␣  ␣  ≪  ␣  ␣    ␣     ␣  ␣ ≪ red part ≪
endl ≪  ␣        ␣   ␣  ;

red part = 0; } if (green part > 1) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣        ␣    ␣  ␣ ≪

green part ≪ endl ≪  ␣          ␣   ␣  ;

green part = 1; } else if (green part < 0) {

cerr ≪  ␣  ␣  ≪  ␣  ␣    ␣     ␣  ␣ ≪ green part ≪
endl ≪  ␣          ␣   ␣  ;

green part = 0; } if (blue part > 1) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣        ␣    ␣  ␣ ≪

blue part ≪ endl ≪  ␣         ␣   ␣  ;

blue part = 1; } else if (blue part < 0) {

cerr ≪  ␣  ␣  ≪  ␣  ␣    ␣     ␣  ␣ ≪ blue part ≪
endl ≪  ␣         ␣   ␣  ;

blue part = 0; } return;

}

129. Set red part. ⟨ Declare Color functions 97 ⟩ +≡

void set red part (const real r);

§130  3DLDF-1.1.5.1  SET RED PART 37

130. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set red part (const real r) {

if (r > 1) {

cerr ≪  ␣  ␣  ≪ ␣  ␣       ␣    ␣   ␣ ≪ r ≪ endl ≪

      ␣        ␣   ␣  ;

red part = 1; } else if (r < 0) {

cerr ≪  ␣  ␣  ≪ ␣  ␣    ␣    ␣  ␣ ≪ r ≪ endl ≪

      ␣        ␣   ␣  ;

red part = 0; } else red part = r; return;

}

131. Set green part. ⟨ Declare Color functions 97 ⟩ +≡

void set green part (const real g);

132. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set green part (const real g) {

if (g > 1) {

cerr ≪  ␣  ␣  ≪ ␣  ␣       ␣    ␣   ␣ ≪ g ≪
endl ≪  ␣          ␣   ␣  ;

green part = 1; } else if (g < 0) {

cerr ≪  ␣  ␣  ≪ ␣  ␣    ␣    ␣  ␣ ≪ g ≪ endl ≪

      ␣          ␣   ␣  ;

green part = 0; } else green part = g; return;

}

133. Set blue part. ⟨ Declare Color functions 97 ⟩ +≡

void set blue part (const real b);

38  SET BLUE PART  3DLDF-1.1.5.1 §134

134. ⟨ Define Color functions 98 ⟩ +≡

void Color ::set blue part (const real b) {

if (b > 1) {

cerr ≪  ␣  ␣  ≪ ␣  ␣       ␣    ␣   ␣ ≪ b ≪
endl ≪  ␣         ␣   ␣  ;

blue part = 1; } else if (b < 0) {

cerr ≪  ␣  ␣  ≪ ␣  ␣    ␣    ␣  ␣ ≪ b ≪ endl ≪

      ␣         ␣   ␣  ;

blue part = 0; } else blue part = b; return;

}

135. Show. ⟨ Declare Color functions 97 ⟩ +≡

void show (string text = ) const;

136. ⟨ Define Color functions 98 ⟩ +≡

void Color ::show (string text ) const {

if (text ≡ ) text = ; cout ≪ text ≪ endl ; cout ≪ ␣ ␣ ≪ get name( ) ≪ endl ; cout ≪ ␣ ␣ ≪ get use name( ) ≪ endl ; cout ≪ ␣ ␣ ≪ get red part ( ) ≪ endl ; cout ≪ ␣ ␣ ≪ get green part ( ) ≪ endl ; cout ≪ ␣ ␣ ≪ get blue part ( ) ≪ endl ≪ endl ; return;

}

137. Returning elements and information.

138. Is on free store.

Log

[LDF 2004.01.06.] Made non-inline.

⟨ Declare Color functions 97 ⟩ +≡ bool is on free store( ) const;

§139  3DLDF-1.1.5.1  IS ON FREE STORE 39

139. ⟨ Define Color functions 98 ⟩ +≡

bool Color ::is on free store( ) const {

return on free store; }

140. Get Color parts. [LDF 2002.09.24.] These functions always return a real; the argument decimal can’t make them return an unsigned short.

141. Get red part. ⟨ Declare Color functions 97 ⟩ +≡

inline real get red part (bool decimal = false) const {

if (decimal ) return trunc((red part ∗ 255) + .5); else return red part ;

}

142. Get green part. ⟨ Declare Color functions 97 ⟩ +≡

inline real get green part (bool decimal = false) const {

if (decimal ) return trunc((green part ∗ 255) + .5); else return green part ;

}

143. Get blue part. ⟨ Declare Color functions 97 ⟩ +≡

inline real get blue part (bool decimal = false) const {

if (decimal ) return trunc((blue part ∗ 255) + .5); else return blue part ;

}

144. Get use name. ⟨ Declare Color functions 97 ⟩ +≡

bool get use name( ) const;

40  GET USE NAME  3DLDF-1.1.5.1 §145

145. ⟨ Define Color functions 98 ⟩ +≡

bool Color ::get use name( ) const {

return use name; }

146. Get name. ⟨ Declare Color functions 97 ⟩ +≡

inline string get name( ) const {

return name; }

147. Output operator. ⟨ Declare non-member non-template functions for Color 147 ⟩ ≡

ostream & operator≪(ostream & o, const Color &c);

This code is used in section 163.

148. ⟨ Define non-member non-template functions for Color 148 ⟩ ≡

ostream & operator≪(ostream & o, const Color &c) {

if (c.get use name( ) ≡ true) {

o ≪ c.get name( ); } else {

o ≪ ≪ c.get red part ( ) ≪ ␣ ≪ c.get green part ( ) ≪ ␣ ≪ c.get blue part ( ) ≪ ; } return o;

}

This code is used in section 162.

149. Define Colors in METAPOST. ⟨ Declare Color functions 97 ⟩ +≡

void define color mp( ) const;

§150  3DLDF-1.1.5.1  DEFINE COLORS IN METAPOST 41

150. ⟨ Define Color functions 98 ⟩ +≡

void Color ::define color mp( ) const {

if (¬out stream.is open( )) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣␣ ≪ flush; return;

} if (name ≡ ) {

cerr ≪  ␣  ␣  ≪

      ␣  ␣      ␣␣    ␣     ␣        ␣   ␣  ≪ flush;

return; } out stream ≪ ␣ ≪ name ≪ ≪ ␣␣ ≪ name ≪ ␣ ␣ ≪ get red part ( ) ≪ ␣ ≪

get green part ( ) ≪ ␣ ≪ get blue part ( ) ≪ ≪ flush; return;

}

151. Initialize Colors. [LDF 2002.09.25.] This function presupposes the existence of namespace Colors. ⟨ Declare Color functions 97 ⟩ +≡

static void initialize colors ( );

42  INITIALIZE COLORS  3DLDF-1.1.5.1 §152

152. ⟨ Define Color functions 98 ⟩ +≡

void Color ::initialize colors ( ) {

using namespace Colors; if (¬out stream.is open( )) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣␣ ≪ flush; return;

} out stream ≪ ␣ ␣ ;

#if 0 /∗ [LDF 2002.09.25.] These colors are already defined in METAPOST and their definitions are

not likely to change. However, if they do, I can comment these function calls back in. ∗/ red .define color mp( ); green.define color mp( ); blue.define color mp( ); black .define color mp( ); white.define color mp( ); background .define color mp( );

#endif yellow .define color mp( ); cyan.define color mp( ); magenta.define color mp( ); orange.define color mp( ); violet .define color mp( ); purple.define color mp( ); yellow green.define color mp( ); green yellow .define color mp( ); blue violet .define color mp( ); gray .define color mp( ); light gray .define color mp( ); violet red .define color mp( ); default background .define color mp( );

/∗ [LDF 2002.09.25.] Currently, this function does nothing if I’m using all of the colors. ∗/ out stream ≪ ␣ ␣ ␣ ␣ ; return;

}

153. Namespace Colors. Here I can put either ⟨ Major Colors 156 ⟩ or ⟨ All Colors 0 ⟩ into ⟨ Declare namespace Colors 153 ⟩, and comment out the other, depending on what I want. This prevents too much unneeded code from being processed. ⟨ All Colors 0 ⟩ is very long, so I neither want to compile it, write the extern declarations from it to colors.h, nor print out the code when I run cweave, unless I really want to use it. [LDF 2002.09.25.] ⟨ Declare namespace Colors 153 ⟩ ≡

⟨ Major Colors 156 ⟩ /∗ ⟨ All Colors 0 ⟩ ∗/

This code is cited in section 153. This code is used in section 162.

§154  3DLDF-1.1.5.1  NAMESPACE COLORS 43

154. [LDF 2002.09.25.] Here I can put either ⟨ extern Major Colors 157 ⟩ or ⟨ extern All Colors 0 ⟩ into ⟨ extern namespace Colors declaration 154 ⟩ ⟨ extern namespace Colors declaration 154 ⟩ ≡

⟨ extern Major Colors 157 ⟩

This code is cited in sections 154 and 158. This code is used in section 163.

155. Major Colors. The colors “red”, “green”, “blue”, “black”, and “white” are already defined in METAPOST, however, we need them here in order to access the Color functions for them.

!! [LDF 2002.09.24.] If this definition isn’t explicitly written to the header file, as it is below, this causes real problems!! It took me awhile to find out that this was the cause.

156. Internal (with initialization). [LDF 2002.09.25.] !! If I add Colors here, remember to add them in the “External” section below, and in the definition of Color ::initialize colors ( ) below.

Log

[LDF 2002.10.26.] Added help color .

⟨ Major Colors 156 ⟩ ≡

namespace Colors { /∗ Primaries, additive. ∗/ extern const Color red ( , 255, 0, 0, true); extern const Color green( , 0, 255, 0, true); extern const Color blue( , 0, 0, 255, true); /∗ Primaries, subtractive. ∗/ extern const Color cyan( , 0, 255, 255, true); extern const Color yellow ( , 255, 255, 0, true); extern const Color magenta( , 255, 0, 255, true); /∗ [LDF 2002.09.27.] The convention

that I use is that colors like “orange red ” are reds and colors like “red orange” are oranges. ∗/ /∗ Red. ∗/

extern const Color orange red ( , 255, 69, 0);

extern const Color violet red (  , 208, 32, 144);  /∗ Pink. ∗/
extern const Color pink (  , 255, 192, 203);  /∗ Blue. ∗/  /∗ Yellow. ∗/
extern const Color green yellow (  , 173, 255, 47);  /∗ Orange. ∗/
extern const Color orange(  , 255, 165, 0, true);  /∗ Violet. ∗/

extern const Color violet ( , 238, 130, 238, true); extern const Color purple( , 160, 32, 240, true); extern const Color blue violet ( , 138, 43, 226); /∗ Green. ∗/ extern const Color yellow green( , 154, 205, 50);

/∗ “Unbunt” Colors (blacks, whites, and grays). ∗/ extern const Color black ( , 0, 0, 0, true); extern const Color white( , 255, 255, 255, true); extern const Color gray ( , 192, 192, 192); extern const Color light gray ( , 211, 211, 211);

/∗ Defaults. [LDF 2002.09.27.] Note that default color , help color and background color are pointers and that default background is a plain Color. It can be used to access the original background color (currently white), if the user points the background color at some other Color. ∗/

extern const Color default background ( , 255, 255, 255, true); extern const Color ∗default color = &black ; extern const Color ∗background color = &default background ; extern const Color ∗help color = &green; /∗ LDF 2002.10.26. Added. ∗/

/∗ [LDF 2002.09.25.] !! TO DO: default background is a convenience, in case I change “background” in the METAPOST code. Check METAPOST documentation!! I believe it has something similar. ∗/

44  INTERNAL (WITH INITIALIZATION)  3DLDF-1.1.5.1 §156

}

This code is cited in sections 153 and 158. This code is used in section 153.

157. External. ⟨ extern Major Colors 157 ⟩ ≡

namespace Colors { /∗ [LDF 2002.09.27.] The ordering should be as above for the internal

declarations. ∗/ /∗ Primaries, additive. ∗/ extern const Color red ; extern const Color green; extern const Color blue; /∗ Primaries, subtractive. ∗/ extern const Color cyan; extern const Color yellow ; extern const Color magenta; /∗ Red. ∗/ extern const Color orange red ; extern const Color violet red ; /∗ Pink. ∗/ extern const Color pink ; /∗ Blue. ∗/ /∗ Yellow. ∗/ extern const Color green yellow ; /∗ Orange. ∗/ extern const Color orange; /∗ Violet. ∗/ extern const Color violet ; extern const Color purple; extern const Color blue violet ; /∗ Green. ∗/ extern const Color yellow green; /∗ “Unbunt” Colors (black, white, and grays). ∗/ extern const Color black ; extern const Color white; extern const Color gray ; extern const Color light gray ; /∗ Defaults. ∗/ extern const Color default background ; extern Color ∗default color ; extern Color ∗help color ; /∗ LDF 2002.10.26. Added. ∗/ extern Color ∗background color ;

}

This code is cited in section 154. This code is used in section 154.

158. All Colors. !! IF colall.web IS CHANGED, I WILL HAVE TO MAKE SURE THAT THIS FILE is recompiled!! does not check the state of colall.web. ?? Should I do something about this, or is it not worth it? If I work on colall.web, I could just put the code back in here.

[LDF 2002.09.26.] If I want all of the colors declared in colall.web, I can uncomment the following line and use ⟨ All Colors 0 ⟩ instead of ⟨ Major Colors 156 ⟩ in ⟨ extern namespace Colors declaration 154 ⟩ above.

i colall.web (Commented out).

159. Global constants.

Log

[LDF 2002.10.26.] Added help color vector .

⟨ Global constants 22 ⟩ +≡

namespace Colors { extern const vector⟨const Color ∗⟩ default color vector (1, default color );

§159  3DLDF-1.1.5.1  GLOBAL CONSTANTS 45

extern const vector⟨const Color ∗⟩ help color vector (1, help color );

/∗ LDF 2002.10.26. Added. ∗/ extern const vector⟨const Color ∗⟩ background color vector (1, background color );

}

160. ⟨ extern global constant declarations 160 ⟩ ≡

namespace Colors { extern const vector⟨const Color ∗⟩ default color vector ; extern const vector⟨const Color ∗⟩ help color vector ; /∗ LDF 2002.10.26. Added. ∗/ extern const vector⟨const Color ∗⟩ background color vector ;

}

This code is used in section 163.

161. Putting Color together.

162. This is compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩; ⟨ Define class Color 95 ⟩ ⟨ Declare namespace Colors 153 ⟩ ⟨ Define Color functions 98 ⟩ ⟨ Declare non-member template functions for Color 112 ⟩ ⟨ Define non-member non-template functions for Color 148 ⟩ ⟨ Global constants 22 ⟩

46  PUTTING COLOR TOGETHER  3DLDF-1.1.5.1 §163

163. This is written to colors.h. ⟨ 163 ⟩ ≡

⟨ Define class Color 95 ⟩

⟨ extern namespace Colors declaration 154 ⟩

⟨ Declare non-member template functions for Color 112 ⟩

⟨ Declare non-member non-template functions for Color 147 ⟩

⟨ extern global constant declarations 160 ⟩

164. Transformations (transform.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

165. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include

166. Transform class definition. The Transform class has a 4 × 4 transformation matrix as its only data member and a number of member functions. Points, Pictures, and Focuses contain Transforms as data members.

!! Remember to add items to operator=( ) if if I add them to the class definition here.

Log

[LDF 2003.07.04.] Removed friend declaration for Focus. I’ve added set element ( ) and get element ( ), which are used in the Focus functions, so the latter need no longer be a friend of Transform.

format Transform int

⟨ Define class Transform 166 ⟩ ≡

class Transform { friend class Point; Matrix matrix ; /∗ When I’ve got things working, I can try to optimize use of storage by not

storing the parts of the matrix that I don’t need. This is a little complicated, because the row or column which isn’t needed differs between the affine and perspective transformations. ∗/

public: ⟨ Declare Transform functions 168 ⟩

};

This code is used in sections 239 and 240.

167. Constructors.

§168  3DLDF-1.1.5.1  DEFAULT CONSTRUCTOR 47

168. Default constructor. (No arguments). Initializes a new transformation matrix as the identity matrix ⟨ Declare Transform functions 168 ⟩ ≡

Transform( );

See also sections 170, 172, 174, 176, 178, 180, 182, 185, 187, 190, 192, 195, 197, 200, 202, 203, 205, 211, 212, 213, 216, 218, 221,

223, 226, and 232. This code is used in section 166.

169. ⟨ Define Transform functions 169 ⟩ ≡

Transform ::Transform( )

{

reset ( ); }

See also sections 171, 173, 175, 177, 179, 181, 183, 186, 188, 191, 193, 196, 198, 201, 204, 206, 207, 208, 209, 217, 219, 222, 224,

227, 228, 229, 230, 231, 233, 416, 424, 425, 426, 427, 428, 429, 430, 431, 432, 439, and 759. This code is used in sections 239, 633, and 980.

170. Constructor with one real argument. All elements of matrix are set to the real argument r. ⟨ Declare Transform functions 168 ⟩ +≡

Transform(real r);

171. ⟨ Define Transform functions 169 ⟩ +≡

Transform ::Transform(real r)

{

for (int i = 0; i < 4; i^{++})

for (int j = 0; j < 4; j^{++}) matrix [i][j] = r;

}

172. Constructor with 16 real arguments. [LDF 2002.09.06.] Added this constructor. This constructor makes it possible to specify all of the elements of matrix . ⟨ Declare Transform functions 168 ⟩ +≡

Transform(real r0 0 , real r0 1 , real r0 2 , real r0 3 , real r1 0 , real r1 1 , real r1 2 , real r1 3 , real r2 0 , real r2 1 , real r2 2 , real r2 3 , real r3 0 , real r3 1 , real r3 2 , real r3 3 );

48  CONSTRUCTOR WITH 16 REAL ARGUMENTS  3DLDF-1.1.5.1 §173

173. ⟨ Define Transform functions 169 ⟩ +≡

Transform ::Transform(real r0 0 , real r0 1 , real r0 2 , real r0 3 , real r1 0 , real r1 1 , real r1 2 , real

r1 3 , real r2 0 , real r2 1 , real r2 2 , real r2 3 , real r3 0 , real r3 1 , real r3 2 , real r3 3 )

{ matrix [0][0] = r0 0 ; matrix [0][1] = r0 1 ; matrix [0][2] = r0 2 ; matrix [0][3] = r0 3 ; matrix [1][0] = r1 0 ; matrix [1][1] = r1 1 ; matrix [1][2] = r1 2 ; matrix [1][3] = r1 3 ; matrix [2][0] = r2 0 ; matrix [2][1] = r2 1 ; matrix [2][2] = r2 2 ; matrix [2][3] = r2 3 ; matrix [3][0] = r3 0 ; matrix [3][1] = r3 1 ; matrix [3][2] = r3 2 ; matrix [3][3] = r3 3 ;

}

174. Assignment. Sets matrix to be identical to the matrix of another Transform. !! Remember to add items here if I add them to the class definition. ⟨ Declare Transform functions 168 ⟩ +≡

Transform operator=(const Transform &t);

175. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::operator=(const Transform &t) {

for (int i = 0; i < 4; i^{++})

for (int j = 0; j < 4; j^{++}) matrix [i][j] = t.matrix [i][j]; return t;

}

176. Reset to identity matrix. ⟨ Declare Transform functions 168 ⟩ +≡

void reset ( );

§177  3DLDF-1.1.5.1  RESET TO IDENTITY MATRIX 49

177. ⟨ Define Transform functions 169 ⟩ +≡

void Transform ::reset ( ) {

for (int i = 0; i < 4; i^{++}) /∗ Rows. ∗/ for (int j = 0; j < 4; j^{++}) /∗ Columns. ∗/ {

matrix [i][j] = (i ≡ j) ? 1 : 0;

} }

178. Setting values.

Log

[LDF 2003.07.04.] Added this function.

⟨ Declare Transform functions 168 ⟩ +≡ void set element (const unsigned short row , const unsigned short col , real r);

179. ⟨ Define Transform functions 169 ⟩ +≡

void Transform ::set element (const unsigned short row , const unsigned short col , real r) {

matrix [row ][col ] = (fabs (r) < epsilon( )) ? 0 : r; return;

}

180. Clean. clean( ) changes elements in matrix whose absolute values are < epsilon( ) to 0. ⟨ Declare Transform functions 168 ⟩ +≡

50  CLEAN  3DLDF-1.1.5.1 §181

void clean( ); 181. ⟨ Define Transform functions 169 ⟩ +≡

void Transform ::clean( )

{ real eps = epsilon( ); for (int i = 0; i < 4; i^{++}) /∗ Rows. ∗/

for (int j = 0; j < 4; j^{++}) /∗ Columns. ∗/ {

if (fabs (matrix [i][j]) < eps ) matrix [i][j] = 0; }

}

182. Epsilon. Minimum magnitude of values stored in matrix . [LDF 2002.10.16.] The value returned by epsilon( ) has to be fairly large because of the poor precision resulting from the use floats and the Standard Library versions of the trigonometric functions. There is currently no equality operator for Transform, but the precision of the Transforms affects that of Points. TO DO: I hope to be able to solve the problem by finding routines for calculating the trigonometric functions more accurately (and faster) by using integers and bitwise shifts. If this doesn’t work out, I could try redefining real as double (which I don’t want to do), or I could try to use double explicitly when using the trigonometric functions. In the latter case, I would have to truncate the doubles to floats eventually, so I don’t know if this would have any benefit.

Log

[LDF 2004.1.2.] Now returning different values, depending on whether real is float or double. TO DO: Try to find out what values would be best. It will be necessary to check how good the value for double is.

[LDF 2004.1.2.] Made epsilon( ) static and non-inline.

⟨ Declare Transform functions 168 ⟩ +≡ static real epsilon( );

183. ⟨ Define Transform functions 169 ⟩ +≡

real Transform ::epsilon( )

{ #if

return .000000001;

#else

return .00001;

#endif }

184. Test for identity matrix. [LDF 2002.11.16.] TO DO: I should check the elements on the main diagonal for whether they differ from 1 by an amount <epsilon( ). If so, they should be set to 1.

185. Non-const version. ⟨ Declare Transform functions 168 ⟩ +≡

§186  3DLDF-1.1.5.1  NON-CONST VERSION 51

bool is identity ( ); 186. ⟨ Define Transform functions 169 ⟩ +≡

bool Transform ::is identity ( )

{ clean( ); for (int i = 0; i < 4; i^{++}) for (int j = 0; j < 4; j^{++})

if ((i ≡ j ∧ matrix [i][j] ≠ 1) ∨ ((i ≠ j) ∧ matrix [i][j] ≠ 0)) return false; return true;

}

187. const version. ⟨ Declare Transform functions 168 ⟩ +≡

bool is identity ( ) const;

188. ⟨ Define Transform functions 169 ⟩ +≡

bool Transform ::is identity ( ) const

{ Transform t; t = ∗this ; t.clean( ); for (int i = 0; i < 4; i^{++}) for (int j = 0; j < 4; j^{++})

if ((i ≡ j ∧ matrix [i][j] ≠ 1) ∨ ((i ≠ j) ∧ matrix [i][j] ≠ 0)) return false; return true;

}

189. Querying.

190. Get element.

Log

[LDF 2003.07.04.] Added this function.

⟨ Declare Transform functions 168 ⟩ +≡ real get element (const unsigned short row , const unsigned short col ) const;

191. ⟨ Define Transform functions 169 ⟩ +≡

real Transform ::get element (const unsigned short row , const unsigned short col ) const {

return matrix [row ][col ]; }

192. Show. ⟨ Declare Transform functions 168 ⟩ +≡

52  SHOW  3DLDF-1.1.5.1 §193

void show (string text = ) const; 193. ⟨ Define Transform functions 169 ⟩ +≡

void Transform ::show (string text ) const

{ if (text ≡ ) text = ; cout ≪ text ≪ ; for (int i = 0; i < 4; i^{++}) {

for (int j = 0; j < 4; j^{++}) { /∗ !! [LDF 2002.02.07.] Can’t use left here, and I can’t include ios. This causes an error with a reference to something in the C^{++} manual. Must write to K. Heuer and ask if he can fix it. ∗/

cout ≪ setw (7) ≪ setprecision(3) ≪ matrix [i][j] ≪ ␣ ; } cout ≪ endl ;

}

cout ≪ endl ≪ flush; }

194. Affine transformations. [LDF 2002.10.16.] The functions for the affine transformations all return a Transform representing the transformation, not ∗this . This makes it possible to chain expressions using operator∗=( ), e.g.,

Point pt0 ;

Point pt1 (1, 2, 3); Point pt2 (3, 4, 5); Transform t; t.rotate(90, 90, 90); pt0 ∗= pt1 ∗= pt2 ∗= t;

pt0 , pt1 , and pt2 are all rotated 90^{∘} around the x, y, and z-axes.

195. Scale.

Log

[LDF 2002.10.15.] BUG FIX: If the absolute value of an argument is < epsilon( ), the argument is now set to 0 instead of 1. Setting it to 1 causes no scaling to take place, which is not the effect of multiplying the corresponding coordinate by a number of very small magnitude.

[LDF 2003.03.25.] BUG FIX: Fixed conditional that tests whether all the arguments are 1.

⟨ Declare Transform functions 168 ⟩ +≡ Transform scale(real x, real y = 1, real z = 1);

§196  3DLDF-1.1.5.1  SCALE 53

196. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::scale(real x, real y, real z) {

Transform t; if (x ≡ 1 ∧ y ≡ 1 ∧ z ≡ 1) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; return t;

} real eps = epsilon( ); t.matrix [0][0] = (fabs (x) ≥ eps ) ? x : 0; t.matrix [1][1] = (fabs (y) ≥ eps ) ? y : 0; t.matrix [2][2] = (fabs (z) ≥ eps ) ? z : 0; ∗this ∗= t; clean( ); return t;

}

197. Shear. [LDF 2002.10.15.] Replaced the dummy definition of this function with a proper one. ⟨ Declare Transform functions 168 ⟩ +≡

Transform shear (real xy , real xz = 0, real yx = 0, real yz = 0, real zx = 0, real zy = 0);

54  SHEAR  3DLDF-1.1.5.1 §198

198. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::shear (real xy , real xz , real yx , real yz , real zx , real zy ) {

Transform t; real eps = epsilon( ); if (fabs (xy ) < eps ) xy = 0; if (fabs (xz ) < eps ) xz = 0; if (fabs (yx ) < eps ) yx = 0; if (fabs (yz ) < eps ) yz = 0; if (fabs (zx ) < eps ) zx = 0; if (fabs (zy ) < eps ) zy = 0; if (xy ≡ 0 ∧ xz ≡ 0 ∧ yx ≡ 0 ∧ yz ≡ 0 ∧ zx ≡ 0 ∧ zy ≡ 0) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; return t;

} t.matrix [1][0] = xy ; t.matrix [2][0] = xz ; t.matrix [0][1] = yx ; t.matrix [2][1] = yz ; t.matrix [0][2] = zx ; t.matrix [1][2] = zy ; (∗this ) ∗= t; clean( ); return t;

}

199. Shift. (Translation.)

200. real arguments. ⟨ Declare Transform functions 168 ⟩ +≡

Transform shift (real x, real y = 0, real z = 0);

201. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::shift (real x, real y, real z) {

real eps = epsilon( ); Transform t; if (x ≡ 0 ∧ y ≡ 0 ∧ z ≡ 0) return t; t.matrix [3][0] = (fabs (x) > eps ) ? x : 0; t.matrix [3][1] = (fabs (y) > eps ) ? y : 0; t.matrix [3][2] = (fabs (z) > eps ) ? z : 0; t.clean( ); (∗this ) ∗= t; clean( ); return t;

}

§202  3DLDF-1.1.5.1  POINT ARGUMENT 55

202. Point argument. [LDF 2002.04.24.] Added this function. It must be defined in points.web, because Point is an incomplete type here. ⟨ Declare Transform functions 168 ⟩ +≡

Transform shift (const Point &p);

203. Shift with multiplication. [LDF 2002.08.22.] Added this function. It takes real arguments and multiplies the appropriate elements of matrix by them. ⟨ Declare Transform functions 168 ⟩ +≡

Transform shift times (real x, real y = 1, real z = 1);

204. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::shift times (real x, real y, real z)

{ bool = false; /∗ true ∗/ if ( ) {

show ( ␣ ); } matrix [3][0] ∗= x; matrix [3][1] ∗= y; matrix [3][2] ∗= z; if ( ) {

show ( ␣ ); } return ∗this ;

}

205. Rotation around the main axes. rotate( ) will perform rotation about the x, y and z-axes in that order if called with multiple, non-zero arguments. Rotation only about the y and/or z-axis requires one or two dummy 0 arguments so that rotate( ) “knows” about which axis (or axes) to rotate. ⟨ Declare Transform functions 168 ⟩ +≡

56  ROTATION AROUND THE MAIN AXES  3DLDF-1.1.5.1 §206

Transform rotate(real x, real y = 0, real z = 0); 206. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::rotate(real x, real y, real z){ bool = false; /∗ true ∗/ Transform t all ; real eps = epsilon( ); if (x ≡ 0 ∧ y ≡ 0 ∧ z ≡ 0) {

if (  ) cerr ≪  ␣           ␣      ␣  ≪

        ␣        ␣     ␣    ␣     ␣         ␣        ␣  ≪ flush;

return t all ; } Transform t x ; Transform t y ; Transform t z ; real ssin; real ccos ; real temp1 ; real temp2 ; int i;

207. Rotation around the x-axis. ⟨ Define Transform functions 169 ⟩ +≡

if (x ≠ 0) { /∗ !! Reversed direction of rotation because I didn’t like the way it was. ∗/ x ∗= − /180.0; /∗ Convert to radians. ∗/ ssin = sin(x); ccos = cos (x); for (i = 0; i < 4; i^{++}) {

temp1 = (t x .matrix [i][1] ∗ ccos ) − (t x .matrix [i][2] ∗ ssin); temp2 = (t x .matrix [i][1] ∗ ssin) + (t x .matrix [i][2] ∗ ccos ); t x .matrix [i][2] = (fabs (temp2 ) ≥ eps ) ? temp2 : 0; t x .matrix [i][1] = (fabs (temp1 ) ≥ eps ) ? temp1 : 0;

} } /∗ if ∗/

208. Rotation around the y-axis. ⟨ Define Transform functions 169 ⟩ +≡

if (y ≠ 0) { /∗ !! Reversed direction of rotation because I didn’t like the way it was. ∗/ y ∗= − /180.0; ssin = sin(y); ccos = cos (y); for (i = 0; i < 4; i^{++}) {

temp1 = (t y .matrix [i][0] ∗ ccos ) + (t y .matrix [i][2] ∗ ssin); temp2 = (−t y .matrix [i][0] ∗ ssin) + (t y .matrix [i][2] ∗ ccos ); t y .matrix [i][2] = (fabs (temp2 ) ≥ eps ) ? temp2 : 0; t y .matrix [i][0] = (fabs (temp1 ) ≥ eps ) ? temp1 : 0;

§209  3DLDF-1.1.5.1  ROTATION AROUND THE MAIN AXES 57

} } /∗ if ∗/ 209. Rotation around the z-axis. ⟨ Define Transform functions 169 ⟩ +≡

if (z ≠ 0) { z ∗= /180.0; ssin = sin(z); ccos = cos (z); for (int i = 0; i < 4; i^{++}) {

temp1 = (t z .matrix [i][0] ∗ ccos ) − (t z .matrix [i][1] ∗ ssin); temp2 = (t z .matrix [i][0] ∗ ssin) + (t z .matrix [i][1] ∗ ccos ); t z .matrix [i][1] = (fabs (temp2 ) ≥ eps ) ? temp2 : 0; t z .matrix [i][0] = (fabs (temp1 ) ≥ eps ) ? temp1 : 0;

} } /∗ if ∗/ t all ∗= t x ; t all ∗= t y ; t all ∗= t z ; t all .clean( ); (∗this ) ∗= t all ; clean( ); return t all ; } /∗ End of rotate( ). ∗/

210. Rotation around an arbitrary axis.

211. Point arguments. Defined in points.web because Point is an incomplete type here.

Log

[LDF 2002.4.7.] Added default value for angle ≡ 180. [LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now

overloads rotate( ) with three real arguments.

⟨ Declare Transform functions 168 ⟩ +≡ Transform rotate(Point p0 , Point p1 , const real angle = 180);

58 PATH ARGUMENT 3DLDF-1.1.5.1 §212

212. Path argument. [LDF 2002.05.03.] Defined in paths.web because Path is an incomplete type here.

Log

[LDF 2002.05.03.] Added this function.

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Declare Transform functions 168 ⟩ +≡ Transform rotate(const Path &p, const real angle = 180);

213. Alignment with an axis. Defined in points.web, because it uses Points, which haven’t been defined yet. ⟨ Declare Transform functions 168 ⟩ +≡

Transform align with axis (Point p0 , Point p1 , char axis = ); /∗ Default is the z-axis. ∗/

214. Matrix multiplication.

215. With assignment.

216. real argument. [LDF 2002.11.19.] This function multiplies each element of Matrix by the real argument r and returns r. This makes it possible to chain invocations of this function. Not currently used anywhere, but it may turn out to be useful for something.

Log

[LDF 2002.08.22.] Added this function.

[LDF 2002.11.19.] Changed return value from ∗this to r.

⟨ Declare Transform functions 168 ⟩ +≡ real operator∗=(real r);

217. ⟨ Define Transform functions 169 ⟩ +≡

real Transform ::operator∗=(real r)

{

for (int i = 0; i < 4; i^{++})

for (int j = 0; j < 4; j^{++}) matrix [i][j] ∗= r; clean( ); return r;

}

218. Transform argument.

Log

[LDF 2002.11.06.] If t is the identity Transform, it is returned right away. If ∗this is, it is set to t using operator=( ). BUG FIX: Now t is always returned, instead of ∗this . This makes it possible to chain expressions using this function.

⟨ Declare Transform functions 168 ⟩ +≡ Transform operator∗=(const Transform &t);

§219  3DLDF-1.1.5.1  TRANSFORM ARGUMENT 59

219. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::operator∗=(const Transform &t) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (t.is identity ( )) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ ␣ ≪ flush; return t;

} else if (is identity ( )) {

if (  ) cout ≪  ␣  ␣   ␣        ␣              ␣ ≪

        ␣     ␣  ␣ ␣    ␣         ␣  ≪ flush;

return (∗this = t); } Matrix temp matrix = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; for (int i = 0; i < 4; i^{++})

for (int k = 0; k < 4; k^{++})

for (int j = 0; j < 4; j^{++}) temp matrix [i][k] += matrix [i][j] ∗ t.matrix [j][k]; for (int i = 0; i < 4; i^{++})

for (int j = 0; j < 4; j^{++}) {

matrix [i][j] = temp matrix [i][j]; }

clean( ); if ( ) cout ≪ ␣ ≪ flush; return t;

}

220. Plain multiplication.

221. real argument. [LDF 2002.08.22.] Added this function. Not currently used anywhere, but it may turn out to be useful for something. ⟨ Declare Transform functions 168 ⟩ +≡

Transform operator∗(const real r) const;

222. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::operator∗(const real r) const {

Transform t = ∗this ; t ∗= r; t.clean( ); return t;

}

223. Transform argument. ⟨ Declare Transform functions 168 ⟩ +≡

Transform operator∗(const Transform t) const;

60 TRANSFORM ARGUMENT 3DLDF-1.1.5.1 §224

224. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::operator∗(const Transform t) const

{ Transform a = ∗this ; a ∗= t; a.clean( ); return a;

}

225. Matrix inversion.

226. const version (no assignment). It would be easy to generate the inverses of the transformations that I call explicitly using rotate( ), shift ( ), etc., as I go along. However, it is not possible to do this for the ones produced using operator∗( ) and operator∗=( ). So, since a matrix inversion routine is needed anyway, I don’t bother to generate the inverses as I go along.

TO DO: Get format for references! inverse( ) uses the Gauß-Jordan algorithm with column pivot search. I’ve taken the algorithm from Stoer, Josef. Numerische Mathematik 1^{1} and adapted it to C^{++}.

Log

[LDF 2002.12.01.] !! Changed hi from real to int because of a warning, when I tried to compile under GNU/Linux. I think hi can be an int, but test to be sure!

⟨ Declare Transform functions 168 ⟩ +≡ Transform inverse( ) const;

1 Stoer, Josef. Numerische Mathematik 1. Achte, neu bearbeitete und erweiterte Auflage. Springer-Verlag. Berlin 1999. ISBN 3-540-66154-9, page 205.

§227  3DLDF-1.1.5.1  CONST VERSION (NO ASSIGNMENT) 61

227. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::inverse( ) const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ endl ≪ flush;

int i; int j; int k; int row ; const int n = 4; real max ; real hr ; int hi ; /∗ [LDF 2002.12.01.] See above in “Log”. ∗/ real hv [n]; Transform t; if ( ) {

cout ≪ ␣ ; } for (i = 0; i < 4; i^{++}) {

for (j = 0; j < 4; j^{++}) { t.matrix [i][j] = matrix [i][j]; if ( ) {

cout ≪ matrix [i][j] ≪ ␣ ; }

}

if ( ) {

cout ≪ ; }

} if ( ) {

cout ≪ ;

t.show ( );

cout ≪ ␣ ␣ ␣ ≪ flush; getchar ( );

} int p[n]; for (int j = 0; j < n; j^{++}) p[j] = j; for (j = 0; j < n; j^{++}) {

62 CONST VERSION (NO ASSIGNMENT) 3DLDF-1.1.5.1 §228

228. Pivot search. ⟨ Define Transform functions 169 ⟩ +≡

max = fabs (t.matrix [j][j]); row = j; for (i = j + 1; i < n; i^{++}) {

if (fabs (t.matrix [i][j]) > max ) { max = fabs (t.matrix [i][j]); row = i;

} /∗ if ∗/ } /∗ inner for ∗/ if ( ) {

cout ≪ ␣ ␣ ≪ max ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ row ≪ endl ≪ flush; } if (max ≡ 0) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣␣ ␣ ≪ flush; return ;

}

229. Row exchange. ⟨ Define Transform functions 169 ⟩ +≡

if (row > j) {

for (k = 0; k < n; k^{++}) { hr = t.matrix [j][k]; t.matrix [j][k] = t.matrix [row ][k]; t.matrix [row ][k] = hr ;

} /∗ for ∗/

hi = p[j];

p[j] = p[row ];

p[row ] = hi ; } /∗ if ∗/

if (  ) cout ≪  ␣   ␣  ≪ flush;

230. Transformation. ⟨ Define Transform functions 169 ⟩ +≡

if ( ) cout ≪ ≪ j ≪ ≪ j ≪ ␣ ␣ ≪ t.matrix [j][j] ≪ endl ≪ flush; hr = 1/t.matrix [j][j]; for (i = 0; i < n; i^{++}) t.matrix [i][j] = hr ∗ t.matrix [i][j]; t.matrix [j][j] = hr ; for (k = 0; k < n; k^{++})

if (k ≠ j) {

for (i = 0; i < n; i^{++})

if (i ≠ j) t.matrix [i][k] −= t.matrix [i][j] ∗ t.matrix [j][k];

t.matrix [j][k] ∗= −hr ; }

} /∗ outer for ∗/

if (  ) cout ≪  ␣  ≪ flush;

231. Column exchange. ⟨ Define Transform functions 169 ⟩ +≡

for (i = 0; i < n; i^{++}) { for (k = 0; k < n; k^{++}) hv [p[k]] = t.matrix [i][k]; for (k = 0; k < n; k^{++}) t.matrix [i][k] = hv [k];

} /∗ for ∗/

if ( ) {

cout ≪  ␣      ␣  ≪ flush;
cout ≪  ␣  ≪ endl ≪ flush;

}

if ( ) cout ≪ ␣ ≪ endl ≪ flush;

return t; }

232. Non-const version (with assignment). [LDF 2002.10.20.] Added this function. I thought of calling in “invert ( )”, but I decided against it, because I thought having two functions called “inverse( )” and “invert ( )” would be confusing.

There is no point in calling this function with assign ≡ false, since it is equivalent to the const version above with no argument. If it is called with assign ≡ false, a warning is issued, the const version is invoked, and its return value is returned. ⟨ Declare Transform functions 168 ⟩ +≡

Transform inverse(bool assign);

233. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::inverse(bool assign)

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣                       ␣  ≪ flush;

if (assign ≡ false) {

cerr ≪  ␣  ␣                       ␣  ≪

          ␣  ␣      ␣␣       ␣  ␣      ␣  ␣     ␣ ≪
          ␣    ␣        ␣     ␣ ␣         ␣  ≪
          ␣  ␣       ␣  ␣    ␣     ␣␣  ≪ flush;

return inverse( ); } if ( ) cout ≪ ␣ ␣ ≪ flush; return (∗this = inverse( ));

}

234. Global variables. ⟨ Global variables 18 ⟩ +≡

64  GLOBAL VARIABLES  3DLDF-1.1.5.1 §235

Transform user transform; 235. ⟨ Declarations for the header file 21 ⟩ +≡

extern Transform user transform;

236. Global constants. ⟨ Global constants 22 ⟩ +≡

extern const Transform ( ); extern const Transform ;

237. ⟨ Declarations for the header file 21 ⟩ +≡

extern const Transform ; extern const Transform ;

238. Putting Transform together.

239. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define class Transform 166 ⟩ ⟨ Global variables 18 ⟩ ⟨ Global constants 22 ⟩ ⟨ Define Transform functions 169 ⟩

§240  3DLDF-1.1.5.1  PUTTING TRANSFORM TOGETHER 65

240. This is what’s written to transfor.h. ⟨ 240 ⟩ ≡

⟨ Define class Transform 166 ⟩

⟨ Declarations for the header file 21 ⟩

241. Shape (shapes.web). [LDF 2002.10.20.] Shape is an abstract class. This means that no objects of type Shape may be declared. Shape is used as a base class for all “drawable” classes, e.g., Point, Path, and Dodecahedron. All objects that are put onto a Picture must be either Shapes or Labels.

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

242. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include

243. Shape class definition.

244. class Point is known when shapes.c is compiled, because it’s declared (but not defined) in transfor.web, which is processed by first. ?? Apparently, both the return value and the argument types of pure virtual functions must be the same,

otherwise the derived classes will cause compiler errors. Check where this is stated.

Log

[LDF 2003.05.16.] Added declarations of get minimum z ( ) and get mean z ( ).

format Shape int

⟨ Define Shape class 244 ⟩ ≡

class Shape { protected: static const signed short ; /∗ const values used for output. ∗/

static const signed short ;

static const signed short ;

static const signed short ;

static const signed short ;

static const signed short ;

static const signed short ;

static const signed short ;

See also section 245. This code is used in sections 248 and 249.

66 SHAPE CLASS DEFINITION 3DLDF-1.1.5.1 §245

245. Shape function declarations. All Shape functions are pure virtual functions.

[LDF 2002.10.20.] I’ve thought about getting rid of get copy ( ) a couple of times, and using ⟨type⟩( ) instead, but it’s not possible: get copy ( ) is used in Picture functions for objects of types derived from Shape where the type is not known. The compiler must resolve to the correct version of get copy ( ), so a virtual Shape function is needed. The “ ⟨type⟩( )” functions are not virtual Shape functions, and can’t be, because the names of the types are part of the name of the functions. I could solve this problem by renaming get copy ( ) create new ( ), but what I wanted to do was have a template function create new ( ) (or just create( )). So far, I haven’t been able to get this to work. So, for the time being, I’m leaving things as they are.

[LDF 2002.10.23.] The default arguments to show ( ) are necessary, since ⟨ Define Shape class 244 ⟩ +≡ public: virtual void show (string text = , char coords = , const bool do persp = true, const

bool do apply = true, Focus ∗f = 0, const unsigned short proj = 0, const real factor = 1) const = 0;

virtual Shape ∗get copy ( ) const = 0; virtual bool is on free store( ) const = 0; virtual bool set on free store(bool b = true) = 0; virtual void clear ( ) = 0; virtual void output ( ) = 0; virtual vector⟨Shape ∗⟩ extract (const Focus &, const unsigned short proj , real factor ) = 0; virtual Transform rotate(const real, const real, const real) = 0; virtual Transform scale(real, real, real) = 0; virtual Transform shear (real xy , real xz , real yx , real yz , real zx , real zy ) = 0; virtual Transform shift (real, real, real) = 0; virtual Transform rotate(const Point &, const Point &, const real) = 0; virtual Transform operator∗=(const Transform &) = 0; virtual void apply transform(void) = 0; virtual bool set extremes ( ) = 0; virtual real get minimum z ( ) const = 0; virtual real get maximum z ( ) const = 0; virtual real get mean z ( ) const = 0; virtual const valarray⟨real⟩ get extremes ( ) const = 0; virtual void suppress output ( ) = 0; virtual void unsuppress output ( ) = 0; } ;

246. Static data members. ⟨ Define static Shape member variables 246 ⟩ ≡

const signed short Shape :: = 1; const signed short Shape :: = 2; const signed short Shape :: = 3; const signed short Shape :: = 4; const signed short Shape :: = −1; const signed short Shape :: = −2; const signed short Shape :: = −3; const signed short Shape :: = −4;

This code is used in section 248.

247. Putting Shape together.

§248  3DLDF-1.1.5.1  PUTTING SHAPE TOGETHER 67

248. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define Shape class 244 ⟩ ⟨ Define static Shape member variables 246 ⟩

68  PUTTING SHAPE TOGETHER  3DLDF-1.1.5.1 §249

249. This is what’s written to shapes.h. ⟨ 249 ⟩ ≡

⟨ Define Shape class 244 ⟩

250. Picture and Label (pictures.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

251. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include

252. Label. [LDF 2002.10.20.] Labels are the only objects, other than Shapes, that can be put onto Pictures. They are created by the functions label ( ) and dotlabel ( ), which are currently defined for Points and Paths.

253. Label class definition. A Label contains a pointer to a Point, which is its location, a bool to indicate whether the label should have a dot or not, a string for the text of the label and a string for positioning the text with respect to the label. pt must be a pointer, because Point is an incomplete type

here. position can be any of the strings used in METAFONT, i.e.,  ,  ,  ,  ,  ,
,  , or  .

[LDF 2002.10.09.] Labels are currently only ever created on the free store.

format Label int

⟨ Define classes 253 ⟩ ≡

class Label { friend class Point; friend class Picture; Point ∗pt ; bool dot ; string text ; string position;

public: static bool ;

⟨ Declare Label functions 255 ⟩ };

See also section 261. This code is used in sections 305 and 306.

§254  3DLDF-1.1.5.1  STATIC DATA MEMBERS 69

254. Static data members. is used for globally enabling or suppressing putting Labels onto Pictures: If is false, then label ( ) and dotlabel ( ) have no effect, i.e., no Label is put onto the Picture. Note that Picture has a private data member do labels , which is for enabling or suppressing output of Labels for a single Picture (see below).

Log

[LDF 2002.10.20.] Added this section. was formerly a global variable defined in pspglb.web.

⟨ Initialize static Label data members 254 ⟩ ≡

bool Label :: = true;

This code is used in section 305.

255. Declarations for Label functions. These must be defined in points.web, because they require operations on pt , and Point is an incomplete type in this file.

Log

[LDF 2002.10.23.] Added arguments proj and factor .

⟨ Declare Label functions 255 ⟩ ≡ void output (const Focus &f, const unsigned short proj , real factor , const Transform &t); Label ∗get copy ( ) const;

This code is used in section 253.

256. namespace Projections.

Log

[LDF 2003.05.11.] Added .

⟨ Declare namespace Projections 256 ⟩ ≡

namespace Projections { extern const unsigned short = 0; extern const unsigned short = 1; extern const unsigned short = 2; extern const unsigned short = 3; extern const unsigned short = 4; extern const unsigned short = 5;

};

This code is used in section 305.

70 NAMESPACE PROJECTIONS  3DLDF-1.1.5.1  §257

257. External. ⟨ extern declaration of namespace Projections 257 ⟩ ≡

namespace Projections { extern const unsigned short ; extern const unsigned short ; extern const unsigned short ; extern const unsigned short ; extern const unsigned short ; extern const unsigned short ;

};

This code is used in section 306.

258. namespace Sorting. This namespace contains constants that are passed to Picture ::output ( ) for determining how the Shapes on the Picture are sorted in order to determine the order in which they are output.

Log

[LDF 2003.05.16.] Added this namespace.

⟨ Declare namespace Sorting 258 ⟩ ≡

namespace Sorting { extern const unsigned short = 0; extern const unsigned short = 1; extern const unsigned short = 2; extern const unsigned short = 3;

};

This code is used in section 305.

§259  3DLDF-1.1.5.1  NAMESPACE SORTING  71

259. External. ⟨ extern declaration of namespace Sorting 259 ⟩ ≡

namespace Sorting { extern const unsigned short ; extern const unsigned short ; extern const unsigned short ; extern const unsigned short ;

};

This code is used in section 306.

260. Picture.

format Picture int

261. Picture class definition. [LDF 2002.08.06.] Note that Label has a public static data member named , which is used for globally enabling or suppressing putting Labels onto Pictures (see above).

Picture ::do labels , on the other hand, is for enabling or suppressing the output of Labels for a single Picture. If a Picture is output when do labels is false for that Picture, the Labels are not output. However, the Labels are still on the Picture. If do labels is reset to true and the Picture is output again, the Labels will be output this time.

[LDF 2002.04.25.] Added do labels . It’s set to true in the constructors and can be set to false using suppress labels ( ). ⟨ Define classes 253 ⟩ +≡

class Picture { Transform transform; vector⟨Shape ∗⟩ shapes ; vector⟨Label ∗⟩ labels ; bool do labels ;

public: ⟨ Declare Picture functions 263 ⟩

};

262. Constructors.

263. Default constructor. (No arguments). ⟨ Declare Picture functions 263 ⟩ ≡

Picture( );

See also sections 265, 267, 269, 270, 272, 274, 275, 276, 280, 283, 285, 286, 288, 289, 291, 293, 295, 298, 299, 300, and 301. This code is used in section 261.

264. ⟨ Define Picture functions 264 ⟩ ≡

Picture ::Picture( )

: do labels (true) { }

See also sections 271, 273, 277, 281, 284, 287, 290, 292, 294, 296, 417, 440, 587, 588, 589, 590, 592, 593, 594, 595, 596, 597,

and 598. This code is used in sections 305 and 633.

265. Copy constructor. !! PORTING. [LDF 2002.12.05.] Moved to points.web because I’ve moved Picture ::operator=( ) to points.web, so the latter is undefined in this file. I’ve had to do these things because of differences between the DEC compiler and the GNU compiler. ⟨ Declare Picture functions 263 ⟩ +≡

Picture(const Picture &p);

266. Destructor. [LDF 2002.10.20.] Picture does not currently have a destructor. clear ( ) takes care of deallocating memory and clearing shapes and labels . Defining a destructor would probably cause problems.

267. Assignment. TO DO: Add TEX macro for “PORTING”. !! PORTING. [LDF 2002.12.05.] Moved to points.web because Picture ::clear ( ) and Label ::get copy ( ) are undefined in this file. This didn’t cause a problem with the DEC compiler, but it does with the GNU Compiler. ⟨ Declare Picture functions 263 ⟩ +≡

void operator=(const Picture &p);

268. Adding elements.

269. Add Picture. This function must be defined in points.web, because it uses Point, which is an incompletely defined class here.

[LDF 2002.04.17.] It seems to be most useful to have the argument Picture p be non-const, in order to be able to shift it and add it to ∗this multiple times. For this to work, it must be possible to set p.transform to the identity matrix afterwards. It is possible to do this explicitly by calling reset transform( ) on the Picture following the call to operator+=( ), but it’s more convenient to have it done automatically. If it turns out to be useful, I can add a const version of this function.

Log

[LDF 2002.04.17.] Added this declaration.

⟨ Declare Picture functions 263 ⟩ +≡ void operator+=(const Picture &p);

270. Add Shape. ⟨ Declare Picture functions 263 ⟩ +≡

void operator+=(Shape ∗s);

§271  3DLDF-1.1.5.1  ADD SHAPE 73

271. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::operator+=(Shape ∗s) {

shapes .push back (s); }

272. Add Label. ⟨ Declare Picture functions 263 ⟩ +≡

void operator+=(Label ∗label );

273. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::operator+=(Label ∗label ) {

labels .push back (label ); }

274. Suppress Labels. [LDF 2002.04.25.] Added this function. Sometimes it’s irritating to have the labels when a Picture is copied and transformed, and both the original and the transformed versions are output. ⟨ Declare Picture functions 263 ⟩ +≡

inline void suppress labels ( ) {

do labels = false; }

275. Unsuppress Labels.

Log

[LDF 2002.12.20.] Added this function.

⟨ Declare Picture functions 263 ⟩ +≡ inline void unsuppress labels ( ) {

do labels = true; }

276. Kill Labels.

Log

[LDF 2003.05.07.] Added this function.

⟨ Declare Picture functions 263 ⟩ +≡ void kill labels ( );

74  KILL LABELS  3DLDF-1.1.5.1 §277

277. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::kill labels ( )

{

labels .clear ( ); }

278. Transformations. Transformations for Pictures are saved up, and then performed when the Picture is output.

279. Affine transformations.

280. Scale. ⟨ Declare Picture functions 263 ⟩ +≡

Transform scale(real x, real y = 1, real z = 1);

281. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::scale(real x, real y, real z)

{

return transform.scale(x, y, z); }

282. Shift. (Translation.)

283. real version. ⟨ Declare Picture functions 263 ⟩ +≡

Transform shift (real x, real y = 0, real z = 0);

284. shift ( ) returns a Transform representing the shift, not ∗this . This makes it possible to apply the transformation to other objects. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::shift (real x, real y, real z)

{

return transform.shift (x, y, z); }

285. Point version. This function must defined in points.web, because Point is an incompletely defined type here. ⟨ Declare Picture functions 263 ⟩ +≡

Transform shift (const Point &p);

286. Rotation around the main axes. rotate( ) will perform rotation about the x, y and z-axes in that order if called with multiple, non-zero arguments. Rotation only about the y and/or z-axis requires one or two dummy 0 arguments so that rotate( ) “knows” about which axis (or axes) to rotate. ⟨ Declare Picture functions 263 ⟩ +≡

Transform rotate(const real x, const real y = 0, const real z = 0); 287. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::rotate(const real x, const real y, const real z) {

return transform.rotate(x, y, z); }

288. Rotation around an arbitrary axis. [LDF 2002.05.03.] This function is defined in points.web, because it has Point arguments, and Point is an incomplete type in this file.

Log

[LDF 2002.05.03.] Added this declaration. [LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now

overloads rotate( ) with three real arguments.

⟨ Declare Picture functions 263 ⟩ +≡

Transform rotate(const Point &p0 , const Point &p1 , const real angle = 180); /∗ Remember to add shear! ∗/

289. Set transform.

Log

[LDF 2003.01.17.] Made non-inline and changed t from plain Transform to const Transform &.

⟨ Declare Picture functions 263 ⟩ +≡ Transform set transform(const Transform &t);

290. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::set transform(const Transform &t) {

transform = t;

return t; }

291. Multiplying transform.

Log

[LDF 2003.01.17.] Changed t from plain Transform to const Transform &.

⟨ Declare Picture functions 263 ⟩ +≡ Transform operator∗=(const Transform &t);

76  MULTIPLYING TRANSFORM  3DLDF-1.1.5.1 §292

292. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::operator∗=(const Transform &t) {

transform ∗= t; return t;

}

293. Show. ⟨ Declare Picture functions 263 ⟩ +≡

void show (string text = , bool stop = false);

294. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::show (string text , bool stop) {

cout ≪ ␣ ␣ ≪ text ≪ ≪ flush; transform.show ( ); cout ≪ ␣ ␣ ≪ shapes .size( ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ labels .size( ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ do labels ≪ endl ≪ flush; cout ≪ ␣ ; for (vector⟨Shape ∗⟩::iterator iter = shapes .begin( ); iter ≠ shapes .end ( ); ^{++}iter ) (∗∗iter ).show ( ); if (stop) {

cout ≪ ␣ ␣ ␣ ≪ flush; getchar ( );

} cout ≪ ␣ ␣ ≪ flush;

}

295. Show transform. ⟨ Declare Picture functions 263 ⟩ +≡

void show transform(string text =  ␣    ␣  );

§296  3DLDF-1.1.5.1  SHOW TRANSFORM 77

296. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::show transform(string text )

{

transform.show (text ); }

297. Output. [LDF 2002.09.18.] Added the optional real arguments min x proj , max x proj , etc. The purpose of these is to suppress output of Shapes whose projective extremes fall outside of these limits, whereby the “z” values are not currently checked. They are not set for a particular Focus or Picture, but for a particular invocation of output ( ). I believe the default values are sufficiently generous, but they can always be changed if it turns out that they’re not. Alternatively, I could store them in the Picture or the Focus, if that turns out be more convenient. They are checked in Picture ::check projection limits ( ).

298. Focus argument. ⟨ Declare Picture functions 263 ⟩ +≡

void output (const Focus &f, const unsigned short projection = Projections :: , real factor = 1, const unsigned short sort value = Sorting :: , const bool do warnings = true, const real min x proj = −40, const real max x proj = 40, const real min y proj = −40, const real max y proj = 40, const real min z proj = −40, const real max z proj = 40);

299. No Focus argument. ⟨ Declare Picture functions 263 ⟩ +≡

void output (const unsigned short proj = Projections :: , real factor = 1, const unsigned short sort value = Sorting :: , const bool do warnings = true, const real min x proj = −40, const real max x proj = 40, const real min y proj = −40, const real max y proj = 40, const real min z proj = −40, const real max z proj = 40);

300. Clear. Defined in points.web. ⟨ Declare Picture functions 263 ⟩ +≡

void clear ( );

301. Reset transform. [LDF 2002.04.17.] Added this function. ⟨ Declare Picture functions 263 ⟩ +≡

inline void reset transform( )

{

transform.reset ( ); }

302. Global variables. ⟨ Global variables 18 ⟩ +≡

Picture current picture;

303. ⟨ Declarations for the header file 21 ⟩ +≡

extern Picture current picture;

304. Putting Picture and Label together.

78  PUTTING PICTURE AND LABEL TOGETHER  3DLDF-1.1.5.1 §305

305. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Declare namespace Projections 256 ⟩ ⟨ Declare namespace Sorting 258 ⟩ ⟨ Define classes 253 ⟩ ⟨ Initialize static Label data members 254 ⟩ ⟨ Global variables 18 ⟩ ⟨ Define Picture functions 264 ⟩

§306  3DLDF-1.1.5.1  PUTTING PICTURE AND LABEL TOGETHER 79

306. This is what’s written to pictures.h. ⟨ 306 ⟩ ≡

⟨ extern declaration of namespace Projections 257 ⟩

⟨ extern declaration of namespace Sorting 259 ⟩

⟨ Define classes 253 ⟩

⟨ Declarations for the header file 21 ⟩

307. Point (points.web).

[LDF 2002.10.20.] Point is the most basic drawable (not fillable!) type. All of the other Shapes contain Points and are ultimately defined by their Points and the relationships among them. It is therefore understandable that points.web is by far the largest of the source files of 3DLDF and that Point has the most functions of any class in 3DLDF. Many of the functions in the other classes do little more than apply the Point version of the function to their Points.

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

308. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include #include #include

309. Point class definition. [LDF 2002.10.20.]

• world coordinates contains the coordinates of the Point in the global coordinate system.

• user coordinates and view coordinates are not currently used.

• user coordinates is intended for use with a user-defined coordinate system. For example, it may be convenient to define a coordinate system based on a plane defined by an object in a drawing. The user-defined coordinate system will be defined in terms of the global coordinate system and the world coordinates can be derived from the user coordinates by using the appropriate transformation.

• projective coordinates is used for projecting the three-dimensional Points onto two-dimensions for output. Currently, the only projection routines are for perspective and parallel projection. I plan to add others (axionometric, etc.) soon.

• transform is used for storing the transformations that are applied the Point. It is not necessary to update world coordinates (or user coordinates , if they’re being used) every time a Point is transformed. The transformations can be saved up and their result applied to the Point when needed. This will be when the Point or the Shape or Label containing it is output, or when a function (such as get x ( )) requires up-to-date coordinate values.

• drawdot value, drawdot color , and pen are used in the drawing and undrawing functions and in Point ::output ( ). They are explained below.

80 POINT CLASS DEFINITION 3DLDF-1.1.5.1 §309

• projective extremes is used in outputting Pictures. It’s for culling Points that are invisible using a particular Focus, or that lie outside the boundaries passed as arguments to Picture ::output ( ).

• do output is for enabling or suppressing output of a Point. It’s needed when a Point has been culled, as described above. Culling does not actually remove a Point (or any other Shape) from a Picture, so a way of suppressing output is needed. However, it must be possible to enable output again, because the Picture may be output again using a different Focus and/or different values for the boundaries.

• measurement units is a string that is attached to the numerical values of the projective coordinates when the METAPOST code is output to out stream. It is currently and at the present time (2002.10.20), it’s not a good idea to use more than one value for a single drawing. Changing this will only become urgent when I start writing the input routine. TO DO.

Log

[LDF 2003.04.01.] Added , , , and . They are used in label ( ) for labelling Points using the values in world coordinates , projective coordinates , etc.

[LDF 2003.05.06.] Changed  ,  ,  , and  to  ,
,  , and  . Added  ,  ,

, and for suppressing the z-coordinate.

[LDF 2003.05.20.] Added .

format Point Shape

⟨ Define class Point 309 ⟩ ≡

class Point : protected Shape {

friend Transform Transform ::align with axis (Point, Point, char); private: Transform transform;

bool on free store; valarray⟨real⟩ world coordinates ; valarray⟨real⟩ user coordinates ; valarray⟨real⟩ view coordinates ; valarray⟨real⟩ projective coordinates ; signed short drawdot value; const Color ∗drawdot color ; string pen;

protected: /∗ LDF 2002.09.18. Added projective extremes . It contains the minimum and maximum

values for x, y, and z in projective coordinates . ∗/ valarray⟨real⟩ projective extremes ; bool do output ; /∗ LDF 2002.09.18. Added this data member. ∗/

public: static string measurement units ; static real ; static real ; static const short ; static const short ; static const short ; static const short ; static const short ; static const short ; static const short ; static const short ; static const short ; ⟨ Declare Point constructors 324 ⟩ ⟨ Declare Point functions 329 ⟩

};

This code is used in sections 633 and 634.

§310  3DLDF-1.1.5.1  POINT CLASS DEFINITION 81

310.

Log

LDF 2003.04.01. Added initialization of , , , and . They are used in label ( ) for labelling Points using the values in world coordinates , projective coordinates , etc. !! KLUDGE: Using the macro because the numeric limits template doesn’t seem to be available under GNU/Linux using GCC, at least not on the computer I’m using.

LDF 2003.05.06. Added initialization of  ,  ,  , and
LDF 2003.05.22. BUG FIX: Changed  so that it’s one less than  .

Previously, it had the same value.

⟨ Define static Point data members 310 ⟩ ≡ string Point ::measurement units = ; real Point :: = 0; real Point :: = 0;

const short Point ::  =  ;
const short Point ::  =  − 1;
const short Point ::  =  − 2;
const short Point ::  =  − 3;
const short Point ::  =  − 4;
const short Point ::  =  − 5;
const short Point ::  =  − 6;
const short Point ::  =  − 7;
const short Point ::  =  − 8;

This code is used in section 633.

311. Type definitions and utility structures. Some of the types are simple enough to be defined using typedef , but others require struct definitions.

Log

[LDF 2002.04.10.] Added these formatting instructions. They are duplicated using “@s” in

cwdriver.web.

format point pair Point
format bool point Point
format bool point pair Point
format bool point quadruple Point
format bool real point Point

312. point pair and bool point pair. ⟨ Type definitions 15 ⟩ +≡

typedef pair⟨Point, Point⟩ point pair; typedef pair⟨bool point, bool point⟩ bool point pair;

313. bool point.

Log

LDF 2002.04.15. Added this section. bool point was formerly a simple typedef . I’ve had to change it to a struct, in order for Point ::intersection points ( ) to return one.

82 BOOL POINT  3DLDF-1.1.5.1  §313

LDF 2003.05.30. Removed the definition of the default constructor to the new section ⟨ Define bool point functions 314 ⟩. See below for an explanation.

⟨ Type definitions 15 ⟩ +≡

struct bool point { bool b; Point pt ; bool point( ); bool point(bool bb, const Point &ppt ) : b(bb), pt (ppt ) { } void operator=(const bool point &bp) {

b = bp.b;

pt = bp.pt ; }

};

§314  3DLDF-1.1.5.1  BOOL POINT  83

314.

Log

LDF 2003.05.30. Added this section, and the definition of bool point(void). Previously, b and pt were not set, so their values were unpredictable. I had to remove the definition from the declaration of bool point, because isn’t defined, when the declaration is read by the compiler.

⟨ Define bool point functions 314 ⟩ ≡ bool point ::bool point( ) {

b = false; pt = ;

}

This code is cited in section 313. This code is used in section 633.

315. bool point quadruple. It would be possible to define this as a pair of pairs, but then the individual element s would be nested inconveniently. ⟨ Type definitions 15 ⟩ +≡

struct bool point quadruple { bool point first ; bool point second ; bool point third ; bool point fourth; bool point quadruple( ); bool point quadruple(bool point a, bool point b, bool point c, bool point d) : first (a), second (b), third (c), fourth(d) { } void operator=(const bool point quadruple &arg ) {

first .b = arg .first .b;

first .pt = arg .first .pt ;

second .b = arg .second .b; second .pt = arg .second .pt ; third .b = arg .third .b; third .pt = arg .third .pt ; fourth.b = arg .fourth.b; fourth.pt = arg .fourth.pt ;

} };

84  DEFAULT CONSTRUCTOR FOR BOOL POINT QUADRUPLE  3DLDF-1.1.5.1 §316

316. Default Constructor for bool point quadruple.

Log

LDF 2003.06.1. Added this section. Redefined the default constructor bool point quadruple(void), so that first , second , third , and fourth are all set to . In order to do this, it was necessary to remove the definition from the declaration of bool point quadruple, because when the compiler sees it, isn’t defined yet.

⟨ Define bool point quadruple functions 316 ⟩ ≡ bool point quadruple ::bool point quadruple( ) : first ( ), second ( ), third ( ),

fourth( ) { }

This code is used in section 633.

317. bool real point. [LDF 2002.04.10.] Added this type. Line ::intersection point ( ) returns a bool real point. I may change Point ::intersection point ( ) so that it calls Line ::intersection point ( ) and returns a bool real point, too.

[LDF 2002.10.26.] !! KLUDGE: \newline inserted in the text above to avoid overfull boxes. ⟨ Type definitions 15 ⟩ +≡

struct bool real point { bool b; real r; Point pt ; bool real point( ); /∗ Default constructor. ∗/ bool real point(const bool real point &brp) : b(brp.b), r(brp.r), pt (brp.pt ) { } /∗ Copy constructor. ∗/ bool real point(const bool &bb, const real &rr , const Point &ppt ) : b(bb), r(rr ), pt (ppt ) { } /∗ Construcor with bool, real, and Point arguments. ∗/ void operator=(const bool real point &brp) /∗ Assignment operator. ∗/ {

b = brp.b;

r = brp.r;

pt = brp.pt ; }

};

§318  3DLDF-1.1.5.1  DEFAULT CONSTRUCTOR FOR BOOL REAL POINT 85

318. Default Constructor for bool real point.

Log

LDF 2003.06.1. Added this section. Redefined the default constructor bool real point(void), so that b is set to false, r is set to , and pt is set to . In order to do this, it was necessary to remove the definition from the declaration of bool real point, because when the compiler sees

it,  and  aren’t defined yet.

⟨ Define bool real point functions 318 ⟩ ≡ bool real point ::bool real point( )

: b(false), r(  ), pt (  ) { }

This code is used in section 633.

319. Global constants. [LDF 2002.09.25.] Changed this section. I now know that consts have internal linkage by default and that I must declare them with extern in order to give them external linkage. ⟨ Global constants 22 ⟩ +≡

extern const Point ( , , ); extern const Point origin(0, 0, 0);

extern const bool point  (false,  );
extern const bool point pair  (  ,

);

extern const bool real point  (false,  ,  );
extern const bool point quadruple  (  ,
,  ,  );

320. ⟨ Declarations for the header file 21 ⟩ +≡

extern const Point ; extern const Point origin; extern const bool point ; extern const bool point pair ; extern const bool real point ; extern const bool point quadruple ;

321. Constructors and setting functions.

86  CONSTRUCTORS AND SETTING FUNCTIONS  3DLDF-1.1.5.1 §322

322. The valarrays I use for the various sets of coordinates can be declared in the class declaration, but neither can their size be set nor can they be initialized. null coordinates is defined in pspglb.web and is a valarray of reals with 4 elements = 0. Setting world coordinates , etc. to null coordinates makes them the right size.

323. Initialize coordinates and limits.

Log

[LDF 2002.4.3.] Now setting world coordinates [3], user coordinates [3], and view coordinates [3] = 1. It fixes a bug that showed up when I tried to shift a Point with coordinates ≡ 0.

⟨ Initialize coordinates and limits 323 ⟩ ≡ #ifdef

world coordinates = null coordinates ; user coordinates = null coordinates ; view coordinates = null coordinates ; projective coordinates = null coordinates ;

#endif #ifdef

world coordinates .resize(4, 0); user coordinates .resize(4, 0); view coordinates .resize(4, 0); projective coordinates .resize(4, 0);

#if 1

pen = ; #endif

transform.reset ( ); #endif

world coordinates [3] = 1; user coordinates [3] = 1; view coordinates [3] = 1; projective extremes .resize(6, 0);

This code is used in sections 325, 328, and 332.

324. Default version. No arguments. ⟨ Declare Point constructors 324 ⟩ ≡

Point( );

See also sections 327 and 331. This code is used in section 309.

§325  3DLDF-1.1.5.1  DEFAULT VERSION 87

325. ⟨ Define Point constructors 325 ⟩ ≡

Point ::Point( )

{ ⟨ Initialize coordinates and limits 323 ⟩ on free store = false; do output = true;

}

See also sections 328 and 332. This code is used in section 633.

326. Three real values.

327. Constructor.

Log

[LDF 2002.12.01.] Made arguments const.

⟨ Declare Point constructors 324 ⟩ +≡

Point(const real x, const real y =  , const real z =  );

328. ⟨ Define Point constructors 325 ⟩ +≡

Point ::Point(const real x, const real y, const real z)

{ ⟨ Initialize coordinates and limits 323 ⟩ on free store = false; do output = true;

#if 0 /∗ [LDF 2002.10.23.] user transform is not currently in use. It is intended for use in implementing

user-defined coordinate systems. ∗/ if (user transform.is identity ( ))

#endif

world coordinates [0] = x; world coordinates [1] = y; world coordinates [2] = z; world coordinates [3] = 1;

}

329. Setting function.

Log

[LDF 2002.12.01.] Made arguments const.

[LDF 2003.03.25.] Changed this function, so that it returns ∗this instead of void. This makes it possible to chain invocations of this function.

⟨ Declare Point functions 329 ⟩ ≡

const Point &set (const real x, const real y =  , const real z =  );

See also sections 333, 338, 340, 342, 344, 346, 349, 350, 352, 355, 357, 360, 362, 365, 367, 370, 372, 375, 377, 380, 382, 384, 385, 387, 389, 393, 396, 398, 400, 401, 404, 406, 408, 412, 414, 419, 421, 436, 438, 442, 446, 448, 450, 454, 456, 458, 460, 463, 464, 466, 467, 469, 470, 472, 473, 475, 477, 482, 484, 486, 488, 489, 491, 493, 495, 501, 505, 507, 510, 512, 518, 521, 523, 525, 527, 529, 532, 536, 538, 540, 542, 544, 546, 548, 551, 553, 555, 557, 560, 567, 569, 572, and 573.

This code is used in section 309.

88  SETTING FUNCTION  3DLDF-1.1.5.1 §330

330. ⟨ Define Point functions 330 ⟩ ≡

const Point &Point ::set (const real x, const real y, const real z)

{ Point p(x, y, z); ∗this = p; do output = true; return ∗this ; /∗ LDF 2003.03.25. Added this. Formerly, the return value was void. ∗/

}

See also sections 334, 339, 341, 343, 345, 347, 351, 356, 358, 361, 363, 366, 368, 371, 373, 376, 378, 381, 383, 386, 388, 390, 391, 394, 395, 397, 399, 405, 407, 409, 413, 415, 420, 422, 437, 443, 444, 445, 447, 449, 451, 455, 457, 459, 461, 476, 478, 483, 485, 487, 490, 492, 494, 496, 502, 506, 508, 511, 513, 519, 522, 524, 526, 528, 530, 533, 537, 539, 541, 543, 545, 547, 549, 552, 554, 556, 561, 562, 563, 564, 565, 566, 568, 570, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 645, 647, 681, 760, 823, 824, 832, 833, 841, 842, 860, 861, 945, 948, 949, and 950.

This code is used in sections 633, 657, 694, and 980.

331. Copy constructor. ⟨ Declare Point constructors 324 ⟩ +≡

Point(const Point &p);

332. ⟨ Define Point constructors 325 ⟩ +≡

Point ::Point(const Point &p)

{ ⟨ Initialize coordinates and limits 323 ⟩ ∗this = p; on free store = false; do output = true;

}

333. Setting function. [LDF 2002.10.23.] This function is unnecessary, because it does nothing that the assignment operator can’t do. However, I’ve tried to use set ( ) a couple of times with a Point argument, so it’s convenient to have it. If nothing else, it prevents compilation from failing occasionally.

Log

[LDF 2002.10.23.] Added this function.

⟨ Declare Point functions 329 ⟩ +≡ void set (const Point &p); 334. ⟨ Define Point functions 330 ⟩ +≡

void Point ::set (const Point &p)

{ ∗this = p; do output = true;

}

335. Pseudo-constructor for dynamic allocation. create new < Point > ( ) is meant to be used instead of new ( ) for dynamic allocation of Points. It calls the default constructor (without arguments) and then sets on free store to true.

[LDF 2002.10.11.] It is used in various Point functions, and in Path and some classes derived from Path, currently Ellipse, Reg Polygon, and Rectangle. It is intended that objects of these types be declared, i.e., unlike Reg Cl Plane Curve, they are not meant to be used only as base classes. Reg Cl Plane Curve does not use create new < Point > ( ) and it is unlikely that other classes of this kind will use it.

Log

[LDF 2003.12.30.] Replaced the non-template create new point ( ) functions with versions of the create new ( ) template function. I believe the definitions shouldn’t be necessary, but at present they are. Without them, the templates aren’t instantiated.

[LDF 2003.12.30.] Changed the argument. It’s now a const Point ∗.

[LDF 2003.12.30.] Removed default argument “0”, because this caused a compiler error when using the DEC C^{++} compiler. Apparently, it suffices to declare a default argument in the template declaration.

336. Pointer argument. ⟨ Declare non-member template functions for Point 336 ⟩ ≡

Point ∗create new (const Point ∗p);

See also section 337. This code is used in sections 633 and 634.

337. Referece argument.

Log

[LDF 2003.12.30.] Changed argument from Point to const Point &.

⟨ Declare non-member template functions for Point 336 ⟩ +≡ Point ∗create new (const Point &p);

338. Destructor.

Log

[LDF 2003.08.27.] Added a virtual destructor with an empty definition, because GCC with the “-Wall” option issued the following warning: “‘class Point’ has virtual functions but non-virtual destructor”.

⟨ Declare Point functions 329 ⟩ +≡ virtual ∼Point( );

90  DESTRUCTOR  3DLDF-1.1.5.1 §339

339. ⟨ Define Point functions 330 ⟩ +≡

Point ::∼Point( )

{ }

340. Assignment.

Log

[LDF 2003.03.25.] Changed this function, so that it returns p instead of void. This makes it possible to chain invocations of this function.

⟨ Declare Point functions 329 ⟩ +≡ const Point &operator=(const Point &p);

341. ⟨ Define Point functions 330 ⟩ +≡

const Point &Point ::operator=(const Point &p)

{ transform = p.transform; drawdot value = p.drawdot value; drawdot color = p.drawdot color ;

#if 1

pen = p.pen;

#endif world coordinates = p.world coordinates ; user coordinates = p.user coordinates ; view coordinates = p.view coordinates ; projective coordinates = p.projective coordinates ; projective extremes = p.projective extremes ; /∗ LDF 2002.09.18. Added this line. I think that it

shouldn’t be necessary to do this, but I’ve added it just to be sure. ∗/ do output = true; /∗ [LDF 2002.09.18.] Probably not necessary, but I might as well. ∗/ return p; /∗ LDF 2003.03.25. Added this. Formerly, the return value was void. ∗/

}

342. Set on free store.

Log

[LDF 2003.12.29.] Made non-inline.

⟨ Declare Point functions 329 ⟩ +≡ virtual bool set on free store(bool b = true);

§343  3DLDF-1.1.5.1  SET ON FREE STORE 91

343. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::set on free store(bool b)

{ on free store = b; return b;

}

344. Clear. I need this function because it’s a virtual function in Shape.

Log

[LDF 2002.10.27.] Redefined this function. Formerly, it was inline and empty. Now it sets all of the x, y, and z coordinates to 0, and resets transform. It doesn’t seem worthwhile to set drawdot value, drawdot color , or pen to any particular values.

⟨ Declare Point functions 329 ⟩ +≡ void clear ( );

345. ⟨ Define Point functions 330 ⟩ +≡

void Point ::clear ( )

{

for (int i = 0; i < 4; i^{++}) {

world coordinates [i] = user coordinates [i] = view coordinates [i] = projective coordinates [i] = 0; } transform.reset ( ); return;

}

346. Clean. ⟨ Declare Point functions 329 ⟩ +≡

void clean(int factor = 1); 347. ⟨ Define Point functions 330 ⟩ +≡

void Point ::clean(int factor )

{ apply transform( ); real eps = epsilon( ) ∗ factor ; for (int i = 0; i < 4; i^{++})

if (fabs (world coordinates [i]) < eps ) world coordinates [i] = 0.0; }

348. Returning elements and information.

349. Is identity. ⟨ Declare Point functions 329 ⟩ +≡

inline bool is identity ( )

{

return (transform.is identity ( )); }

350. Epsilon.

Log

[LDF 2004.1.2.] Now returning different values, depending on whether real is float or double. TO DO: Try to find out what values would be best. It will be necessary to check how good the value for double is.

[LDF 2004.1.2.] Made epsilon( ) non-inline.

⟨ Declare Point functions 329 ⟩ +≡ static real epsilon( );

351. ⟨ Define Point functions 330 ⟩ +≡

real Point ::epsilon( )

{ #if

return .000000001;

#else

return .00001;

#endif }

352. Get Line. Defined in lines.web. Must be defined there, because Line is an incomplete type here. [LDF 2002.04.12.] Removed this function to lines.web.

⟨ Declare Point functions 329 ⟩ +≡ Line get line(const Point &pt ) const;

353. Getting coordinates. ?? Change get x ( ), etc., back to inline??

354. Get all coordinates. [LDF 2002.09.19.] Added this function. ?? [LDF 2002.12.01.] Can I make the Focus ∗ argument const? What is the syntax for a pointer to a const, as opposed to a const pointer? Look up!! Make sure I change this is 3DLDF.texi if I change it here!

355. Non-const version. [LDF 2002.09.19.] Added this function. ⟨ Declare Point functions 329 ⟩ +≡

valarray⟨real⟩ get all coords (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1);

356. ⟨ Define Point functions 330 ⟩ +≡

valarray⟨real⟩ Point ::get all coords (char coords , const bool do persp, const bool do apply , Focus

∗f, const unsigned short proj , real factor )

{ if (do apply ) apply transform( ); coords = tolower (coords ); if (coords ≡ ) return world coordinates ; else if (coords ≡ ) return view coordinates ; else if (coords ≡ ) return user coordinates ; else if (coords ≡ ) {

if (do persp) { if (f ≡ 0) f = &default focus ; project (∗f, proj , factor );

}

return projective coordinates ; } else {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ␣ ≪ coords ≪

␣ ␣ ␣ ≪ flush;

return world coordinates ; }

}

357. const version. [LDF 2002.09.19.] Added this function. ⟨ Declare Point functions 329 ⟩ +≡

valarray⟨real⟩ get all coords (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const;

358. ⟨ Define Point functions 330 ⟩ +≡

valarray⟨real⟩ Point ::get all coords (char coords , const bool do persp, const bool do apply , Focus

∗f, const unsigned short proj , real factor ) const

{ Point p(∗this ); valarray⟨real⟩ v = p.get all coords (coords , do persp, do apply , f); return v;

}

359. Get coord. [LDF 2002.09.14.] Added get coord ( ). Fixing a bug that caused get x ( ), etc., to call project ( ) multiple times when doing Path ::output ( ).

94  NON-CONST VERSION  3DLDF-1.1.5.1 §360

360. Non-const version. [LDF 2002.10.27.] The argument c refers to either the x, y, z, or w coordinate. ⟨ Declare Point functions 329 ⟩ +≡

real get coord (char c, char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1);

361. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get coord (char c, char coords , const bool do persp, const bool do apply , Focus ∗f, const

unsigned short proj , real factor )

{ if (do apply ) apply transform( ); if (f ≡ 0) f = &default focus ; unsigned short ctr ; c = tolower (c); if (c ≡ ) ctr = 0; else if (c ≡ ) ctr = 1; else if (c ≡ ) ctr = 2; else if (c ≡ ) ctr = 3; else {

cerr ≪ ␣ ␣ ␣ ≪ ␣ ␣ ␣ ≪ c ≪ ≪

␣ ≪ flush; ctr = 0;

} coords = tolower (coords ); if (coords ≡ ) return world coordinates [ctr ]; else if (coords ≡ ) return user coordinates [ctr ]; else if (coords ≡ ) {

if (do persp) project (∗f, proj , factor );

return projective coordinates [ctr ]; } else if (coords ≡ ) return view coordinates [ctr ]; else {

cerr ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ coords ≪

endl ≪ ␣ ≪ flush; return ;

} }

362. const version. ⟨ Declare Point functions 329 ⟩ +≡

§363  3DLDF-1.1.5.1  CONST VERSION 95

real get coord (char c, char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const; 363. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get coord (char c, char coords , const bool do persp, const bool do apply , Focus ∗f, const

unsigned short proj , real factor ) const

{ Point p(∗this ); return p.get coord (c, coords , do persp, do apply , f, proj , factor );

}

364. Get x.

365. Non-const version. ⟨ Declare Point functions 329 ⟩ +≡

real get x (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1);

366. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get x (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor )

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

367. const version. ⟨ Declare Point functions 329 ⟩ +≡

real get x (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const;

368. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get x (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor ) const

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

369. Get y.

370. Non-const version. ⟨ Declare Point functions 329 ⟩ +≡

real get y (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1); 371. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get y (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor )

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

372. const version. ⟨ Declare Point functions 329 ⟩ +≡

real get y (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const;

373. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get y (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor ) const

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

374. Get z.

375. Non-const version. ⟨ Declare Point functions 329 ⟩ +≡

real get z (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1);

376. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get z (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor )

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

377. const version. ⟨ Declare Point functions 329 ⟩ +≡

real get z (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const;

378. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get z (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor ) const

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

379. Get w.

380. Non-const version. ⟨ Declare Point functions 329 ⟩ +≡

real get w (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1);

381. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get w (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor )

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

382. const version. ⟨ Declare Point functions 329 ⟩ +≡

real get w (char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , real factor = 1) const;

383. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get w (char coords , const bool do persp, const bool do apply , Focus ∗f, const unsigned

short proj , real factor ) const

{

return get coord ( , coords , do persp, do apply , f, proj , factor ); }

384. Get transform.

Log

[LDF 2002.10.27.] Made this function const.

⟨ Declare Point functions 329 ⟩ +≡ inline Transform get transform( ) const {

return transform; }

385. Get copy.

Log

[LDF 2002.10.27.] Made this function const.

⟨ Declare Point functions 329 ⟩ +≡ Shape ∗get copy ( ) const;

98  GET COPY  3DLDF-1.1.5.1 §386

386. ⟨ Define Point functions 330 ⟩ +≡

Shape ∗Point ::get copy ( ) const{ Point ∗p = create new < Point > (0); ∗p = ∗this ; return static cast⟨Shape ∗⟩(p); }

387. Is on free store.

Log

[LDF 2004.01.06.] Made non-inline.

⟨ Declare Point functions 329 ⟩ +≡ bool is on free store( ) const;

388. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::is on free store( ) const

{

return on free store; }

389. Slope. [LDF 2002.10.27.] slope( ) returns the slope of the trace of the line from ∗this to p on the plane indicated by the char arguments m and n. These should be , , , , , or .

Log

[LDF 2002.10.27.] Now using world coordinates directly instead of “get” functions.

[LDF 2002.10.27.] Changed argument p from const Point & to Point.

⟨ Declare Point functions 329 ⟩ +≡ real slope(Point p, char m = , char n = ) const;

§390  3DLDF-1.1.5.1  SLOPE 99

390. ⟨ Define Point functions 330 ⟩ +≡

real Point ::slope(Point p, char m, char n) const{ bool = false; /∗ true ∗/ Point a(∗this ); a.apply transform( ); p.apply transform( ); if (a ≡ p) {

  cerr ≪  ␣  ␣  ≪  ␣   ␣   ␣      ␣         ␣

≪ flush; if ( ) {

a.show ( ); p.show ( );

}

return ; } m = tolower (m); n = tolower (n);

if (¬((m ≡  ∨ m ≡  ∨ m ≡ ) ∧ (n ≡  ∨ n ≡  ∨ n ≡ ) ∧ (m ≠ n))) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣    ␣    ␣         ␣   ␣       ␣

␣    ␣   ␣   ␣      ␣ ≪ m ≪ ␣ ≪ n ≪ endl ≪  ␣  ≪

flush; return ;

} int ctr = m − ; real a m coord = a.world coordinates [ctr ]; real p m coord = p.world coordinates [ctr ]; ctr = n − ; real a n coord = a.world coordinates [ctr ]; real p n coord = p.world coordinates [ctr ];

391. We often use slope( ) in order to find out whether a line has slope or not, so an error message is out of place here. A warning is too, probably, but I’m leaving this in here for now, just in case I change my mind. ⟨ Define Point functions 330 ⟩ +≡

if (a m coord ≡ p m coord ) { #if 0

cerr ≪  ␣  ␣  ≪ m ≪

  ␣          ␣  ␣       ␣   ␣     ␣   ␣  ≪  ␣  ;

#endif

return ; } return (a n coord − p n coord )/(a m coord − p m coord ); }

392. Is on segment.

393. Non-const version. [LDF 2002.10.29.] is on segment ( ) returns a bool real with the bool indicating whether ∗this lies on the line segment between p0 and p1 , and a real value t representing the distance of ∗this on the way from p0 to p1 . If the bool is true, then 0 <= t <= 1. If t < 0 or t > 1, then ∗this lies on the line passing through p0 and p1 , but not on the segment. If ∗this doesn’t lie on the line, t will be .

[LDF 2002.10.29.] To check whether ∗this lies on the line, use is on line( ).

Log

[LDF 2002.10.29.] BUG FIX: Added code to check whether the unit vectors ∗this − p0 and p1 − ∗this are equal before calculating r. Before I did this, true was returned for Points that weren’t on the line segment.

[LDF 2002.10.29.] Now using world coordinates directly instead of get x ( ), get y ( ), and get z ( ).

⟨ Declare Point functions 329 ⟩ +≡ bool real is on segment (Point p0 , Point p1 ); 394. ⟨ Define Point functions 330 ⟩ +≡

bool real Point ::is on segment (Point p0 , Point p1 ){ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

apply transform( ); p0 .apply transform( ); p1 .apply transform( ); if ( ) {

show ( );

p0 .show ( );

p1 .show ( ); }

if (∗this ≡  ∨ p0 ≡  ∨ p1 ≡  ) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣   ␣      ␣   ␣        ␣ ≪

␣ ␣ ␣ ≪ flush; return pair⟨bool, real⟩(false, );

} bool b; real r; if (p0 ≡ p1 ∧ ∗this ≡ p0 ) {

cerr ≪  ␣  ␣  ≪

      ␣   ␣   ␣         ␣  ␣   ␣  ␣   ␣    ␣      ␣ ≪
      ␣     ␣    ␣  ;

return pair⟨bool, real⟩(false, ); } else if (p0 ≡ p1 ) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣   ␣   ␣   ␣      ␣ ≪
      ␣     ␣    ␣  ;

return pair⟨bool, real⟩(false, ); } else if (∗this ≡ p0 ) {

return pair⟨bool, real⟩(true, 0.0); } else if (∗this ≡ p1 ) {

return pair⟨bool, real⟩(true, 1.0); }

/∗ [LDF 2002.10.29.] Beginning of new code. ∗/ Point v0 (∗this − p0 ); Point v1 (p1 − ∗this ); v0 .apply transform( ); v1 .apply transform( ); if ( ) {

v0 .show ( );

v1 .show ( ); } v0 .unit vector (true); v1 .unit vector (true); if ( ) {

v0 .show ( );

v1 .show ( ); } Point v2 (−v1 ); if ( ) {

v2 .show ( ); } if (v0 ≠ v1 ∧ v0 ≠ v2 ) {

if ( ) cout ≪ ␣ ␣ ;

return pair⟨bool, real⟩(false, ); }

/∗ [LDF 2002.10.29.] End of new code. ∗/

395. [LDF 2002.10.29.] Calculate how far ∗this is on the way from p0 to p1 .

LDF Undated. The value t can be calculated from either the x, y, or z-coordinates. We try them in order and return the first one that works. Because of the limited precision with which we are working, it’s possible that the value of t can differ, depending on what coordinates are used to calculate it. In general, this will not be significant, since we’ll mainly be needing this function to determine whether a Point is on a line segment; the exact value of t will usually not be significant. ⟨ Define Point functions 330 ⟩ +≡

if (p1 .world coordinates [0] ≠ p0 .world coordinates [0])

r = (world coordinates [0]−p0 .world coordinates [0])/(p1 .world coordinates [0]−p0 .world coordinates [0]); else if (p1 .world coordinates [1] ≠ p0 .world coordinates [1])

r = (world coordinates [1]−p0 .world coordinates [1])/(p1 .world coordinates [1]−p0 .world coordinates [1]); else if (p1 .world coordinates [2] ≠ p0 .world coordinates [2])

r = (world coordinates [2]−p0 .world coordinates [2])/(p1 .world coordinates [2]−p0 .world coordinates [2]); else {

cerr ≪  ␣  ␣  ≪

      ␣         ␣  ␣         ␣     ␣   ␣  ≪ flush;

return pair⟨bool, real⟩(false, ); } if (r ≥ 0 ∧ r ≤ 1) b = true; else b = false; return pair⟨bool, real⟩(b, r); }

396. const version.

Log

[LDF 2002.10.29.] Added this function.

⟨ Declare Point functions 329 ⟩ +≡ bool real is on segment (const Point &p0 , const Point &p1 ) const; 397. ⟨ Define Point functions 330 ⟩ +≡

bool real Point ::is on segment (const Point &p0 , const Point &p1 ) const

{ Point a(∗this ); return a.is on segment (p0 , p1 );

}

398. Is on line. [LDF 2002.10.29.] TO DO: Maybe add a non-const version. This isn’t urgent, though.

Log

[LDF 2002.10.29.] Added this function.

⟨ Declare Point functions 329 ⟩ +≡ bool real is on line(const Point &p0 , const Point &p1 ) const;

399. ⟨ Define Point functions 330 ⟩ +≡

bool real Point ::is on line(const Point &p0 , const Point &p1 ) const

{ bool real br = is on segment (p0 , p1 ); if (br .second ≠ ) br .first = true; return br ;

}

400. Is on Plane. [LDF 2003.06.04.] This function returns true, if ∗this lies on the Plane p, otherwise false. It must be defined in planes.web, because Plane is an incomplete type here.

Log

[LDF 2003.06.04.] Added this function.

⟨ Declare Point functions 329 ⟩ +≡ bool is on plane(const Plane &p) const;

401. Is in triangle. [LDF 2003.06.11.] This function returns true, if ∗this lies within the triangle defined by the three Point arguments, otherwise false. Defined in paths.web, because it uses class Path, which is an incompletely defined type here.

Log

[LDF 2003.06.11.] Added this function.

[LDF 2003.06.24.] Removed the argument test points .

⟨ Declare Point functions 329 ⟩ +≡

bool is in triangle(const Point &p0 , const Point &p1 , const Point &p2 , bool verbose = false) const;

402. Transformations.

403. Affine transformations.

404. Rotation around the main axes.

Log

[LDF 2003.01.22.] Replaced body of function. Transform ::rotate( ) returns a Transform representing the rotation only, so I don’t need to use a locally declared Transform t in this function.

⟨ Declare Point functions 329 ⟩ +≡ Transform rotate(const real x, const real y = 0, const real z = 0);

405. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::rotate(const real x, const real y, const real z)

{

return transform.rotate(x, y, z); }

406. Scale.

Log

[LDF 2003.01.22.] Replaced body of function. Transform ::scale( ) returns a Transform representing the rotation only, so I don’t need to use a locally declared Transform t in this function.

⟨ Declare Point functions 329 ⟩ +≡ Transform scale(real x, real y = 1, real z = 1);

407. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::scale(real x, real y, real z)

{

return transform.scale(x, y, z); }

408. Shear.

Log

[LDF 2003.01.22.] Replaced body of function. Transform ::shear ( ) returns a Transform representing the rotation only, so I don’t need to use a locally declared Transform t in this function.

⟨ Declare Point functions 329 ⟩ +≡ Transform shear (real xy , real xz = 0, real yx = 0, real yz = 0, real zx = 0, real zy = 0);

409. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::shear (real xy , real xz , real yx , real yz , real zx , real zy )

{

return transform.shear (xy , xz , yx , yz , zx , zy ); }

410. Shift.

411. Point versions.

§412  3DLDF-1.1.5.1  THREE REAL ARGUMENTS 105

412. Three real arguments. ⟨ Declare Point functions 329 ⟩ +≡

Transform shift (real x, real y = 0, real z = 0);

413. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::shift (real x, real y, real z)

{ Transform t; if (x ≠ 0 ∨ y ≠ 0 ∨ z ≠ 0) transform ∗= t.shift (x, y, z); return t;

}

414. Point argument. ⟨ Declare Point functions 329 ⟩ +≡

Transform shift (const Point &p);

415. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::shift (const Point &p)

{

return shift (p.get x ( ), p.get y ( ), p.get z ( )); }

416. Transform version. Point argument. [LDF 2002.04.24.] Added this function. It’s declared in transfor.web, but must be defined here, because Point is an incomplete type there. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::shift (const Point &p)

{

return shift (p.get x ( ), p.get y ( ), p.get z ( )); }

417. Picture version. Point argument. [LDF 2002.08.08.] Added this function. It’s declared in pictures.web, but must be defined here, because Point is an incomplete type there. ⟨ Define Picture functions 264 ⟩ +≡

Transform Picture ::shift (const Point &p)

{

return shift (p.get x ( ), p.get y ( ), p.get z ( )); }

418. Shift times.

[LDF 2003.01.19.] Note that shift times ( ) will only have an effect if it’s called after a call to shift ( ) and before an operation is applied that causes apply transform( ) to be called.

106  THREE REAL ARGUMENTS  3DLDF-1.1.5.1 §419

419. Three real arguments.

Log

[LDF 2003.01.19.] Added this function.

[LDF 2003.01.22.] Got rid of local Transform t. It wasn’t needed. Now just returning the return value of transform.shift times ( ).

⟨ Declare Point functions 329 ⟩ +≡ Transform shift times (real x, real y = 1, real z = 1);

420. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::shift times (real x, real y, real z)

{

return transform.shift times (x, y, z); }

421. Point argument.

Log

[LDF 2003.01.19.] Added this function.

⟨ Declare Point functions 329 ⟩ +≡ Transform shift times (const Point &p);

422. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::shift times (const Point &p)

{

return transform.shift times (p.get x ( ), p.get y ( ), p.get z ( )); }

423. Alignment with an axis. Declared in transfor.web. Defined here, because it needs Points. [LDF 2002.10.23.] align with axis ( ) returns the Transform needed to align \overrightarrow{p_{0}p_{1}} with one of the main axes.

[LDF 2003.05.04.] BUG: TO DO: Try to find out why I sometimes get erroneous results with rotate(Point, Point, real) (formerly rotate around ( )). I think the problem may be here.

Log

[LDF 2002.12.10.] Made this function a friend in class Point. Now calling p0 .apply transform( ) and p1 .apply transform( ) at the beginning of this function and using p0 .world coordinates and p1 .world coordinates directly instead of get x ( ), get y ( ), and get z ( ).

§424  3DLDF-1.1.5.1  ALIGNMENT WITH AN AXIS 107

424. ⟨ Define Transform functions 169 ⟩ +≡

Transform Transform ::align with axis (Point p0 , Point p1 , char axis )

/∗ Default is the z-axis. ∗/

{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ endl ≪ flush;

p0 .apply transform( ); /∗ LDF 2002.12.10. Added these two lines. ∗/ p1 .apply transform( ); Transform t; axis = tolower (axis ); /∗ Upper- or lowercase is permitted for axis . ∗/

if (axis ≠  ∧ axis ≠  ∧ axis ≠ ) {

  cerr ≪  ␣  ␣                             ␣       ␣        ␣         ␣ ≪

axis ≪ endl ≪  ␣        ␣  ≪ endl ≪ flush;

return t; } real angle;

425. [LDF 2002.10.23.] Shift p0 to origin, and shift p1 the same way, so that the relationship between them remains constant. ⟨ Define Transform functions 169 ⟩ +≡

if (p0 ≠ origin) {

if ( ) { p0 .show ( ); p1 .show ( );

} t.shift (−p0 ); p1 ∗= t; p1 .apply transform( ); p0 .apply transform( );

} ⟨ Normalize point 433 ⟩ /∗ [LDF 2002.10.23.] Transform the Point so that it’s x, y, and z coordinates

are all positive. See below for the explanation. ∗/ if ( ) {

t.show ( ␣ ␣ ␣␣ ); } Point proj on x z plane(p1 ); /∗ [LDF 2002.10.23.] Get the projection of p1 on the x-z plane. ∗/

proj on x z plane.shift (0, −p1 .world coordinates [1]);

if (  ) proj on x z plane.show (  );

108  ALIGNMENT WITH AN AXIS  3DLDF-1.1.5.1 §426

426. [LDF 2002.10.23.] If we’re aligning with the x or y-axis, rotate p1 onto the x-y plane and then to the x-axis. ⟨ Define Transform functions 169 ⟩ +≡

if (axis ≡ ∨ axis ≡ ) { Point pt on x axis ; pt on x axis .set (1); angle = proj on x z plane.angle(pt on x axis ); if ( ) cout ≪ ␣ ␣ ␣ ≪ angle ≪ endl ≪ flush; if (angle ≠ 0 ∧ angle ≠ ) t ∗= p1 .rotate(0, −angle); if ( ) p1 .show ( ␣ ␣ ␣ ␣ ␣ ); angle = p1 .angle(pt on x axis ); if ( ) cout ≪ ␣ ␣ ␣ ≪ angle ≪ endl ≪ flush; if (angle ≠ 0 ∧ angle ≠ ) t ∗= p1 .rotate(0, 0, −angle); if ( ) p1 .show ( ␣ ␣ ␣ ␣ );

}

427. [LDF 2002.10.23.] If we’re aligning with the z-axis, rotate p1 onto the y-z plane and then to the z-axis. ⟨ Define Transform functions 169 ⟩ +≡

else if (axis ≡ ) { Point pt on z axis ; pt on z axis .set (0, 0, 1); /∗ [LDF 2002.10.23.] This assumes that proj on x z plane.get z ( ) ≥ 0. It

should be, but if it isn’t, the following error handling code takes care of the problem. ∗/ if (proj on x z plane.get z ( ) < 0) {

cerr ≪  ␣  ␣  ≪

      ␣ ␣  ≪  ␣        ␣      ␣      ␣    ␣ ≪
      ␣     ␣  ␣  ␣  ≪  ␣   ␣       ␣   ␣    ␣   ␣   ␣   ␣  ≪

endl ≪ endl ≪ flush; pt on z axis .set (0, 0, −1);

}

428.

Log

[LDF 2002.12.10.] Added the following conditional. Trying to fix a bug that occurred while porting to GNU/Linux.

⟨ Define Transform functions 169 ⟩ +≡ if (proj on x z plane.world coordinates [0] ≡ 0 ∧ proj on x z plane.world coordinates [1] ≡ 0) angle = 0; else angle = proj on x z plane.angle(pt on z axis );

429. ⟨ Define Transform functions 169 ⟩ +≡

if ( ) cout ≪ ␣ ␣ ␣ ≪ angle ≪ endl ≪ flush; if (angle ≠ 0 ∧ angle ≠ ) t ∗= p1 .rotate(0, angle); if ( ) p1 .show ( ␣ ␣ ␣ ␣ ␣ ); p1 .apply transform( ); 430.

Log

[LDF 2002.12.10.] Added the following conditional. Trying to fix a bug that occurred while porting to GNU/Linux.

[LDF 2003.06.13.] BUG FIX: Changed proj on x z plane to p1 in the “if ” part of the following conditional. The y-coordinate of proj on x z plane is always 0, so angle was always set to 0. I discovered this bug when I tried rotating a Point in the plane of a Reg Polygon about a line from the center of the Reg Polygon in the direction of its normal, and the resulting Point was not in the same plane.

⟨ Define Transform functions 169 ⟩ +≡ if (p1 .world coordinates [1] ≡ 0) angle = 0; else angle = p1 .angle(pt on z axis );

431. ⟨ Define Transform functions 169 ⟩ +≡

if ( ) cout ≪ ␣ ␣ ␣ ≪ angle ≪ endl ≪ flush; if (angle ≠ 0 ∧ angle ≠ ) t ∗= p1 .rotate(−angle); if ( ) p1 .show ( ␣ ␣ ␣ ␣ ); }

432. [LDF 2002.10.23.] If we’re aligning with the y-axis, p1 must be rotated from the x-axis (where it is now) around the z-axis by 90^{∘}. Then it will be on the y-axis. ⟨ Define Transform functions 169 ⟩ +≡

if (axis ≡ ) { t ∗= p1 .rotate(0, 0, 90); if ( ) p1 .show ( ␣ ␣ ␣ ␣ );

} if ( ) {

cout ≪ ␣ ␣ ≪ p1 .magnitude( ) ≪ endl ≪ flush; t.show ( ␣ ␣ ␣ ␣ );

} ∗this ∗= t; if ( ) cout ≪ ␣ ≪ endl ≪ flush; return t; }

110  NORMALIZE POINT  3DLDF-1.1.5.1 §433

433. Normalize point. It makes it easier to determine the correct direction of rotation toward the x-y or y-z plane if p1 ’s coordinates are all >= 0, so we rotate it in order to make them so. The only case that requires more than a rotation around a single axis is the case that x_{p1}, y_{p1}, and z_{p1} are all < 0. It would be nice if I could replace this long conditional with a more elegant construction, but I don’t know one. ⟨ Normalize point 433 ⟩ ≡

{ if ( ) p1 .show ( ␣ ␣ ); if (p1 .world coordinates [0] < 0 ∧ p1 .world coordinates [1] ≥ 0 ∧ p1 .world coordinates [2] ≥ 0)

/∗ x negative, y and z positive. ∗/ t ∗= p1 .rotate(0, −90);

else if (p1 .world coordinates [0] ≥ 0 ∧ p1 .world coordinates [1] < 0 ∧ p1 .world coordinates [2] ≥ 0)

/∗ x positive, y negative, z positive. ∗/ t ∗= p1 .rotate(90);

else if (p1 .world coordinates [0] ≥ 0 ∧ p1 .world coordinates [1] ≥ 0 ∧ p1 .world coordinates [2] < 0)

/∗ x positive, y positive, z negative. ∗/ t ∗= p1 .rotate(−90);

else if (p1 .world coordinates [0] < 0 ∧ p1 .world coordinates [1] < 0 ∧ p1 .world coordinates [2] ≥ 0)

/∗ x negative, y negative, z positive. ∗/ t ∗= p1 .rotate(0, 0, 180);

else if (p1 .world coordinates [0] < 0 ∧ p1 .world coordinates [1] ≥ 0 ∧ p1 .world coordinates [2] < 0)

/∗ x negative, y positive, z negative. ∗/ t ∗= p1 .rotate(0, 180);

else if (p1 .world coordinates [0] ≥ 0 ∧ p1 .world coordinates [1] < 0 ∧ p1 .world coordinates [2] < 0)

/∗ x positive, y negative, z negative. ∗/ t ∗= p1 .rotate(180);

else if (p1 .world coordinates [0] < 0 ∧ p1 .world coordinates [1] < 0 ∧ p1 .world coordinates [2] < 0)

/∗ All negative. ∗/ {

real a = p1 .world coordinates [0]; t ∗= p1 .rotate(180, 180); t ∗= p1 .shift (a); t ∗= p1 .rotate(0, 180); t ∗= p1 .shift (−a);

} p1 .apply transform( ); if ( ) {

p0 .show ( ␣ ␣ ); p1 .show ( ␣ ␣ ); t.show ( ␣ ␣ );

} }

This code is used in section 425.

434. Rotation around an arbitrary axis.

435. Point versions. [LDF 2002.4.7.] Added default value for angle ≡ 180.

§436  3DLDF-1.1.5.1  POINT ARGUMENTS 111

436. Point arguments. This function first checks to see if ∗this lies on the axis. It does this by creating unit vectors in the directions of p1 −p0 and ∗this −p0 . If they are equal, or the latter is the former multiplied by -1, then we don’t bother to perform the rotation. Otherwise, we call Transform ::rotate( ) (defined below).

Log

[LDF 2002.4.7.] Added default value for angle ≡ 180.

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Declare Point functions 329 ⟩ +≡ Transform rotate(const Point &p0 , const Point &p1 , const real angle = 180);

437. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::rotate(const Point &p0 , const Point &p1 , const real angle)

{ Point a = p1 − p0 ; Point b = ∗this − p0 ; a.unit vector (true); b.unit vector (true); Transform t; if (a ≡ b ∨ a ≡ −b) {

      cerr ≪  ␣  ␣  ≪  ␣  ␣  ␣       ␣    ␣  ␣  ≪

␣ ␣ ≪ flush;

return t; } return transform.rotate(p0 , p1 , angle);

}

438. Path argument. Defined in paths.web, because Path is still an incomplete type in this compilation unit.

Log

[LDF 2002.04.07.] Added default value for angle ≡ 180.

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Declare Point functions 329 ⟩ +≡ Transform rotate(const Path &p, const real angle = 180);

112 TRANSFORM VERSION 3DLDF-1.1.5.1 §439

439. Transform version. Declared in transfor.web. [LDF 2002.09.29.] TO DO: Possible BUG!! Actually, the problem that occurred may just have to do choosing the direction of rotation. I’ve changed the place where the problem occurred, so I’ll have to write a routine to test this.

Log

[LDF 2002.10.23.] Changed, so that the direction of \overrightarrow{p_{0}p_{1}} is tested. If it is parallel to the x or y-axis, then that axis is used for alignment. Otherwise, the z-axis is used. This may help reduce inaccuracies caused by rotations. Haven’t tested it yet. TO DO: Test this!

[LDF 2002.11.03.] TO DO: See if I can’t make Point arguments const. [LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now

overloads rotate( ) with three real arguments.

⟨ Define Transform functions 169 ⟩ +≡ Transform Transform ::rotate(Point p0 , Point p1 , const real angle) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

p0 .apply transform( ); p1 .apply transform( ); Point a = p1 − p0 ; a.unit vector (true); char axis ; if (a.get x ( ) ≡ 1 ∨ a.get x ( ) ≡ −1) axis = ; else if (a.get y ( ) ≡ 1 ∨ a.get y ( ) ≡ −1) axis = ; else axis = ; Transform t; t.align with axis (p0 , p1 , axis ); Transform i = t.inverse( ); if (axis ≡ ) t.rotate(angle); else if (axis ≡ ) t.rotate(0, angle); else t.rotate(0, 0, angle); t ∗= i; t.clean( ); ∗this ∗= t; clean( ); return t;

}

§440  3DLDF-1.1.5.1  PICTURE VERSION 113

440. Picture version. [LDF 2002.10.20.] angle is in degrees.

Log

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Define Picture functions 264 ⟩ +≡ Transform Picture ::rotate(const Point &p0 , const Point &p1 , const real angle) {

Transform t;

t.rotate(p0 , p1 , angle); transform ∗= t; return t;

}

441. Projection. [LDF 2002.10.23.] For stylistic reasons, and for the sake of clean programming, I believe that the programmer who uses project ( ) should ensure that apply transform( ) has been invoked first. However, transform is checked in project ( ) and apply transform( ) is invoked, if required, so invoking apply transform( ) explicitly beforehand is not strictly speaking necessary.

Log

[LDF 2002.09.09.] The new version now almost works Added division of projective coordinates by the value calculated for w. However, it doesn’t work when I use hex pattern1 ( ). Find out why not!! TO DO: Add routine for calculating z. Then I can add sorting routine in Picture ::output ( ).

[LDF 2002.09.14.] I believe I’ve gotten the new version to work now. LOOK UP: Do I need to divide the derived z value by w? I don’t think it’s necessary. Since the z values of all of the Points would be divided by the same amount, their relative positions would remain the same, since only the relationship “closer or further away” matters, not the exact amounts.

[LDF 2002.09.16.] Added Focus argument to this function. Default is default focus , but it was necessary to write a dummy version of this function in order to make this work, because default focus doesn’t exist at the time that this declaration is compiled.

[LDF 2002.09.18.] Changed name of this function from persp transform( ) to project and added Transform argument.

[LDF 2003.05.09.] BUG FIX: Added loop, setting all elements of projective coordinates to 0. This was done in the conditionally compiled code for the DEC compiler, but I forgot to do it for GCC when added the declaration of temp coordinates and resized it. It took me about 6–7 hours to find this bug!

442. Focus argument.

Log

[LDF 2003.07.11.] Added defaults for proj and factor .

114 FOCUS ARGUMENT 3DLDF-1.1.5.1 §443

⟨ Declare Point functions 329 ⟩ +≡ bool project (const Focus &f, const unsigned short proj = Projections :: , real factor = 1); 443. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::project (const Focus &f, const unsigned short proj , real factor ){ bool = false;

/∗ true ∗/ if ( ) cout ≪ ␣ ≪ flush; if (¬transform.is identity ( )) /∗ LDF 2002.10.23. Added, just to be sure. ∗/

apply transform( );

#ifdef valarray⟨real⟩ temp coordinates ; temp coordinates .resize(4, 0); for (int i = 0; i < 4; ^{++}i) /∗ LDF 2003.05.09. Added this loop. ∗/

projective coordinates [i] = 0;

#else #ifdef

valarray⟨real⟩ temp coordinates = projective coordinates = null coordinates ; #endif #endif

int i; int j; /∗ [LDF 2002.09.18.] Transform temp coordinates by Focus ::transform. ∗/ for (i = 0; i < 4; i^{++}) {

for (j = 0; j < 4; j^{++}) {

temp coordinates [i] += world coordinates [j] ∗ f.get transform element (j, i); }

}

§444  3DLDF-1.1.5.1  PARALLEL PROJECTION 115

444. Parallel projection. [LDF 2002.11.06.] TO DO: Add a way of projecting onto a plane other than the x-y plane. It’s possible to acheive the same effect by rotating the Picture before outputting it, but it would be nice to do so without changing the Picture.

The x and y projective coordinates are simply taken from the world coordinates.

Log

[LDF 2002.10.23.] Added this section.

[LDF 2002.12.18.] Changed  to  and added  and  .

⟨ Define Point functions 330 ⟩ +≡

if (proj ≡ Projections :: ∨ proj ≡ Projections :: ∨ proj ≡

Projections :: ) { using namespace Projections; if (factor ≡ 0) {

  cerr ≪  ␣  ␣  ≪  ␣  ␣  ␣␣           ␣          ␣
      ␣ ␣       ␣    ␣      ␣ ≪  ␣ ␣  ≪ flush;

factor = 1; } unsigned short horizontal ; unsigned short vertical ; if (proj ≡ ∨ proj ≡ ) /∗ [LDF 2002.12.18.] Explain this!! ∗/ horizontal = 0; else horizontal = 2; if (proj ≡ ∨ proj ≡ ) vertical = 1; else vertical = 2; projective coordinates [0] = world coordinates [horizontal ] ∗ factor ; projective coordinates [1] = world coordinates [vertical ] ∗ factor ; projective coordinates [2] = 0; projective coordinates [3] = 1; if ( ) {

cout ≪ ␣ ≪ projective coordinates [0] ≪ ␣ ≪ projective coordinates [1] ≪ ␣ ≪ projective coordinates [2] ≪ ␣ ≪ projective coordinates [3] ≪ ≪ endl ≪ endl ≪ flush;

} return true;

}

116  PERSPECTIVE PROJECTION  3DLDF-1.1.5.1 §445

445. Perspective projection. !! KLUDGE: See below. [LDF 2002.11.08.] TO DO: Get numbers to output using only decimal notation! ⟨ Define Point functions 330 ⟩ +≡

if (temp coordinates [2] + f.get distance( ) ≡ 0) {

cerr ≪  ␣  ␣  ≪  ␣  ␣ ≪ temp coordinates [2] ≪
␣          ␣  ␣ ≪ f.get distance( ) ≪ endl ≪  ␣  ␣  ␣     ␣       ␣  ≪
endl ≪  ␣                      ␣  ␣  ≪ ␣   ␣  ≪

flush; for (i = 0; i < 4; i^{++}) projective coordinates [i] = ; return false;

} else if (temp coordinates [2] + f.get distance( ) < 0) {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ≪ temp coordinates [2] ≪ ␣ ␣ ␣ ≪ f.get distance( ) ≪

endl ≪  ␣   ␣ ␣  ␣      ␣    ␣      ␣  ≪ endl ≪
␣                      ␣  ␣  ≪ ␣   ␣  ≪ flush;

for (i = 0; i < 4; i^{++}) projective coordinates [i] = ; return false;

} real save z = temp coordinates [2]/(temp coordinates [2] + f.get distance( )); if ( ) {

cout ≪ ␣ ␣ ≪ temp coordinates [2] ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ f.get distance( ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ save z ≪ endl ≪ flush;

} for (i = 0; i < 4; i^{++}) {

for (j = 0; j < 4; j^{++}) {

projective coordinates [i] += temp coordinates [j] ∗ f.get persp element (j, i); }

} real eps = epsilon( ); if (projective coordinates [3] ≡ 0) {

cerr ≪  ␣  ␣                 ␣ ≪  ␣  ␣  ≪

    ␣    ␣     ␣ ␣        ␣     ␣  ≪

␣                      ␣  ␣  ≪ ␣   ␣  ≪ flush;

for (i = 0; i < 4; i^{++}) projective coordinates [i] = ; return false;

} for (i = 0; i < 4; i^{++}) {

projective coordinates [i] /= projective coordinates [3]; if (fabs (projective coordinates [i]) < eps ) projective coordinates [i] = 0;

} /∗ [LDF 2002.09.14.] Set the z value of the perspective coordinates in order to be able to use it for

my hidden surface algorith. ∗/ projective coordinates [2] = (fabs (save z ) > eps ) ? save z : 0; if ( ) {

cout ≪ ␣ ; for (i = 0; i < 4; i^{++}) {

cout ≪ projective coordinates [i];

if (i < 3) cout ≪ ␣ ; } cout ≪ ≪ flush;

§445  3DLDF-1.1.5.1  PERSPECTIVE PROJECTION 117

}

for (i = 0; i < 2; i^{++})

/∗ [LDF 2002.11.07.] KLUDGE. Added this loop. The value used for comparison is slightly larger than one that arose while I was testing the constructor of Trunc Octahedron. eps was too small. ∗/

if (fabs (projective coordinates [i]) ≤ 10.0 · 10^{−05}) projective coordinates [i] = 0; if ( ) cout ≪ ␣ ≪ flush; return true; }

446. No Focus argument. [LDF 2002.09.13.] Added this function. This dummy function just passes default focus to project ( const Focus &f …). This is necessary because it’s impossible make the argument f optional with default focus as the default. This is because project ( ) must be declared inside the class declaration of Point, whereas the declaration of Focus must be later, because it contains Points. It’s not a problem to use default focus inside of project ( ), as long as default focus is defined before the function is called. ⟨ Declare Point functions 329 ⟩ +≡

bool project (const unsigned short &proj = Projections :: , real factor = 1);

447. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::project (const unsigned short &proj , real factor )

{

return project (default focus , proj , factor ); }

448. Applying transformations. This version applies the transformation stored in Point ::transform. !! Add a version that applies a Transform supplied as an argument!! [LDF 2002.12.08.] BUG FIX: See below. ⟨ Declare Point functions 329 ⟩ +≡

void apply transform( );

118  APPLYING TRANSFORMATIONS  3DLDF-1.1.5.1 §449

449. ⟨ Define Point functions 330 ⟩ +≡

void Point ::apply transform( ) {

bool = false; /∗ true ∗/ if (transform.is identity ( )) /∗ If transform.matrix is the identity matrix, we don’t need to bother

to perform the matrix multiplication. ∗/ return;

int i; int j; valarray⟨real⟩ new coordinates ; new coordinates .resize(4, 0); /∗ [LDF 2002.12.08.] BUG FIX. For GNU CC. ∗/ if ( ) {

cout ≪ ␣ ␣ ≪ world coordinates [0] ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ world coordinates [1] ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ world coordinates [2] ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ world coordinates [3] ≪ endl ≪ flush; } for (i = 0; i < 4; i^{++}) {

for (j = 0; j < 4; j^{++}) { new coordinates [i] += world coordinates [j] ∗ transform.matrix [j][i]; if (new coordinates [i] ≠ 0) {

if ( ) {

cout ≪ ≪ i ≪ ␣ ␣ ≪ new coordinates [i] ≪ endl ≪ flush; } }

} } real eps = epsilon( ); for (i = 0; i < 4; i^{++}) {

if ( ) {

cout ≪ ≪ i ≪ ␣ ␣ ≪ new coordinates [i] ≪ endl ≪ flush; } world coordinates [i] = (fabs (new coordinates [i]) > eps ) ? new coordinates [i] : 0;

} transform.reset ( );

}

450. Set transform to identity. ⟨ Declare Point functions 329 ⟩ +≡

void reset transform( );

§451  3DLDF-1.1.5.1  SET TRANSFORM TO IDENTITY 119

451. ⟨ Define Point functions 330 ⟩ +≡

void Point ::reset transform( )

{

transform.reset ( ); }

452. Drawing.

453. Drawdot.

[LDF 2002.10.26.] drawdot ( ) copies ∗this and puts the copy onto the vector shapes of the Picture argument picture. The data members drawdot value, drawdot color , and pen are only set on the copy, not on ∗this . All of the drawing and filling functions behave similarly.

[LDF 2003.05.30.] TO DO: Add code for allocating new Color, if ddrawdot color .use name is false, as in the drawing and filling functions for Path and Solid.

454. Normal version.

Log

[LDF 2003.07.11.] Made ppen and drawdot ( ) itself const.

⟨ Declare Point functions 329 ⟩ +≡

void drawdot (const Color &ddrawdot color = ∗Colors ::default color , const string ppen = , Picture &picture = current picture) const;

455. ⟨ Define Point functions 330 ⟩ +≡

void Point ::drawdot (const Color &ddrawdot color , const string ppen, Picture &picture) const{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪  ≪ flush;

Point ∗pt = create new < Point > (0);

∗pt = ∗this ;

pt drawdot value = ;

pt drawdot color = &ddrawdot color ; #if 1

pt pen = ppen; #endif

picture += static cast⟨Shape ∗⟩(pt );

120 PICTURE ARGUMENT FIRST 3DLDF-1.1.5.1 §456

if ( ) cout ≪ ␣ ≪ ≪ flush; } 456. Picture argument first.

Log

[LDF 2002.01.24.] Added this version.

[LDF 2003.01.31.] Removed default for picture. Having a default made calls to drawdot ( ) with no arguments ambiguous.

[LDF 2003.07.11.] Made ppen and drawdot ( ) itself const.

⟨ Declare Point functions 329 ⟩ +≡

void drawdot (Picture &picture, const Color &ddrawdot color = ∗Colors ::default color , const string ppen = ) const;

457. ⟨ Define Point functions 330 ⟩ +≡

void Point ::drawdot (Picture &picture, const Color &ddrawdot color , const string ppen) const {

drawdot (ddrawdot color , ppen, picture); }

458. Undrawdot. [LDF 2002.10.26.] undraw ( ) does not remove a dot from picture, but causes the METAPOST command undrawdot to be written to out stream when picture is output. ⟨ Declare Point functions 329 ⟩ +≡

void undrawdot (string ppen = , Picture &picture = current picture);

459. ⟨ Define Point functions 330 ⟩ +≡

void Point ::undrawdot (string ppen, Picture &picture){ Point ∗pt = create new < Point > (0); ∗pt = ∗this ; pt drawdot value = ; pt drawdot color = Colors ::background color ;

#if 1

pt pen = ppen; #endif

picture += static cast⟨Shape ∗⟩(pt ); }

460. Picture argument first.

Log

[LDF 2002.01.24.] Added this version.

[LDF 2003.01.31.] Removed default for picture. Having a default made calls to undrawdot ( ) with no arguments ambiguous.

§461  3DLDF-1.1.5.1  PICTURE ARGUMENT FIRST 121

⟨ Declare Point functions 329 ⟩ +≡ void undrawdot (Picture &picture, string ppen = ); 461. ⟨ Define Point functions 330 ⟩ +≡

void Point ::undrawdot (Picture &picture, string ppen)

{

undrawdot (ppen, picture); }

462. Draw. [LDF 2002.10.26.] draw ( ) creates a Path with the two Points ∗this and the argument p, and the connector , calls Path ::draw ( ) for it, and returns the Path. The latter is a line, i.e., Path ::get line switch( ) returns true for it.

draw ( ) must be defined in paths.web, because Path is an incomplete type here.

463. Normal version.

Log

[LDF 2003.01.15.] Added the argument aarrow .

⟨ Declare Point functions 329 ⟩ +≡

Path draw (const Point &p, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = , Picture &picture = current picture, bool aarrow = false) const;

464. Picture argument first. [LDF 2003.01.15.] This function is convenient for when I want to pass a Picture argument.

Log

[LDF 2002.09.17.] Added this function.

[LDF 2003.01.15.] Added the argument aarrow .

⟨ Declare Point functions 329 ⟩ +≡

Path draw (Picture &picture, const Point &p, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = , bool aarrow = false);

465. Draw arrow.

466. Normal version. [LDF 2003.01.15.] Defined in paths.web.

Log

[LDF 2003.01.15.] Added this function.

[LDF 2003.06.03.] Made drawarrow ( ) const.

⟨ Declare Point functions 329 ⟩ +≡

Path drawarrow (const Point &p, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = , Picture &picture = current picture) const; 467. Picture argument first. [LDF 2003.01.15.] Defined in paths.web.

Log

[LDF 2003.06.03.] Made drawarrow ( ) const.

⟨ Declare Point functions 329 ⟩ +≡

Path drawarrow (Picture &picture, const Point &p, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = ) const;

468. Undraw.

469. Normal version. This function must be defined in paths.web, because it uses Path, which is an incomplete type here.

Log

[LDF 2002.4.8.] Added this function.

[LDF 2002.11.03.] Changed this function, so that it returns the Path pa, instead of void.

⟨ Declare Point functions 329 ⟩ +≡

Path undraw (const Point &pt , string ddashed = , string ppen = , Picture &picture = current picture);

470. Picture argument first.

Log

[LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. [LDF 2002.11.03.] Changed this function, so that it returns the Path pa, instead of void.

⟨ Declare Point functions 329 ⟩ +≡ Path undraw (Picture &picture, const Point &pt , string ddashed = , string ppen = );

471. Draw help. [LDF 2002.10.26.] draw help( ) is like draw ( ), except that the Path is only drawn if the static Path data member do help lines ≡ true. This is convenient for drawing construction lines that shouldn’t be output in the final version of a drawing. Also, the default color is ∗Colors ::help color .

472. Normal version. [LDF 2002.4.8.] This function must be defined in paths.web, because it uses Path, which is an incomplete type here.

Log

[LDF 2002.4.8.] Added this function.

[LDF 2003.07.13.] Made this function const.

⟨ Declare Point functions 329 ⟩ +≡

Path draw help(const Point &pt , const Color &ddraw color = ∗Colors ::help color , string ddashed = , string ppen = , Picture &picture = current picture) const; 473. Picture argument first. [LDF 2002.09.17.] This version is convenient for when I want to pass a Picture argument.

Log

[LDF 2002.09.17.] Added this function. [LDF 2003.07.13.] Made this function const.

⟨ Declare Point functions 329 ⟩ +≡

Path draw help(Picture &picture, const Point &pt , const Color &ddraw color = ∗Colors ::help color , string ddashed = , string ppen = ) const;

474. Showing.

475. Show. [LDF 2002.10.26.] The arguments:

string text If text is non-empty, (i.e., not ), it’s written to standard output ( ). If it is empty, or show ( ) is called without any arguments, the default is used, namely .

char coords  One of the characters ,  ,  , or  should be used, to indicate

which set of coordinates should be shown: world coordinates , projective coordinates, user coordinates , or view coordinates , respectively. The latter two exist, but are not currently used. The corresponding uppercase characters can also be used.

const bool do persp Only meaningful if the projective coordinates are being shown (coords argument ). If do persp ≡ true, then project ( ) is called on ∗this before projective coordinates are shown. This is usually what one wants. However, it may sometimes be useful to show the contents of projective coordinates, without calling project ( ), in which case do persp should be false.

const bool do apply Usually, apply transform( ) should be called on ∗this before showing a set of coordinates, so the default for do apply is true. However, it may sometimes be useful to show the values of the coordinates without applying transform, in which case do apply should be false.

Focus ∗f Only meaningful if the projective coordinates are being shown (coords argument ). Refers to the Focus used for projection. If the default is used, or 0 is passed as the argument explicitly, then the global variable default focus is used.

const unsigned short proj Only meaningful if the projective coordinates are being shown (coords argument ). Refers to the projection used. Currently, I’ve only programmed the perspective and the parallel projections. The default is the perspective projection.

const real factor Only meaningful if the projective coordinates are being shown (coords argument ) and the parallel projection is being used. The x and y values in projective coordinates are multiplied by factor , so it can be used to magnify or shrink the projected image. The default is 1 (no magnification or shrinking).

[LDF 2002.10.26.] TO DO: Add case for coords for showing all of the sets of coordinates.

Log

[LDF 2002.10.26.] !! KLUDGE: In the text above, I’ve had to typeset “projective coordinates” using “\it” explicitly in a couple of places, in order to get the hyphenation to work.

[LDF 2002.11.12.] Added “ ” after the arguments to “ ” in the TEX code above in order to suppress a space at the beginning of the first line of the following indented paragraph. I couldn’t figure out a way of suppressing the space within the definition of .

[LDF 2003.04.30.] Changed, so that a newline is not output following text .

⟨ Declare Point functions 329 ⟩ +≡

void show (string text = , char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , const real factor = 1) const;

476. ⟨ Define Point functions 330 ⟩ +≡

void Point ::show (string text , char coords , const bool do persp, const bool do apply , Focus

∗f, const unsigned short proj , const real factor ) const

{ bool = false; /∗ true ∗/ if (text ≡ ) text = ; cout ≪ text ≪ ␣ ; coords = tolower (coords ); if (coords ≡ ) ; /∗ Do nothing. ∗/

else if (coords ≡ ) cout ≪  ␣  ≪ flush;
else if (coords ≡ ) cout ≪  ␣  ≪ flush;
else if (coords ≡ ) cout ≪  ␣  ≪ flush;

else {

  cerr ≪  ␣  ␣         ␣ ≪  ␣         ␣    ␣      ␣  ≪

␣ ␣ ≪ flush; coords = ;

} if (∗this ≡ ) {

cerr ≪ ␣ ␣ ␣ ␣ ␣ ≪ flush;

return; } if ( ) transform.show ( ␣ ␣ ); valarray⟨real⟩ v = get all coords (coords , do persp, do apply , f, proj , factor ); cout ≪ ≪ v[0] ≪ ␣ ≪ v[1] ≪ ␣ ≪ v[2] ≪ ≪ flush; if ( ) {

transform.show (  ␣     ␣  );
cout ≪  ␣  ␣ ≪ on free store ≪  ;

} }

477. Show transform. ⟨ Declare Point functions 329 ⟩ +≡

void show transform(string text = ); 478. ⟨ Define Point functions 330 ⟩ +≡

void Point ::show transform(string text )

{ if (text ≡ ) text = ; cout ≪ text ≪ endl ; transform.show ( );

}

479. Outputting.

480. Output operator. [LDF 2002.10.26.] This function is used in Path ::output ( ) for writing the x and y values of the projective coordinates to out stream. All code using this function must ensure that apply transform( ) and project ( ) are called first!

Log

[LDF 2002.09.16.] Removed calls to apply transform( ) and project ( ).

⟨ Declare non-member non-template functions for Point 480 ⟩ ≡

ostream & operator≪(ostream & o, Point &p);

See also section 534. This code is used in section 634.

481. ⟨ Define non-member non-template functions for Point 481 ⟩ ≡

ostream & operator≪(ostream & o, Point &p)

{

o ≪ ≪ p.get x ( , false, false) ≪ Point ::measurement units ≪ ␣ ≪ p.get y ( , false,

false) ≪ Point ::measurement units ≪ ; return o;

}

See also section 535. This code is used in section 633.

482. Suppress output. [LDF 2002.09.18.] Added this function. It’s needed because trying to erase a Shape ∗ from elements in Picture ::output ( ) causes a memory fault. ⟨ Declare Point functions 329 ⟩ +≡

virtual void suppress output ( );

483. ⟨ Define Point functions 330 ⟩ +≡

void Point ::suppress output ( )

{

do output = false; }

484. Unsuppress output. [LDF 2002.09.18.] Added this function. It’s needed because trying to erase a Shape ∗ from elements in Picture ::output ( ) causes a memory fault. ⟨ Declare Point functions 329 ⟩ +≡

virtual void unsuppress output ( );

126  UNSUPPRESS OUTPUT  3DLDF-1.1.5.1 §485

485. ⟨ Define Point functions 330 ⟩ +≡

void Point ::unsuppress output ( )

{

do output = true; }

486. Extract. [LDF 2002.10.26.] extract ( ) is a pure virtual function in Shape. It’s called by Picture ::output ( ). Each of the Shape pointers on the vector shapes in the Picture must be “extracted”. For Points, this means projecting the Point using the Focus passed to extract ( ) as an argument. If project ( ) succeeds, extract ( ) returns a vector containing this . Otherwise, it returns an empty vector.

[LDF 2002.10.26.] A vector is returned rather than this by itself because it may sometimes be useful to return a collection of Shape pointers rather than a single one. This was formerly the case for Cuboid, but at the present time, no version of extract ( ) returns a vector with more than one pointer to Shape.

Log

[LDF 2002.09.17.] Added const Focus &f argument and error handling code. Now, if the Point cannot be projected onto the projection plane using the Focus f, it is not put onto the vector⟨Shape ∗⟩ Picture ::elements , and consequently never reaches Picture ::output ( ) and Point ::output ( ).

⟨ Declare Point functions 329 ⟩ +≡ vector⟨Shape ∗⟩ extract (const Focus &f, const unsigned short proj , real factor );

§487  3DLDF-1.1.5.1  EXTRACT 127

487. ⟨ Define Point functions 330 ⟩ +≡

vector⟨Shape ∗⟩ Point ::extract (const Focus &f, const unsigned short proj , real factor ) {

bool = false; /∗ true ∗/ vector⟨Shape ∗⟩ v; /∗ [LDF 2002.09.16.] Added this error checking code. Check ∗this first, to

make sure that it can be drawn with the current value of default focus . ∗/ apply transform( ); if (¬project (f, proj , factor )) {

if ( )

    cerr ≪  ␣  ␣  ≪  ␣  ␣    ␣       ␣  ␣          ␣ ≪

␣ ␣ ␣ ≪ flush;

return v; } if ( ) {

cout ≪ ␣ ␣␣␣␣␣ ≪ world coordinates [0] ≪ ␣ ≪ world coordinates [1] ≪ ␣ ≪ world coordinates [2] ≪ ␣ ≪ world coordinates [3] ≪ ≪ ␣ ≪ projective coordinates [0] ≪ ␣ ≪ projective coordinates [1] ≪ ␣ ≪ projective coordinates [2] ≪ ␣ ≪ projective coordinates [3] ≪ ;

} v.push back (this ); return v;

}

488. Get extremes. [LDF 2002.09.18.] Added this function. Any code that calls get extremes ( ) must ensure that project ( ) has been invoked first. ⟨ Declare Point functions 329 ⟩ +≡

virtual inline const valarray⟨real⟩ get extremes ( ) const {

return projective extremes ; }

489. Get minimum z. [LDF 2002.09.17.] Added this function. ⟨ Declare Point functions 329 ⟩ +≡

virtual real get minimum z ( ) const;

128  GET MINIMUM Z  3DLDF-1.1.5.1 §490

490. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get minimum z ( ) const

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ endl ≪ flush;
if (  ) cout ≪  ␣  ␣ ≪ projective extremes [4] ≪ endl ≪ flush;
if (  ) cout ≪  ␣  ≪ endl ≪ flush;

return projective extremes [4]; }

491. Get maximum z. [LDF 2002.09.17.] Added this function. ⟨ Declare Point functions 329 ⟩ +≡

virtual real get maximum z ( ) const;

492. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get maximum z ( ) const

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ endl ≪ flush;
if (  ) cout ≪  ␣  ␣ ≪ projective extremes [5] ≪ endl ≪ flush;
if (  ) cout ≪  ␣  ≪ endl ≪ flush;

return projective extremes [5]; }

493. Get mean z. [LDF 2003.05.16.] Added this function. ⟨ Declare Point functions 329 ⟩ +≡

virtual real get mean z ( ) const;

494. ⟨ Define Point functions 330 ⟩ +≡

real Point ::get mean z ( ) const

{

return ((projective extremes [4] + projective extremes [5])/2); }

495. Set extremes. This function sets “extreme” values for the x, y, and z-coordinates. This is, of course, trivial for Points, because they only have one x, y and z-coordinate. So the maxima and minima for each coordinate are always the same.

[LDF 2002.10.20.] The programmer who uses set extremes ( ) must ensure that apply transform( ) and project ( ) are invoked before set extremes ( )!

Log

[LDF 2002.09.17.] Added this function.

[LDF 2002.09.18.] Changed the name of this function from set minimum z ( ) to set extremes ( ).

§496  3DLDF-1.1.5.1  SET EXTREMES 129

⟨ Declare Point functions 329 ⟩ +≡ virtual bool set extremes ( ); 496. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::set extremes ( ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ endl ≪ flush;

for (int i = 0; i < 4; i^{++}) {

if (projective coordinates [i] ≡ ) {

cerr ≪  ␣  ␣  ≪  ≪ i ≪  ≪

        ␣  ␣  ≪  ␣     ␣        ␣  ␣                   ␣ ≪

␣ ␣ ␣ ␣ ≪ flush;

for (int j = 0; j < 6; j^{++}) projective extremes [j] = ;

return false; }

} projective extremes [0] = projective coordinates [0]; /∗ min x ∗/ projective extremes [1] = projective coordinates [0]; /∗ max x ∗/ projective extremes [2] = projective coordinates [1]; /∗ min y ∗/ projective extremes [3] = projective coordinates [1]; /∗ max y ∗/ projective extremes [4] = projective coordinates [2]; /∗ min z ∗/ projective extremes [5] = projective coordinates [2]; /∗ max z ∗/ if ( ) cout ≪ ␣␣ ≪ endl ≪ flush; return true;

}

497. Comparison classes. [LDF 2003.05.16.] The function classes in this section are used in Picture ::output ( ) to sort the pointers to Shape in vector⟨Shape ∗⟩ elements . The argument sort value, which should be one of the constants in namespace Sorting, determines which one is used, or if elements shouldn’t be sorted.

• If Sorting :: is passed to Picture ::output ( ), Compare minimum z is used for sorting. The elements are sorted in descending order of the minimum z-value from their projective extremes .

• If Sorting :: is passed to Picture ::output ( ), Compare maximum z is used for sorting. The elements are then sorted in descending order of the maximum z-value from their projective extremes .

• If Sorting :: is passed to Picture ::output ( ), Compare mean z is used for sorting. The elements are then sorted in descending order of of the mean of the minimum and maximum z-values from their projective extremes . In all three of these cases, the Shapes that are furthest from the Focus are output first, so that they can

be covered, if necessary, by Shapes that are closer.

• If Sorting :: is passed to Picture ::output ( ), elements is not sorted, and the Shapes are output in the order in which they were drawn or filled.

130  COMPARE MINIMUM Z  3DLDF-1.1.5.1 §498

498. Compare minimum z.

Log

[LDF 2003.05.16.] Added this class.

⟨ Define comparison classes 498 ⟩ ≡ class Compare minimum z { public: int operator( )(const Shape ∗s1 , const Shape ∗s2 ) const

{

return s1 get minimum z ( ) > s2 get minimum z ( ); }

};

See also sections 499 and 500. This code is cited in section 596. This code is used in sections 633 and 634.

499. Compare maximum z.

Log

[LDF 2002.09.17.] Added this class. [LDF 2002.09.21.] Changed from “minimum z” to “maximum z”. This works for the more common cases.

⟨ Define comparison classes 498 ⟩ +≡ class Compare maximum z { public: int operator( )(const Shape ∗s1 , const Shape ∗s2 ) const

{

return s1 get maximum z ( ) > s2 get maximum z ( ); }

};

§500  3DLDF-1.1.5.1  COMPARE MEAN Z 131

500. Compare mean z.

Log

[LDF 2002.09.17.] Added this class.

⟨ Define comparison classes 498 ⟩ +≡ class Compare mean z { public: int operator( )(const Shape ∗s1 , const Shape ∗s2 ) const

{

return (((s1 get minimum z ( ) + s1 get maximum z ( ))/2) > ((s2 get minimum z ( ) + s2 get maximum z ( ))/2));

} };

501. Output. [LDF 2002.10.26.] output ( ) is a pure virtual function in Shape. After the Shape pointers on the vector Picture ::shapes have been extracted, output ( ) is called for each of the Shapes they point to (except for the ones, if any, where project ( ) failed). output ( ) writes the METAPOST code to out stream.

Log

[LDF 2002.09.16.] Added Focus argument f. I want the default to be default focus , but I can’t put it in the declaration, as I normally do, because default focus hasn’t been defined yet. I’ve put it in the definition, and it seems to work. Sometimes it doesn’t, and I don’t know why, nor do I know why it works this time. If I run into problems, this may be the reason. If necessary, I can make a dummy version of this function with no argument that calls this version with default focus as its argument.

[LDF 2002.09.17.] Changed the argument f from Focus to const Focus &. Removed the invocations of apply transform( ) and project ( ) and error handling code to extract ( ).

[LDF 2002.10.23.] Removed the argument f. Since extract ( ) takes care of applying project ( ), the projective coordinates are already set, so all output ( ) needs to do is write them to out stream with the proper METAPOST instructions.

132  OUTPUT  3DLDF-1.1.5.1 §502

⟨ Declare Point functions 329 ⟩ +≡ void output ( ); 502. ⟨ Define Point functions 330 ⟩ +≡

void Point ::output ( ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (do output ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ flush; return;

}

if (drawdot value ≡  ) out stream ≪  ␣ ;
else if (drawdot value ≡  ) out stream ≪  ␣ ;

else /∗ DRAWDOT ∗/ {

cerr ≪ ␣ ␣ ␣ ≪ drawdot value ≪

␣ ␣ ≪ flush;

#if 0 /∗ !! Define a class for information on the run state. ∗/

if (¬Run State ::non stop) getchar ( ); #endif

out stream ≪ ␣ ; } out stream ≪ ≪ projective coordinates [0] ≪ measurement units ≪ ␣ ≪

projective coordinates [1] ≪ measurement units ≪ ; if (drawdot color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗drawdot color ;

#if 1

if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; #endif

out stream ≪ ; if ( ) cout ≪ ␣ ≪ flush;

}

503. Labelling.

504. Label.

§505  3DLDF-1.1.5.1  STRING ARGUMENT 133

505. string argument. [LDF 2002.10.27.] The arguments:

string text str The text for the label.

string position str Indicates the position of the label text relative to the Point. The same strings are permitted as in METAPOST. They are written unchecked to out stream, so if an invalid string is used, it won’t cause an error in 3DLDF, but it will in METAPOST.

The permitted strings are:  (the default),  ,  ,  ,
(upper left),  (lower left),  (upper right),  (lower right), and

for putting the label right on top of the Point. The empty string must be used explicitly, because is the default.

bool dot If true, then dotlabel is written to out stream rather than label. This argument is mainly for use by the function dotlabel ( ), which calls label ( ) with dot ≡ true.

Picture &picture Indicates the Picture onto which the Label should be placed. The default is current picture .

[LDF 2003.01.15.] TO DO: Add pen argument to label ( ) and dotlabel ( )!!

Log

[LDF 2002.05.14.] Changed text str so that it is no longer optional. It doesn’t make any sense to print empty labels, so I’ve made it a required argument.

[LDF 2002.11.12.] Added “ ” after the arguments to “ ” in the TEX code above in order to suppress a space at the beginning of the first line of the following indented paragraph. I couldn’t figure out a way of suppressing the space within the definition of .

[LDF 2003.07.09.] Made text str , position str , and dot arguments const.

⟨ Declare Point functions 329 ⟩ +≡

void label (const string text str , const string position str = , const bool dot = false, Picture &picture = current picture) const;

134 STRING ARGUMENT 3DLDF-1.1.5.1 §506

506. ⟨ Define Point functions 330 ⟩ +≡

void Point ::label (const string text str , const string position str , const bool dot , Picture &picture)

const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪  ≪ flush;

if (Label :: ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ ≪ flush; return;

} if (∗this ≡ ) {

  cerr ≪  ␣  ␣               ␣ ≪  ␣  ␣                   ␣     ␣

≪ flush; return;

} Label ∗lbl = new (Label); lbl pt = create new < Point > (0); ∗(lbl pt ) = ∗this ; if (dot ≡ true) lbl dot = true; lbl position = position str ; if (text str ≠ ) lbl text = text str ; else lbl text = ; picture += lbl ; /∗ [LDF 2002.10.27.] The Label is pushed onto the vector labels in picture. ∗/ if ( ) cout ≪ ␣ ≪ ≪ flush; return; }

§507  3DLDF-1.1.5.1  SHORT ARGUMENT 135

507. short argument. [LDF 2003.04.01.] TO DO: Make non-const version of this function! TO DO: Make it possible to use to use the values in projective coordinates for the label. This will require adding arguments for use by project ( ).

Log

[LDF 2003.04.01.] Changed this function so that it tests whether text short is equal to , , , or , which are public const static data members in Point. If text short is equal to , ∗this is copied and apply transform( ) is called on the copy. This is necessary, because this function is const. Then, the updated values in the world coordinates vector of the copy are used for the label.

[LDF 2003.05.06.] Added comparison of text short with , , , or , which are used for suppressing the z-coordinate, when the values from one of the sets of coordinates are used for the label. Also, no longer copying ∗this , since get x ( ), get y ( ), and get z ( ) are const anyway.

[LDF 2003.05.20.] Added “ ” case.

[LDF 2003.05.22.] BUG FIX: The “ ” case started with if instead of else if . This caused s.str ( ) to have an erroneous five-digit integer following the closing parenthesis, when or was used. I don’t know why this should have been the case, but changing if to else if fixed the problem. It probably had something to do with the fact that had the same value as . I’ve fixed this above today, too.

[LDF 2003.06.06.] Changed the case, where text short = or text short = : The coordinates surrounded by parentheses are now printed out using TEX’s math mode, i.e., “(x, y, z)” instead of “(x, y, z)”.

[LDF 2003.07.09.] Made text short , position str , and dot arguments const.

⟨ Declare Point functions 329 ⟩ +≡

136 SHORT ARGUMENT 3DLDF-1.1.5.1 §508

void label (const short text short , const string position str = , const bool dot = false, Picture &picture = current picture) const; 508. ⟨ Define Point functions 330 ⟩ +≡

void Point ::label (const short text short , const string position str , const bool dot , Picture

&picture) const

{ bool = false; /∗ true ∗/ stringstream s;

if (text short ≡  ∨ text short ≡  ) {
if (  ) cout ≪  ␣           ␣   ␣  ;

s ≪ ≪ get x ( ) ≪ ␣ ≪ get y ( );

if (text short ≡ ) s ≪ ␣ ≪ get z ( );

s ≪ ; } else if (text short ≡ ) {

if ( ) cout ≪ ␣ ;

s ≪ get z ( ); } else if (text short ≡ ) {

if (  ) cout ≪  ␣  ;
cerr ≪  ␣  ␣  ≪ endl ≪  ␣  ␣            ␣ ≪
␣          ␣     ␣    ␣  ≪  ≪ flush;

return; } else if (text short ≡ ) {

if (  ) cout ≪  ␣  ;
cerr ≪  ␣  ␣  ≪ endl ≪  ␣  ␣            ␣ ≪
␣          ␣     ␣    ␣  ≪  ≪ flush;

return; } else if (text short ≡ ) {

if (  ) cout ≪  ␣  ;
cerr ≪  ␣  ␣  ≪ endl ≪  ␣  ␣            ␣ ≪
␣          ␣     ␣    ␣  ≪  ≪ flush;

return; } else {

if ( ) cout ≪ ␣ ␣ ␣ ;

s ≪ text short ; } if ( ) cout ≪ ␣ ␣ ≪ s.str ( ) ≪ endl ≪ flush; label (s.str ( ), position str , dot , picture); return;

}

509. Dotlabel. TO DO: Add an optional pen argument. If it’s used, use drawdot ( ) with the pen argument, together with label ( ). When I do this, I should also add real arguments (to both label ( ) and dotlabel ( )) for shifting the position of the text, and a version with a Point argument for the same purpose. This is so that the dot won’t cover the text. [LDF 2003.07.16.] 510. string argument.

Log

[LDF 2003.07.09.] Made text str and position str arguments const.

⟨ Declare Point functions 329 ⟩ +≡

void dotlabel (const string text str , const string position str = , Picture &picture = current picture) const;

511. ⟨ Define Point functions 330 ⟩ +≡

void Point ::dotlabel (const string text str , const string position str , Picture &picture) const {

label (text str , position str , true, picture); }

512. short argument.

Log

[LDF 2003.07.09.] Made text short and position str arguments const.

⟨ Declare Point functions 329 ⟩ +≡

void dotlabel (const short text short , const string position str = , Picture &picture = current picture) const;

513. ⟨ Define Point functions 330 ⟩ +≡

void Point ::dotlabel (const short text short , const string position str , Picture &picture) const {

label (text short , position str , true, picture); } 514. [LDF 2002.09.06.] Commented out ∼Label( ). This was the cause of a bug that caused a memory fault when I tried to use a label in figure 2 (beginfig (2)) after having used it in figure 1 and then invoking current picture.clear ( ) in between. ⟨ Define Label functions 514 ⟩ ≡ #if 0

Label ::∼Label( )

{

if (pt ≠ 0) delete pt ; }

#endif

See also sections 515 and 516. This code is used in section 633.

515. Get copy of Label. ⟨ Define Label functions 514 ⟩ +≡

Label ∗ Label ::get copy ( ) const{ Label ∗lbl = new (Label); lbl pt = create new < Point > (0); ∗(lbl pt ) = ∗pt ; lbl dot = dot ; lbl text = text ; lbl position = position; return lbl ; }

516. Output Labels. [LDF 2002.10.23.] Declared in pictures.web. Must be defined here, because Point is an incomplete type there.

Log

[LDF 2002.10.23.] Added arguments proj and factor .

⟨ Define Label functions 514 ⟩ +≡ void Label ::output (const Focus &f, const unsigned short proj , real factor , const Transform &t) {

if (¬t.is identity ( )) ∗pt ∗= t;

pt apply transform( );

if (¬pt project (f, proj , factor )) {

      cerr ≪  ␣  ␣  ≪  ␣  ␣     ␣       ␣  ␣          ␣ ≪

␣ ␣ ≪ flush;

return; } if (dot ≡ true) out stream ≪ ; out stream ≪ ; if (position ≠ ) out stream ≪ ≪ position; out stream ≪ ␣ ≪ text ≪ ␣ ␣ ≪ pt get x ( ,

false) ≪ Point ::measurement units ≪ ␣ ≪ pt get y ( , false) ≪ Point ::measurement units ≪ ;

return; }

517. Matrix operations.

518. Multiplication by a Transform with assignment.

§518  3DLDF-1.1.5.1  MULTIPLICATION BY A TRANSFORM WITH ASSIGNMENT 139

Log

[LDF 2002.11.06.] BUG FIX: This function now returns t instead of transform. This makes it possible to chain expressions using operator∗=( ).

⟨ Declare Point functions 329 ⟩ +≡ Transform operator∗=(const Transform &t);

519. ⟨ Define Point functions 330 ⟩ +≡

Transform Point ::operator∗=(const Transform &t)

{

return (transform ∗= t); }

520. Vector operations. [LDF 2002.10.27.] Note that the vector operations don’t affect the w coordinate.

Log

[LDF 2002.10.27.] In the functions operator+( ),operator+=( ), operator−( ), and operator−=( ): It doesn’t seem worth it to write non-const versions, although I could. Now using the elements of p0 .world coordinates directly instead of using get x ( ), get y ( ), and get z ( ). This is safe, as is calling apply transform( ) on p, and saves the cost of three function calls.

521. Vector addition. ⟨ Declare Point functions 329 ⟩ +≡

Point operator+(Point p) const;

522. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::operator+(Point p) const

{ Point a; a = ∗this ; p.apply transform( ); a.shift (p.world coordinates [0], p.world coordinates [1], p.world coordinates [2]); return a;

}

523. Vector addition with assignment. ⟨ Declare Point functions 329 ⟩ +≡

void operator+=(Point p);

140  VECTOR ADDITION WITH ASSIGNMENT  3DLDF-1.1.5.1 §524

524. ⟨ Define Point functions 330 ⟩ +≡

void Point ::operator+=(Point p) {

p.apply transform( );

shift (p.world coordinates [0], p.world coordinates [1], p.world coordinates [2]); }

525. Vector subtraction. ⟨ Declare Point functions 329 ⟩ +≡

Point operator−(Point p) const;

526. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::operator−(Point p) const {

Point a(∗this );

p.apply transform( );

a.shift (−p.world coordinates [0], −p.world coordinates [1], −p.world coordinates [2]); return a;

}

527. Vector subtraction with assignment. ⟨ Declare Point functions 329 ⟩ +≡

void operator−=(Point p);

528. ⟨ Define Point functions 330 ⟩ +≡

void Point ::operator−=(Point p) {

p.apply transform( );

shift (−p.world coordinates [0], −p.world coordinates [1], −p.world coordinates [2]); }

529. Vector-scalar multipication with assignment.

Log

[LDF 2002.10.27.] Made argument r const. Changed return value from Point & to void. [LDF 2003.05.14.] Changed return value from void to real. It now returns the argument r. This makes

it possible to chain invocations of this function.

⟨ Declare Point functions 329 ⟩ +≡ real operator∗=(const real r);

§530  3DLDF-1.1.5.1  VECTOR-SCALAR MULTIPICATION WITH ASSIGNMENT 141

530. ?? I’m not sure whether multiplication with a scalar is commutative with transformations. I doubt it. Therefore, I apply transform before multiplying. ⟨ Define Point functions 330 ⟩ +≡

real Point ::operator∗=(const real r)

{ apply transform( ); for (int i = 0; i < 3; i^{++}) world coordinates [i] ∗= r; return r;

}

531. Vector-scalar multipication.

532. Member version (Point first).

Log

[LDF 2002.10.27.] Made this function and the argument r const.

⟨ Declare Point functions 329 ⟩ +≡ Point operator∗(const real r) const;

533. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::operator∗(const real r) const

{ Point a(∗this ); a.apply transform( ); a ∗= r; return a;

}

534. Non-member version (scalar first). ⟨ Declare non-member non-template functions for Point 480 ⟩ +≡

Point operator∗(const real, const Point &p);

535. ⟨ Define non-member non-template functions for Point 481 ⟩ +≡

Point operator∗(const real r, const Point &p)

{

return p ∗ r; }

536. Unary minus.

Log

[LDF 2002.10.27.] Made this function const.

⟨ Declare Point functions 329 ⟩ +≡ Point operator−( ) const;

142  UNARY MINUS  3DLDF-1.1.5.1 §537

537. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::operator−( ) const {

Point a(∗this );

a.apply transform( );

a ∗= −1;

return a; }

538. Vector-scalar division with assignment. ?? I’m not sure whether division with a scalar is commutative with transformations. I doubt it. Therefore, I apply transform before dividing.

Log

[LDF 2002.10.27.] Made the argument r const.

⟨ Declare Point functions 329 ⟩ +≡ void operator/=(const real r);

539. ⟨ Define Point functions 330 ⟩ +≡

void Point ::operator/=(const real r) {

apply transform( );

for (int i = 0; i < 3; i^{++}) world coordinates [i] /= r; }

540. Vector-scalar division.

Log

[LDF 2002.10.27.] Made this function and the argument r const.

⟨ Declare Point functions 329 ⟩ +≡ Point operator/(const real r) const;

§541  3DLDF-1.1.5.1  VECTOR-SCALAR DIVISION 143

541. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::operator/(const real r) const {

Point a(∗this );

a.apply transform( );

a /= r;

return a; }

542. Dot product.

Log

[LDF 2002.10.27.] Changed this function and argument p to const. Now using world coordinates directly instead of get x ( ), get y ( ), and get z ( ).

[LDF 2003.07.11.] Changed, so that if the dot product is less than Point ::epsilon( ), 0 will be returned.

⟨ Declare Point functions 329 ⟩ +≡ real dot product (Point p) const;

543. ⟨ Define Point functions 330 ⟩ +≡

real Point ::dot product (Point p) const {

Point a(∗this );

a.apply transform( );

p.apply transform( );

real r = ((a.world coordinates [0] ∗ p.world coordinates [0]) + (a.world coordinates [1] ∗

p.world coordinates [1]) + (a.world coordinates [2] ∗ p.world coordinates [2])); if (fabs (r) < Point ::epsilon( )) r = 0; return r;

}

544. Cross product.

Log

[LDF 2002.10.27.] Changed this function and argument p to const. Now using world coordinates directly instead of get x ( ), get y ( ), and get z ( ).

⟨ Declare Point functions 329 ⟩ +≡ Point cross product (Point p) const;

144  CROSS PRODUCT  3DLDF-1.1.5.1 §545

545. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::cross product (Point p) const

{ Point a(∗this ); a.apply transform( ); p.apply transform( ); Point r; r.world coordinates [0] = (a.world coordinates [1] ∗ p.world coordinates [2]) − (a.world coordinates [2] ∗

p.world coordinates [1]); /∗ x. ∗/ r.world coordinates [1] = (a.world coordinates [2] ∗ p.world coordinates [0]) − (a.world coordinates [0] ∗

p.world coordinates [2]); /∗ y. ∗/ r.world coordinates [2] = (a.world coordinates [0] ∗ p.world coordinates [1]) − (a.world coordinates [1] ∗

p.world coordinates [0]); /∗ z. ∗/ return r;

}

546. Magnitude. [LDF 2002.10.27.] The magnitude of a Point is its distance from the origin and is equal to \sqrt{(x^{2} + y^{2} + z^{2})}. Since floats are so large anyway, and since I can easily redefine real to use double or double double, (or

whatever it’s called Look up!!), it’s not really necessary to use an algorithm to approximate \sqrt{(x^{2} + y^{2} + z^{2})} (viz., “Pythagorean addition” in Knuth, Metafont: The Program. (Get reference!!) However, it might be nice to use it anyway.

Log

[LDF 2002.10.27.] Made this function const. Now using world coordinates directly instead of get x ( ), get y ( ), and get z ( ).

⟨ Declare Point functions 329 ⟩ +≡ real magnitude( ) const;

§547  3DLDF-1.1.5.1  MAGNITUDE 145

547. ⟨ Define Point functions 330 ⟩ +≡

real Point ::magnitude( ) const {

bool = true; /∗ false ∗/ real r; real temp; Point a(∗this ); a.apply transform( ); if ((a.world coordinates [0] > ) ∨ (a.world coordinates [1] >

) ∨ (a.world coordinates [2] > )) {

cerr ≪  ␣  ␣  ≪

      ␣   ␣ ␣          ␣   ␣     ␣   ␣  ≪  ␣  ;

return ; } r = a.world coordinates [0] ∗ a.world coordinates [0]; temp = a.world coordinates [1] ∗ a.world coordinates [1]; if ( − r < temp) {

cerr ≪ ␣ ;

cerr ≪ ␣ ␣ ␣ ␣ ␣ ; /∗ !! This show ( ) outputs to stdout . It

would be nice to output it to stderr instead. Must write function for this. ∗/ cerr ≪ ␣ ; return ;

} r += temp; temp = a.world coordinates [2] ∗ a.world coordinates [2]; if ( − r < temp) {

cerr ≪ ␣ ;

cerr ≪ ␣ ␣ ␣ ␣ ␣ ; /∗ !! This show ( ) outputs to stdout . It

would be nice to output it to stderr instead. Must write function for this. ∗/ cerr ≪ ␣ ; return ;

} r += temp; return sqrt (r);

}

548. Angle between two vectors.

Log

[LDF 2002.10.27.] Made this function const. [LDF 2003.07.27.] Made the argument p a const Point &. No longer copying ∗this . Now using

dot product ( ) instead of calculating the angle “by hand”. Simplified the code of the function.

⟨ Declare Point functions 329 ⟩ +≡ real angle(const Point &p) const;

146  ANGLE BETWEEN TWO VECTORS  3DLDF-1.1.5.1 §549

549. ⟨ Define Point functions 330 ⟩ +≡

real Point ::angle(const Point &p) const

{ bool = false; /∗ true ∗/ real mag = magnitude( ); real p mag = p.magnitude( ); if (mag ≡ ) {

cerr ≪ ␣ ␣ ␣ ␣ ≪ ␣ ␣ ; return ;

}

else if (mag ≡ 0) {

if (  ) cerr ≪  ␣  ␣  ≪  ␣   ␣         ␣  ≪

           ␣  ;

return ; } else if (p mag ≡ ) {

cerr ≪ ␣ ␣ ␣ ␣ ≪ ␣ ␣ ; return ;

}

else if (p mag ≡ 0) {

if (  ) cerr ≪  ␣  ␣  ≪ ␣   ␣         ␣  ≪

           ␣  ;

return ; } else return (180/ ∗ acos (dot product (p)/(mag ∗ p mag )));

}

550. Unit vector.

Log

[LDF 2002.10.27.] Added a second version. If assign is not used, unit vector ( ) can be const, so I now have a const version with no argument and a non-const one for assignment that should be called with the argument true.

551. With assignment. This version should only ever be called with true as its argument. Using false will work, unless ∗this is const, in which case it will cause an compilation error. [LDF 2002.10.27.]

If the optional silent argument is true, warning messages will be suppressed, otherwise, they will be issued. The const version below can’t have an optional silent argument, because that would make a call to this function with one argument ambiguous.

Log

[LDF 2002.10.27.] If magnitude( ) fails, unit vector ( ) now returns instead of origin.

[LDF 2003.07.01.] Added the silent argument to suppress warning messages. I kept getting warnings when this function was called from intersection functions, in cases where it wasn’t a problem, that a Point (vector) had 0 magnitude.

§552  3DLDF-1.1.5.1  WITH ASSIGNMENT 147

⟨ Declare Point functions 329 ⟩ +≡ Point unit vector (const bool assign, const bool silent = false); 552. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::unit vector (const bool assign, const bool silent ) {

if (assign ≡ false) {

if (¬silent ) {

cerr ≪  ␣  ␣  ≪

        ␣    ␣    ␣        ␣    ␣     ␣  ␣    ␣  ≪
        ␣            ␣        ␣  ␣        ␣  ≪

␣ ␣ ␣ ␣ ≪ flush;

}

return unit vector ( ); } apply transform( ); real m = magnitude( ); if (m ≡ 0)

/∗ LDF 2002.04.10. Added this error handling code for the case where *this has no magnitude. ∗/ {

if (¬silent ) {

cerr ≪  ␣  ␣  ≪

        ␣        ␣   ␣   ␣          ␣         ␣  ≪ flush;

}

return ; } for (int i = 0; i < 3; i^{++}) world coordinates [i] /= m; world coordinates [3] = 1; /∗ [LDF 2002.10.27.] Setting the w-coordinate to 1, just to be sure. ∗/ return ∗this ;

}

553. const (no assignment). ⟨ Declare Point functions 329 ⟩ +≡

Point unit vector ( ) const;

554. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::unit vector ( ) const {

Point a(∗this ); return a.unit vector (true);

}

555. Mediation.

Log

[LDF 2003.12.09.] Changed from a non-member to a const member function.

⟨ Declare Point functions 329 ⟩ +≡ Point mediate(Point p, const real r = .5) const;

148  MEDIATION  3DLDF-1.1.5.1 §556

556. ⟨ Define Point functions 330 ⟩ +≡

Point Point ::mediate(Point p, const real r) const

{ Point t(∗this ); t ∗= (1 − r); p ∗= r; return (t + p);

}

557. Get normal. get normal ( ) must be defined in paths.web, because it uses a Path in its definition, which is an incompletely defined type in this file.

Log

[LDF 2003.07.11.] Added this declaration.

⟨ Declare Point functions 329 ⟩ +≡ Point get normal (const Point &p, const Point &q) const;

558. Comparison.

559. Equality. !! I may have to adjust to value of eps . It would be nice to be able to use epsilon( ), but for other purposes epsilon( ) must be smaller. Transformations seem to cause fairly large inaccuracies in the values of the coordinates, so I need greater tolerance in the functions testing for equality and inequality.

This function could be formulated more succinctly, but I had some trouble getting it to work properly, so I’m leaving it in its more verbose form, in case I have to debug it some more.

560. Non-const version.

Log

[LDF 2002.10.27.] Revised this function. Now using Point a and Point q. Added factor and using it as the argument to clean( ) and for calculating eps . Since this function is an operator, it’s not possible to pass factor as an argument, unfortunately. Using clean(factor ) makes it possible to compare the coordinates with 0 directly rather than using fabs ( ) and eps . Also, operator≡( ) now uses world coordinates directly rather than get x ( ), get y ( ), and get z ( ).

[LDF 2003.07.09.] Made this function non-const, and added const version below.

⟨ Declare Point functions 329 ⟩ +≡ bool operator≡(Point p); 561. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::operator≡(Point p){ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪  ≪ flush;

unsigned short factor = 10; /∗ LDF 2002.10.27. Added. ∗/ clean(factor ); p.clean(factor ); real eps = epsilon( ) ∗ factor ; /∗ This currently makes eps ≡ .0001. ∗/ real t x = world coordinates [0]; real t y = world coordinates [1]; real t z = world coordinates [2]; real p x = p.world coordinates [0]; real p y = p.world coordinates [1]; real p z = p.world coordinates [2];

562. Points are frequently compared to , so it’s best to suppress debugging output for these comparisons, because they’re probably not the ones we’re interested in. ⟨ Define Point functions 330 ⟩ +≡

if (t x ≡  ∨ t y ≡  ∨ t z ≡  ∨ p x ≡  ∨ p y ≡
∨ p z ≡  )  = false;

563. Debugging output. ⟨ Define Point functions 330 ⟩ +≡

if ( ) { cout ≪ ␣ ␣ ≪ t x ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ t y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ t z ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p x ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p z ≪ endl ≪ flush;

}

564. Check whether the coordinates of both Points are all 0.

Log

[LDF 2002.10.27.] Now that clean(10) and p.clean(10) are called above, it’s no longer necessary to compare the absolute values of the coordinates. I can just compare them with 0 instead.

⟨ Define Point functions 330 ⟩ +≡

if (t x ≡ 0 ∧ p x ≡ 0 ∧ t y ≡ 0 ∧ p y ≡ 0 ∧ t z ≡ 0 ∧ p z ≡ 0) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ; return true;

} 565. Get the signs of the coordinates.

Log

[LDF 2002.10.27.] As in the previous section, changed so that the coordinates are compared with 0, instead of using fabs ( ) and eps .

⟨ Define Point functions 330 ⟩ +≡ signed short t x sign; signed short t y sign; signed short t z sign; signed short p x sign; signed short p y sign; signed short p z sign; if (t x ≡ 0) t x sign = 0; else if (t x < 0) t x sign = −1; else t x sign = 1; if (t y ≡ 0) t y sign = 0; else if (t y < 0) t y sign = −1; else t y sign = 1; if (t z ≡ 0) t z sign = 0; else if (t z < 0) t z sign = −1; else t z sign = 1; if (p x ≡ 0) p x sign = 0; else if (p x < 0) p x sign = −1; else p x sign = 1; if (p y ≡ 0) p y sign = 0; else if (p y < 0) p y sign = −1; else p y sign = 1; if (p z ≡ 0) p z sign = 0; else if (p z < 0) p z sign = −1; else p z sign = 1; if ( ) {

cout ≪ ␣ ␣ ≪ t x sign ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ t y sign ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ t z sign ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p x sign ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p y sign ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ p z sign ≪ endl ≪ flush;

} if ((t x sign ≠ p x sign) ∨ (t y sign ≠ p y sign) ∨ (t z sign ≠ p z sign)) {

if ( )

    cout ≪ ␣     ␣   ␣          ␣    ␣   ␣     ␣     ␣       ␣ ≪  ␣  ;

return false; } 566. Get the difference between each pair of x, y, and z-coordinates. ⟨ Define Point functions 330 ⟩ +≡

t x = fabs (t x ); t y = fabs (t y ); t z = fabs (t z ); p x = fabs (p x ); p y = fabs (p y ); p z = fabs (p z ); real delta x = fabs (t x − p x ); real delta y = fabs (t y − p y ); real delta z = fabs (t z − p z ); if ( ) {

cout ≪ ␣ ␣ ≪ delta x ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ delta y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ delta z ≪ endl ≪ flush;

} bool r; /∗ [LDF 2002.10.27.] The return value. It’s only needed for the sake of the debugging code.

Otherwise, this function could just return the result of the following expression. ∗/ r = (delta x < eps ∧ delta y < eps ∧ delta z < eps ); if ( ) cout ≪ ␣ ␣ ≪ r ≪ endl ≪ flush; if ( ) cout ≪ ␣ ≪ ≪ flush; return r; }

567. const version. [LDF 2003.07.09.] This function merely copies ∗this and calls the non-const version on the copy. Here, p can be a const Point &, because this function does nothing but pass it to non-const version, where it is passed by value.

Log

[LDF 2003.07.09.] Added this version. Made the original version non-const.

⟨ Declare Point functions 329 ⟩ +≡ bool operator≡(const Point &p) const;

568. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::operator≡(const Point &p) const {

Point copy (∗this );

return (copy ≡ p); }

569. Inequality. ⟨ Declare Point functions 329 ⟩ +≡

bool operator≠(const Point &p) const;

152  INEQUALITY  3DLDF-1.1.5.1 §570

570. ⟨ Define Point functions 330 ⟩ +≡

bool Point ::operator≠(const Point &p) const

{

return ¬(∗this ≡ p); }

571. Intersection.

[LDF 2002.10.27.] intersection point ( ) takes four Point arguments. It assumes that the first and second represent one line segment and the third and fourth another. It calculates the intersection point of the two lines, if any, and returns a bool point. If the intersection point exists and is on both line segments, the bool is true and the Point is the intersection point. If the intersection point exists, but is not on both line segments, the bool is false and the Point is the intersection point. If no intersection point exists, i.e, the line segments are congruent or parallel, then the bool is false and the Point is .

LDF Date? Note that intersection point ( ) had to be defined as a static member function, because Path ::intersection point ( ) was not able to resolve the call of this version, when it was not callable as “Point ::intersection point ( )”. I got a compiler error, because the call of intersection point ( ) inside Path ::intersection point ( ) with four references to Points as arguments was deemed to have “too many arguments” and the references to Point couldn’t be converted to const references to Path.

572. Vector version. [LDF 2003.06.29.] Defined in lines.web, because Line is an incomplete type here.

The algorithm used in this function is taken from Jones, Huw. Computer Graphics Through Key Mathematics, pp. 208–311. See References for the complete reference.

!! It may be necessary or desirable to add try…catch blocks where calculations are performed below, just in case overflow occurs.

!! Under Linux, both this function and the version of intersection points ( ) using traces have failed in the same cases, which involved coplanar lines which had been rotated about the z-axis or the y and z-axes. I suspect it has to do with the routines for sine and cosine, since I’ve had trouble with rotation in the constructors for Polyhedra. [LDF 2003.06.29.]

Log

[LDF 2002.04.10.] Added this function. It replaces the old version, below.

[LDF 2002.04.12.] Removed the definition of this function to lines.web, because it requires the use of Lines, and Line is an incomplete type here.

[LDF 2003.06.29.] Started using this version again. Bug fixes I’ve made elsewhere seem to have made it function.

⟨ Declare Point functions 329 ⟩ +≡

static bool point intersection point (const Point &pp0 , const Point &pp1 , const Point &qq0 , const Point &qq1 );

573. Trace version. This function finds the intersection point of two lines by finding the intersection points of the traces of the lines on the major planes. I originally wrote it, because the vector version didn’t work. Bug fixes elsewhere seem to have fixed the problem, so this version isn’t really needed anymore.

[LDF 2003.06.29.]

The bool argument trace serves only to distinguish this function from the vector version. It doesn’t matter whether it’s true or false. [LDF 2003.06.29.]

Log

[LDF 2002.10.27.] Changed the const Point & arguments to Point, because I had to copy them anyway in order to call apply transform( ) on them.

§573  3DLDF-1.1.5.1  TRACE VERSION 153

[LDF 2003.06.29.] Added the bool argument trace, in order to be able to use both the vector and trace versions. Previously, the vector version didn’t work, and was commented-out. Now, bug fixes elsewhere seem to have made the vector version work. Both versions, however, failed under Linux. See the TEX section for the vector version, above, for more information.

⟨ Declare Point functions 329 ⟩ +≡ static bool point intersection point (Point p0 , Point p1 , Point q0 , Point q1 , const bool trace);

574. ⟨ Define Point functions 330 ⟩ +≡

bool point Point ::intersection point (Point p0 , Point p1 , Point q0 , Point q1 , const bool trace){

bool = false; /∗ true ∗/ if ( ) {

cout ≪ ␣ ≪ flush; p0 .show ( ); p1 .show ( ); q0 .show ( ); q1 .show ( );

}

bool point bp; /∗ Return value. ∗/

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

575. Apply the transformations, so we have the correct values for x, y, and z in each of the Points. Then assign them to variables. ⟨ Define Point functions 330 ⟩ +≡

p0 .apply transform( ); p1 .apply transform( ); q0 .apply transform( ); q1 .apply transform( ); real p0 x = p0 .world coordinates [0]; real p0 y = p0 .world coordinates [1]; real p0 z = p0 .world coordinates [2]; real p1 x = p1 .world coordinates [0]; real p1 y = p1 .world coordinates [1]; real p1 z = p1 .world coordinates [2]; real q0 x = q0 .world coordinates [0]; real q0 y = q0 .world coordinates [1]; real q0 z = q0 .world coordinates [2]; real q1 x = q1 .world coordinates [0]; real q1 y = q1 .world coordinates [1]; real q1 z = q1 .world coordinates [2];

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

154  TRACE VERSION  3DLDF-1.1.5.1 §576

576. Get deltas. ⟨ Define Point functions 330 ⟩ +≡

real delta x p = p1 x − p0 x ; real delta y p = p1 y − p0 y ; real delta z p = p1 z − p0 z ; real delta x q = q1 x − q0 x ; real delta y q = q1 y − q0 y ; real delta z q = q1 z − q0 z ;

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

577. Slopes for line \overrightarrow{p_{0}p_{1}}. ⟨ Define Point functions 330 ⟩ +≡

real slope p x y = (delta x p ≠ 0) ? delta y p/delta x p : ; real slope p x z = (delta x p ≠ 0) ? delta z p/delta x p : ; real slope p z y = (delta z p ≠ 0) ? delta y p/delta z p : ;

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

578. Slopes for line \overrightarrow{q_{0}q_{1}}. ⟨ Define Point functions 330 ⟩ +≡

real slope q x y = (delta x q ≠ 0) ? delta y q /delta x q : ; real slope q x z = (delta x q ≠ 0) ? delta z q /delta x q : ; real slope q z y = (delta z q ≠ 0) ? delta y q /delta z q : ;

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

579. The traces on the x-y plane. x i , y i , z i , y int p, and y int q are set to so that I can test for whether the routines below succeed in setting them correctly. ⟨ Define Point functions 330 ⟩ +≡

real x i =  ;  /∗ x-coordinate of the intersection point. ∗/
real y i =  ;  /∗ y-coordinate of the intersection point. ∗/
real z i =  ;  /∗ z-coordinate of the intersection point. ∗/
real y int p =  ;  /∗ y-intercept of \overrightarrow{p_{0}p_{1}}. ∗/
real y int q =  ;  /∗ y-intercept of \overrightarrow{q_{0}q_{1}}. ∗/
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
if (slope p x y ≠  )  /∗ Δx_{p} ≠ 0. ∗/

{

y int p = p0 y − (slope p x y ∗ p0 x ); } if (slope q x y ≠ ) /∗ Δx_{q} ≠ 0. ∗/ {

y int q = q0 y − (slope q x y ∗ q0 x ); }

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

580.

• If both of the traces of p⃗ and q⃗ in the x-y plane are parallel to the y-axis (i.e., Δx = 0), we test whether p_{x} = q_{x}. If they are, then we set x i to that value. If they’re not, the lines don’t intersect, so we return .

• If the trace of p⃗ or the trace of q⃗ in the x-y plane is parallel to the y-axis, we set x i to its x-value, because in this case, the intersection point must have this x-value.

• If Δx_{p} ≠ 0 and Δx_{q} ≠ 0, we derive x i using the slope and y-intercept of the lines. ⟨ Define Point functions 330 ⟩ +≡

if (y int p ≡ ∧ y int q ≡ )

/∗ p⃗_{xz} and q⃗_{xz} are both parallel to the z-axis. ∗/ {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; if (p0 x ≡ q0 x ) /∗ They have the same value for x. ∗/ {

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
if (  ) cout ≪  ␣  ␣   ␣      ␣   ␣  ≪ flush;

x i = p0 x ; real y int p z = ; real y int q z = ; if (slope p z y ≠ ) y int p z = p0 y − slope p z y ∗ p0 z ; if (slope q z y ≠ ) y int q z = q0 y − slope q z y ∗ q0 z ;

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
if (slope p z y ≡  ∧ slope q z y ≡  ) {
if (  ) cout ≪  ␣      ␣  ␣   ␣      ␣   ␣  ≪ flush;
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
if (p0 z ≡ q0 z ) cerr ≪  ␣   ␣  ;
else cerr ≪  ␣  ␣   ␣  ;
cerr ≪  ␣  ≪ flush;

return ; } else if (slope p z y ≡ ) {

if (  ) cout ≪  ␣       ␣  ␣  ≪ flush;
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

z i = p0 z ; y i = z i ∗ slope q z y + y int q z ; if ( ) {

cout ≪ ␣ ␣ ≪ x i ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ y i ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ z i ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ slope q z y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y int q z ≪ endl ≪ flush;

} } else if (slope q z y ≡ ) {

if (  ) cout ≪  ␣       ␣  ␣  ≪ flush;
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

z i = q0 z ; y i = z i ∗ slope p z y + y int p z ; if ( ) {

cout ≪ ␣ ␣ ≪ x i ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ y i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ z i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ slope p z y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y int p z ≪ endl ≪ flush;

} } else {

if (  ) cout ≪  ␣     ␣  ␣  ≪ flush;
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

z i = (y int q z − y int p z )/(slope p z y − slope q z y ); y i = slope p z y ∗ z i + y int p z ; if ( ) {

cout ≪ ␣ ␣ ≪ x i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ z i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ slope p z y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y int p z ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ slope q z y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y int q z ≪ endl ≪ flush;

} }

} else /∗ They don’t have the same value for x. ∗/ {

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
cerr ≪  ␣  ␣   ␣  ;

cerr ≪ ≪ p0 x ≪ ␣ ≪ p0 y ≪ ␣ ≪ p0 z ≪ ␣ ␣ ≪ p1 x ≪ ␣ ≪ p1 y ≪ ␣ ≪ p1 z ≪ ≪ q0 x ≪ ␣ ≪ q0 y ≪ ␣ ≪ q0 z ≪ ␣ ␣ ≪ q1 x ≪ ␣ ≪ q1 y ≪ ␣ ≪ q1 z ≪ ␣ ≪ flush;

return ; }

} else if (y int p ≡ ) /∗ p⃗_{xy} is parallel to the y-axis. ∗/ {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; x i = p0 x ; y i = slope q x y ∗ x i + y int q ;

} else if (y int q ≡ ) /∗ q⃗_{xy} is parallel to the y-axis. ∗/ {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; x i = q0 x ; y i = slope p x y ∗ x i + y int p;

} 581. [LDF 2002.11.12.] !! BUG: Occurred when I tried to find an intersection of two lines in the x-z plane. This code shouldn’t be reached. Rotating the objects 90^{∘} around the x-axis, putting them into the x-y plane, fixed the problem. Obviously, the case that the objects are in the x-z plane already isn’t handled properly. ⟨ Define Point functions 330 ⟩ +≡

else /∗ Neither q⃗_{xy} nor q⃗_{xy} is parallel to the y-axis. ∗/ {

if ( ) /∗ [LDF 2002.11.12.] Start working on finding bug here. ∗/ {

cout ≪ ␣ ␣ ␣ ≪ flush;

cout ≪ ␣ ␣ ≪ slope p x y ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ slope q x y ≪ endl ≪ flush;

}

if (slope p x y ≠ slope q x y ) { x i = (y int q − y int p)/(slope p x y − slope q x y ); y i = slope p x y ∗ x i + y int p;

} }

582. The trace on the x-z plane. We don’t need to do this if we’ve calculated z i above, in the case that the traces on the x-y plane are coincident. ⟨ Define Point functions 330 ⟩ +≡

if (z i ≡ ) {

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
real z int p =  ;  /∗ z-intercept of \overrightarrow{p_{0}p_{1}}. ∗/
real z int q =  ;  /∗ z-intercept of \overrightarrow{q_{0}q_{1}}. ∗/
if (slope p x z ≠  )  /∗ Δx_{p} ≠ 0. ∗/

{

z int p = p0 z − (slope p x z ∗ p0 x ); } if (slope q x z ≠ ) /∗ Δx_{q} ≠ 0. ∗/ {

z int q = q0 z − (slope q x z ∗ q0 x ); } if ( ) {

cout ≪ ␣ ␣ ≪ z int p ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ z int q ≪ endl ≪ flush; }

583. [LDF 2003.06.24.] x i will be equal to , if the traces of the lines on the x-y plane were colinear.

Log

[LDF 2003.06.24.] Added this conditional.

⟨ Define Point functions 330 ⟩ +≡

if (x i ≡ ∧ ¬(z int p ≡ ∨ z int q ≡ )) { x i = (z int q − z int p)/(slope p x z − slope q x z ); y i = p0 y ;

} 584. In the following case, p⃗_{xz} and q⃗_{xz} are both parallel to the z-axis. They have the same value for x. We’ve set x i above, so there’s no need to do so here again. ⟨ Define Point functions 330 ⟩ +≡

if (z int p ≡  ∧ z int q ≡  ) {
if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;

if (p0 x ≠ q0 x ) {

if (  ) cout ≪  ␣     ␣    ␣  ≪ flush;
cerr ≪  ␣  ␣   ␣  ≪  ≪ p0 x ≪ ␣ ≪ p0 z ≪ ␣ ≪
p0 z ≪ ␣ ␣ ≪ p1 x ≪ ␣ ≪ p1 z ≪ ␣ ≪ p1 z ≪ ≪ q0 x ≪
␣ ≪ q0 z ≪ ␣ ≪ q0 z ≪ ␣ ␣ ≪ q1 x ≪ ␣ ≪ q1 z ≪ q1 z ≪
␣ ≪ flush;

return ; }

} else if (z int p ≡ ) {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; z i = p0 z ;

} else if (z int q ≡ ) {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; z i = q0 z ;

} else {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; z i = slope p x z ∗ x i + z int p;

} } 585. [LDF 2002.10.27.] If x i , y i , and z i are all valid, set bp.pt using those values. Otherwise, set it to . If this Point is on both of the line segments \overrightarrow{p_{0}p_{1}} and \overrightarrow{q_{0}q_{1}}, set bp.b to true, otherwise set it to false. ⟨ Define Point functions 330 ⟩ +≡

if ( ) { cout ≪ ␣ ␣ ␣ ≪ flush; cout ≪ ␣ ␣ ≪ x i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ y i ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ z i ≪ endl ≪ flush;

} if (x i ≡ ∨ y i ≡ ∨ z i ≡ ) {

return ; if ( ) cout ≪ ␣ ≪ flush;

} else {

bp.pt .set (x i , y i , z i ); if ( ) bp.pt .show ( );

} if (bp.pt .is on segment (p0 , p1 ).first ≡ false ∨ bp.pt .is on segment (q0 , q1 ).first ≡ false) bp.b = false; else bp.b = true; if ( ) {

cout ≪ ␣ ␣ ≪ bp.b ≪ endl ; cout ≪ ␣ ≪ flush;

} return bp; }

586. Picture functions. These functions must be defined here, because they use types which are incompletely defined in pictures.web.

587. Assignment operator. !! PORTING [LDF 2002.12.05.] Moved here from pictures.web. See that file for explanation. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::operator=(const Picture &p) {

clear ( ); transform = p.transform; for (vector⟨Shape ∗⟩::const iterator iter = p.shapes .begin( ); iter ≠ p.shapes .end ( ); iter^{++}) {

shapes .push back ((∗iter ) get copy ( )); } Label ∗lbl ; for (vector⟨Label ∗⟩::const iterator iter = p.labels .begin( ); iter ≠ p.labels .end ( ); iter^{++}) {

lbl = (∗iter ) get copy ( );

labels .push back (lbl ); }

}

588. Copy constructor. !! PORTING [LDF 2002.12.05.] Moved here from pictures.web. See that file for explanation. ⟨ Define Picture functions 264 ⟩ +≡

Picture ::Picture(const Picture &p) : do labels (true) {

160  COPY CONSTRUCTOR  3DLDF-1.1.5.1 §588

∗this = p; }

589. Combining Pictures. [LDF 2002.04.17.] Added this function.

Log

[LDF 2002.10.29.] Made p const and fixed bugs that changed p (see below). [LDF 2002.10.29.] BUG FIX: Now, p.transform is applied to ∗(shapes .back ( )), previously it was applied

to ∗∗iter , which was not what I wanted.

[LDF 2002.10.29.] BUG FIX: Now, p.transform is applied to ∗(labels .back ( ) pt ), previously it was applied to ∗((∗iter ) pt ), which is not what I wanted.

[LDF 2002.10.29.] BUG FIX: Now, p.transform.reset ( ) is no longer called.

⟨ Define Picture functions 264 ⟩ +≡ void Picture ::operator+=(const Picture &p) {

for (vector⟨Shape ∗⟩::const iterator iter = p.shapes .begin( ); iter ≠ p.shapes .end ( ); iter^{++}) { shapes .push back ((∗iter ) get copy ( ));

/∗ [LDF 2002.10.29.] Normally, transform in a Picture is applied to its Shapes when it’s output, however, it must be done now for the copies of the Shapes from Picture p that are copied onto ∗this , because p.transform is only known within p; the Shapes don’t “know” about it. ∗/

∗(shapes .back ( )) ∗= p.transform; } for (vector⟨Label ∗⟩::const iterator iter = p.labels .begin( ); iter ≠ p.labels .end ( ); iter^{++}) {

labels .push back ((∗iter ) get copy ( ));

∗(labels .back ( ) pt ) ∗= p.transform; }

}

590. Clear Picture. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::clear ( ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (shapes .size( ) ≤ 0 ∧ labels .size( ) ≤ 0) return; transform.reset ( ); for (vector⟨Shape ∗⟩::iterator iter = shapes .begin( ); iter ≠ shapes .end ( ); iter^{++}) {

(∗iter ) clear ( );

delete (∗iter ); } for (vector⟨Label ∗⟩::iterator iter = labels .begin( ); iter ≠ labels .end ( ); iter^{++}) {

/∗ ?? I tried to use ∼Label( ) here, but it didn’t work. I got run-time errors having to do with “Unaligned access pid=299273…” (didn’t understand). This works, though. If I change the definition of Label, I’ll have to make corresponding changes here. ∗/

delete (∗iter ) pt ;

delete (∗iter ); } shapes .clear ( );

§590  3DLDF-1.1.5.1  CLEAR PICTURE 161

labels .clear ( );

if ( ) cout ≪ ␣ ≪ flush; }

591. Output. The arguments:

• sort value is used to determine how to sort the Shapes. The values to be used are found in namespace Sorting. Sorting :: is used, if they shouldn’t be sorted, because we will have already drawn them in the order we want them rendered. Sorting :: is used for sorting them according to their maximum z-coordinate for “furthest-first” output. Sorting :: is used for sorting them according to their maximum z-coordinate for “nearest-last” output. So far, no other types of sorting have been defined. The simple painter’s algorithm implemented here for surface hiding fails for Shapes where one Shape is

partly in front of and partly behind another. For these cases, it will be necessary to find the intersection points and divide the Shapes into parts. TO DO: Implement a routine for dividing up Shapes. This will not be done soon!

do warnings : Sometimes we’ll want use the min x proj , max x proj , etc., arguments to cut off parts of the image, or we’ll deliberately place the Focus where it won’t be able to “see” part of the image. In these cases, it will be annoying to see the warnings.

Log

[LDF 2002.09.21.] Added the arguments do sort and do warnings . [LDF 2003.05.16.] Changed bool do sort to const unsigned short sort value. About to add namespace

Sorting with constants for different ways of sorting, i.e., “no sort”, “nearest-last”, or “furthest-first”.

592. Focus argument. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::output (const Focus &f, const unsigned short proj , real factor , const unsigned short sort value, const bool do warnings , const real min x proj , const real max x proj , const real min y proj , const real max y proj , const real min z proj , const real max z proj ){ bool = false; /∗ true ∗/

using namespace Sorting;

if ( ) { cout ≪ ␣ ␣ ␣ ≪ flush; cout ≪ ␣ ␣ ≪ min x proj ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ max x proj ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ min y proj ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ max y proj ≪ endl ≪ flush;

} /∗ Check whether the vector shapes has anything in it. If it doesn’t, return. ∗/ if (shapes .size( ) ≤ 0 ∧ labels .size( ) ≤ 0) {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; return;

} 593. [LDF 2002.09.17.] Some Shapes may consist of other Shapes, and not have an output ( ) function of their own, so we must extract their contents recursively until we get to Shapes that have one. So far, only Point, Path, and Solid have output ( ) functions, and all other Shapes reduce to Paths or Solids.

[LDF 2002.09.17.] extract ( ) checks that all of the Points contained in the Shape can be projected with the Focus that is being used. If any of them cannot be, then extract ( ) returns an empty vector of Shapes. This means that any Shape must be entirely projectable; partial Shapes will not be output. problem, too.

Log

[LDF 2003.01.05.] Modified the TEX text above to account for the fact that I’ve added Solid. [LDF 2003.01.05.] BUG FIX: Moved the code that causes transform to be applied to the elements of

shapes . This is now done before the extremes are set. The way it was before didn’t work properly, because extract ( ) used the untransformed values to decide whether a Shape was projectable. In order to do this, I had to make apply transform( ) a Shape function.

⟨ Define Picture functions 264 ⟩ +≡ vector⟨Shape ∗⟩ v; vector⟨Shape ∗⟩ elements ; vector⟨Shape ∗⟩::iterator iter ; bool do transform = ¬transform.is identity ( ); = false; /∗ true ∗/ if ( ) {

if (do transform) { cout ≪ ␣ ; transform.show ( );

}

else cout ≪ ␣ ␣ ; } for (iter = shapes .begin( ); iter ≠ shapes .end ( ); ^{++}iter ) {

if (do transform) {

(∗∗iter ) ∗= transform; } v = (∗iter ) extract (f, proj , factor ); if ( ∧ v.size( ) ≡ 0)

    cerr ≪  ␣  ␣  ≪  ␣        ␣   ␣     ␣       ␣ ≪

≪ flush;

for (vector⟨Shape ∗⟩::iterator i = v.begin( ); i ≠ v.end ( ); ^{++}i) {

elements .push back (∗i); }

} = false;

§594  3DLDF-1.1.5.1  FOCUS ARGUMENT 163

594. Set the extremes for the Shape and handle the error if it returns false. (LDF Undated)

Log

[LDF 2002.09.18.] Changed the error handling code below. Formerly, get minimum z ( ) was invoked, but this is unnecessary, since set extremes ( ) returns false if something goes wrong with setting the extreme values for the Shape.

⟨ Define Picture functions 264 ⟩ +≡ { /∗ [LDF 2003.01.05.] Beginning of group. ∗/ valarray⟨real⟩ extremes (6, 0); for (iter = elements .begin( ); iter ≠ elements .end ( ); ^{++}iter ) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; if (¬(∗∗iter ).set extremes ( )) {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ≪

␣ ␣ ␣ ␣ ≪ flush; (∗∗iter ).suppress output ( );

}

595. [LDF 2002.09.18.] Added this routine. It checks for whether the values in the valarray⟨real⟩ projective extremes in the Shape fall within the limits given by the min x proj , max x proj , min y proj , and max x proj arguments to this function (Picture ::output ( )). (Note that min z proj and max z proj are currently not checked.) If they don’t, the Shape ∗ is removed from elements . Note that the projected z-coordinates are not currently checked, but they are used for ordering the Shapes for output (furthest away first). ⟨ Define Picture functions 264 ⟩ +≡

extremes = (∗∗iter ).get extremes ( ); if ( ) /∗ [LDF 2002.09.21.] Show the extremes for this Shape. ∗/ {

for (int i = 0; i < 4; i^{++}) {

cout ≪ ≪ i ≪ ␣ ␣ ≪ extremes [i] ≪ ; } cout ≪ ␣ ␣ ␣ ␣ ≪ (extremes [0] < min x proj ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ␣ ␣ ≪ (extremes [1] > max x proj ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ␣ ␣ ≪ (extremes [2] < min y proj ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ␣ ␣ ≪ (extremes [3] > max y proj ) ≪ endl ≪ flush;

} if (extremes [0] < min x proj ∨ extremes [1] > max x proj ∨ extremes [2] < min y proj ∨ extremes [3] >

max y proj ) { if (do warnings ≡ true) {

    cerr ≪  ␣  ␣  ≪  ␣    ␣       ␣    ␣      ␣   ␣    ␣

␣  ␣  ≪  ␣      ␣    ␣    ␣  ≪ flush;

}

(∗∗iter ).suppress output ( ); } } /∗ for ∗/ } /∗ End of group. ∗/ 596. [LDF 2003.05.16.] Sorting can be performed in different ways, depending on the sort value argument. This is explained in ⟨ Define comparison classes 498 ⟩.

[LDF 2002.09.18.] It’s necessary to make sure that sorting is only performed if elements is non-empty. It could be empty now, if the error handling code above has removed all of the elements because set extremes ( ) returned false for all of them. We can’t just return, because there might still be Labels on the Picture. ⟨ Define Picture functions 264 ⟩ +≡

if (elements .size( ) > 0) { if (sort value ≡ ) sort (elements .begin( ), elements .end ( ), Compare minimum z( )); else if (sort value ≡ ) sort (elements .begin( ), elements .end ( ), Compare maximum z( )); else if (sort value ≡ ) sort (elements .begin( ), elements .end ( ), Compare mean z( )); if ( ) {

if (sort value ≡  ) cout ≪ ␣   ␣     ␣     ␣  ;
else if (sort value ≡  ) cout ≪ ␣   ␣     ␣     ␣  ;
else if (sort value ≡  ) cout ≪ ␣   ␣      ␣     ␣  ;

for (iter = elements .begin( ); iter ≠ elements .end ( ); ^{++}iter ) {

cout ≪ ␣ ␣ ≪ (∗∗iter ).get minimum z ( ) ≪ endl ≪ ␣ ␣ ≪

(∗∗iter ).get maximum z ( ) ≪ endl ≪ ␣ ␣ ≪ (∗∗iter ).get mean z ( ) ≪ endl ≪ endl ; } cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ flush;

}

for (iter = elements .begin( ); iter ≠ elements .end ( ); ^{++}iter ) { (∗∗iter ).output ( ); (∗∗iter ).unsuppress output ( ); /∗ [LDF 2002.09.18.] With a different Focus or different limiting values for the projection, this Shape might be projectable, so we reset do output to true. If it can’t be projected the next time, suppress output ( ) will be invoked again. ∗/

} }

597. Output the labels. LDF Undated. It is necessary to output the labels last because they might otherwise be drawn over by fill ( ) or filldraw ( ) commands.

[LDF 2002.09.17.] I’m not bothering to sort the labels so that the ones behind can be hidden by the ones in front. Labels should all be visible and are not put into perspective, so they shouldn’t overlay one another.

[LDF 2002.04.25.] Added following conditional. Sometimes it’s irritating to have the labels when a Picture is copied and transformed, and both the original and the transformed versions are output. ⟨ Define Picture functions 264 ⟩ +≡

if (do labels ≡ true) {

for (vector⟨Label ∗⟩::iterator i = labels .begin( ); i ≠ labels .end ( ); ^{++}i) {

/∗ [LDF 2002.09.17.] Simplified the following code. Formerly, there was a conditional here that chose which version of Label ::output ( ) to call. I’ve removed the version without a Transform argument and invoke Transform ::is identity ( ) in Label ::output (const Focus &, const Transform &). [LDF 2002.04.25.] This applies transform to the Point Label ::pt . ∗/

(∗∗i).output (f, proj , factor , transform); }

} /∗ [LDF 2002.04.25.] Added following line. This fixes a bug. If I don’t reset transform to identity,

it will be applied again each time I output a Picture, which is not what I want. ∗/ transform.reset ( ); if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; }

§598  3DLDF-1.1.5.1  NO FOCUS ARGUMENT 165

598. No Focus argument. ⟨ Define Picture functions 264 ⟩ +≡

void Picture ::output (const unsigned short proj , real factor , const unsigned short sort value, const bool do warnings , const real min x proj , const real max x proj , const real min y proj , const real max y proj , const real min z proj , const real max z proj )

{

output (default focus , proj , factor , sort value, do warnings , min x proj , max x proj , min y proj ,

max y proj , min z proj , max z proj ); }

599. Focus.

600. Focus class definition. [LDF 2002.09.18.] Made Focus a class (it was formerly a struct). Added char axis data member. It indicates the axis to which position should be transformed to when it’s put in standard position. This determines which plane the image is projected onto. If axis ≡ (the default), the image is projected onto the x-y plane, if axis ≡ , the z-y plane, if , the x-z plane.

At this time, I’m not adding the routines that will do this, which will entail changing transform and possibly persp, I’m just adding axis . I must also add a function for changing axis without changing any of the other data members. TO DO: Add these routines!!

[LDF 2002.09.14.] Added Transform persp. It’s needed because I need to get the z value of the world coordinates after the transformation that puts the Focus into standard position, but before the perspective transformation is performed. This z value can be used in an algorithm for surfaces hiding. If this were not the case, I could combine the transformations, because matrix multiplication is associative (it is not, however, commutative, except with special matrices).

[LDF 2002.09.11.] Added class Focus and the following constructors: The default constructor with no arguments, the one with two Point arguments and a real argument , and the one with seven real arguments.

format Focus int

⟨ Define class Focus 600 ⟩ ≡

class Focus { Point position; Point direction; Point up; real distance; real angle; char axis ; Transform transform; Transform persp;

public: ⟨ Declare Focus functions 602 ⟩

};

This code is used in sections 633 and 634.

601. Constructors and setting functions. [LDF 2002.09.22.] TO DO: Check magnitude of direction − position and make sure it’s non-zero!!

[LDF 2002.10.13.] The effect of using an angle ≠ 0 is similar to that of rotating a camera about an axis through its aperture and perpendicular to the surface of the lens. Because this is possible, it is necessary to indicate the upward direction of a projection. The Point up does this. It is determined in the constructors and setting functions by the vector direction − position and angle. up is first set to (0, 1, 0) if axis ≡ or axis ≡ , or (1, 0, 0) if axis ≡ . If angle ≠ 0, up and transform are then rotated by −angle. Then, up is transformed by the inverse of transform, in order to put it in the correct location with respect to position. This location is “above” position by definition.

[LDF 2002.10.13.] Changed all of the constructors and setting functions except for the default constructor and the first non-default constructor. Now, all the others use the latter to create a Focus locally and use Focus ::operator=( ), which I’ve defined today, to assign to ∗this . This eases maintenance and cuts down on the potential for error through inconsistencies in the different constructors and setting functions.

602. Default constructor. (No arguments). ⟨ Declare Focus functions 602 ⟩ ≡

Focus( )

{ }

See also sections 604, 606, 609, 611, 613, 615, 617, 620, 621, 622, 623, 624, 625, 627, and 628. This code is used in section 600.

603. real arguments. The first three real arguments are for the coordinates of the center of projection (the focus in the narrowest sense) (position), the fourth through the sixth are for the coordinates of the direction of view (direction), dist is for the distance of position to the projection plane (distance), ang is for the angle of rotation around the axis \overrightarrow{pd} where p stands for position and d for direction (angle), and the char argument ax indicates the axis with which \overrightarrow{pd} is to be aligned, and around which up is to be rotated (axis ).

Log

[LDF 2003.07.04.] Now calling persp.set element ( ) instead of accessing the elements of persp directly. The latter is no longer possible, because Focus is no longer a friend of Transform.

604. Constructor. ⟨ Declare Focus functions 602 ⟩ +≡

Focus(const real pos x , const real pos y , const real pos z , const real dir x , const real dir y , const real dir z , const real dist , const real ang = 0, char ax = ); 605. ⟨ Define Focus functions 605 ⟩ ≡

Focus ::Focus(const real pos x , const real pos y , const real pos z , const real dir x , const real

dir y , const real dir z , const real dist , const real ang , char ax )

: distance(dist ), angle(ang ), axis (ax ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣       ␣   ␣    ␣  ≪ flush;

axis = tolower (axis );

if (axis ≠  ∧ axis ≠  ∧ axis ≠ ) {
cerr ≪  ␣  ␣        ␣  ␣    ␣  ≪

␣ ␣ ␣ ␣ ␣ ≪ axis ≪ ␣ ␣ ≪ flush; axis = ;

} position.set (pos x , pos y , pos z ); direction.set (dir x , dir y , dir z );

#if 0

transform.reset ( );

/∗ [LDF 2002.12.10.] This doesn’t seem to be necessary. I believe I added it while debugging. ∗/ #endif

if ( ) {

transform.show ( ␣ ␣ ); } transform.align with axis (position, direction, axis ); if ( ) {

transform.show (  ␣     ␣  );
cout ≪  ␣        ␣  ␣  ≪ flush;

} Transform unalign up = transform.inverse( ); /∗ Use the positive y-axis for the “up” direction,

if axis ≡ or , and the positive x-axis if axis ≡ . ∗/ if (axis ≡ ∨ axis ≡ ) up.set (0, 1, 0); else up.set (1, 0, 0); if (angle ≠ 0) {

if (axis ≡ ) up ∗= transform.rotate(0, 0, −angle);

else if (axis ≡ ) up ∗= transform.rotate(−angle);

else if (axis ≡ ) up ∗= transform.rotate(0, −angle);

else {

cerr ≪  ␣  ␣  ≪  ␣     ␣       ␣
␣    ␣   ␣       ␣      ␣ ≪ axis ≪ endl ≪  ␣      ␣  ≪
␣ ␣ ␣ ␣ ␣ ≪ flush;

up ∗= transform.rotate(0, 0, −angle); } if ( ) up.show ( ␣ ␣ );

} up ∗= unalign up; up.apply transform( ); transform.shift (0, 0, −distance); persp.set element (2, 2, 0); persp.set element (2, 3, 1/distance); if ( ) cout ≪ ␣ ␣ ␣ ␣ ≪ flush;

}

See also sections 607, 610, 612, 614, 616, 618, 626, and 629.

This code is used in section 633.

606. Setting function. [LDF 2002.09.17.] Added this function. ⟨ Declare Focus functions 602 ⟩ +≡

void set (const real pos x , const real pos y , const real pos z , const real dir x , const real dir y , const real dir z , const real dist , const real ang = 0.0, char ax = );

607. ⟨ Define Focus functions 605 ⟩ +≡

void Focus ::set (const real pos x , const real pos y , const real pos z , const real dir x , const real

dir y , const real dir z , const real dist , const real ang , char ax )

{ Focus f(pos x , pos y , pos z , dir x , dir y , dir z , dist , ang , ax ); ∗this = f;

}

608. Point arguments.

609. Constructor. ⟨ Declare Focus functions 602 ⟩ +≡

Focus(const Point &pos , const Point &dir , const real dist , const real ang = 0.0, char ax = );

610. ⟨ Define Focus functions 605 ⟩ +≡

Focus ::Focus(const Point &pos , const Point &dir , const real dist , const real ang , char ax )

{ Focus f(pos .get x ( ), pos .get y ( ), pos .get z ( ), dir .get x ( ), dir .get y ( ), dir .get z ( ), dist , ang , ax ); ∗this = f;

}

611. Setting function. [LDF 2002.09.17.] Added this function. ⟨ Declare Focus functions 602 ⟩ +≡

void set (const Point &pos , const Point &dir , const real dist , const real ang = 0.0, char ax = );

612. ⟨ Define Focus functions 605 ⟩ +≡

void Focus ::set (const Point &pos , const Point &dir , const real dist , const real ang , char ax ) {

Focus f(pos .get x ( ), pos .get y ( ), pos .get z ( ), dir .get x ( ), dir .get y ( ), dir .get z ( ), dist , ang , ax ); ∗this = f;

}

613. Assignment. [LDF 2002.10.13.] Added this function. Now using it in all but the first of the nondefault constructors. This saves on duplicating code and reduces the probability of bugs that might arise from inconsistencies among the constructors and setting functions. ⟨ Declare Focus functions 602 ⟩ +≡

§614  3DLDF-1.1.5.1  ASSIGNMENT 169

const Focus &operator=(const Focus &); 614. ⟨ Define Focus functions 605 ⟩ +≡

const Focus &Focus ::operator=(const Focus &f) {

if (this ≡ &f) /∗ [LDF 2002.10.13.] Prevent self-assignment. ∗/

return ∗this ; position = f.position; direction = f.direction; up = f.up; distance = f.distance; angle = f.angle; axis = f.axis ; transform = f.transform; persp = f.persp; return ∗this ;

}

615. Reset angle. [LDF 2002.10.12.] Added this function. ⟨ Declare Focus functions 602 ⟩ +≡

void reset angle(const real ang );

170  RESET ANGLE  3DLDF-1.1.5.1 §616

616. ⟨ Define Focus functions 605 ⟩ +≡

void Focus ::reset angle(const real ang ) {

angle = ang ; transform.reset ( ); persp.reset ( ); transform.align with axis (position, direction, axis ); Transform unalign up = transform.inverse( ); /∗ Use the positive y-axis for the “up” direction,

if axis ≡ or , and the positive x-axis if axis ≡ . ∗/ if (axis ≡ ∨ axis ≡ ) up.set (0, 1, 0); else up.set (1, 0, 0); if (angle ≠ 0) {

if (axis ≡ ) up ∗= transform.rotate(0, 0, −angle); else if (axis ≡ ) up ∗= transform.rotate(−angle); else if (axis ≡ ) up ∗= transform.rotate(0, −angle); else {

cerr ≪  ␣  ␣  ≪  ␣     ␣       ␣
␣    ␣   ␣       ␣      ␣ ≪ axis ≪ endl ≪  ␣      ␣  ≪
␣ ␣ ␣ ␣ ␣ ≪ flush;

up ∗= transform.rotate(0, 0, −angle); }

} up ∗= unalign up; up.apply transform( ); transform.shift (0, 0, −distance); persp.set element (2, 2, 0); persp.set element (2, 3, 1/distance);

}

617. Show.

Log

[LDF 2002.09.17.] Added this function. [LDF 2003.07.09.] Made the arguments const.

§618  3DLDF-1.1.5.1  SHOW 171

⟨ Declare Focus functions 602 ⟩ +≡ void show (const string text str = , const bool show transforms = false) const; 618. ⟨ Define Focus functions 605 ⟩ +≡

void Focus ::show (const string text str , const bool show transforms ) const {

cout ≪ text str ≪ endl ;

position.show ( );

direction.show ( );

up.show ( );

cout ≪ ␣ ␣ ≪ distance ≪ ␣ ≪ ␣ ␣ ≪ axis ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ angle ≪ endl ≪ flush; if (show transforms ≡ true) {

transform.show ( ); persp.show ( );

}

return; }

619. Returning elements and information. [LDF 2002.09.18.] Added this section. The functions in this section are now necessary, since I’ve made Focus a class (it was formerly a struct), and the data members private.

620. Get position.

Log

[LDF 2002.09.18.] Added this function.

⟨ Declare Focus functions 602 ⟩ +≡ inline const Point &get position( ) const {

return position; }

621. Get direction.

Log

[LDF 2003.07.09.] Added this function.

⟨ Declare Focus functions 602 ⟩ +≡ inline const Point &get direction( ) const {

return direction; }

622. Get distance. [LDF 2002.09.18.] Added this function. ⟨ Declare Focus functions 602 ⟩ +≡

inline const real &get distance( ) const {

return distance; }

623. Get up. [LDF 2002.09.18.] Added this function.

172  GET UP  3DLDF-1.1.5.1 §623

⟨ Declare Focus functions 602 ⟩ +≡ inline const Point &get up( ) const {

return up; }

624. Get transform.

Log

[LDF 2002.09.18.] Added this function.

⟨ Declare Focus functions 602 ⟩ +≡ inline const Transform &get transform( ) const {

return transform; }

625. Get transform element.

Log

[LDF 2002.09.18.] Added this function. [LDF 2003.07.04.] Made non-inline. It now calls Transform ::get element ( ) instead of accessing

transform.matrix directly. This is no longer possible, because Focus is no longer a friend of Transform. [LDF 2003.07.09.] Changed the const unsigned int arguments to const unsigned short.

⟨ Declare Focus functions 602 ⟩ +≡ real get transform element (const unsigned short row , const unsigned short column) const;

§626  3DLDF-1.1.5.1  GET TRANSFORM ELEMENT 173

626. ⟨ Define Focus functions 605 ⟩ +≡

real Focus ::get transform element (const unsigned short row , const unsigned short column) const {

return transform.get element (row , column); }

627. Get persp.

Log

[LDF 2002.09.18.] Added this function.

⟨ Declare Focus functions 602 ⟩ +≡ inline const Transform &get persp( ) const {

return persp; }

628. Get persp element.

Log

[LDF 2002.09.18.] Added this function. [LDF 2003.07.04.] Made non-inline. It now calls Transform ::get element ( ) instead of accessing

transform.matrix directly. This is no longer possible, because Focus is no longer a friend of Transform. [LDF 2003.07.09.] Changed the const unsigned int arguments to const unsigned short.

⟨ Declare Focus functions 602 ⟩ +≡ real get persp element (const unsigned short row , const unsigned short column) const;

629. ⟨ Define Focus functions 605 ⟩ +≡

real Focus ::get persp element (const unsigned short row , const unsigned short column) const {

return persp.get element (row , column); }

630. Global variables. [LDF 2002.12.08.] !! BUG. Commented-out, because of a bug involving transformations.

Default value. Can be changed. ⟨ Global variables 18 ⟩ +≡

Focus default focus (0, 10, −10, 0, 10, 0, 10); 631. ⟨ Declarations for the header file 21 ⟩ +≡

extern Focus default focus ;

632. Putting Point and Focus together.

633. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define class Point 309 ⟩ ⟨ Declare non-member template functions for Point 336 ⟩ ⟨ Define Point constructors 325 ⟩ ⟨ Define class Focus 600 ⟩ ⟨ Define comparison classes 498 ⟩ ⟨ Define static Point data members 310 ⟩ ⟨ Type definitions 15 ⟩ ⟨ Global constants 22 ⟩ ⟨ Global variables 18 ⟩ ⟨ Define Transform functions 169 ⟩ ⟨ Define Point functions 330 ⟩ ⟨ Define non-member non-template functions for Point 481 ⟩ ⟨ Define bool point functions 314 ⟩ ⟨ Define bool point quadruple functions 316 ⟩ ⟨ Define bool real point functions 318 ⟩ ⟨ Define Focus functions 605 ⟩ ⟨ Define Label functions 514 ⟩ ⟨ Define Picture functions 264 ⟩

634. This is what’s written to points.h. ⟨ 634 ⟩ ≡

⟨ Define class Point 309 ⟩ ⟨ Define class Focus 600 ⟩ ⟨ Define comparison classes 498 ⟩ ⟨ Declare non-member template functions for Point 336 ⟩ ⟨ Declare non-member non-template functions for Point 480 ⟩ ⟨ Type definitions 15 ⟩ ⟨ Declarations for the header file 21 ⟩

635. Line (lines.web). [LDF 2002.10.29.] Lines are not Shapes. They are used for performing vector operations. A Line is defined by a Point representing a position vector and a Point representing a direction vector.

[LDF 2003.06.03.] TO DO: Add setting functions.

Log

[LDF 2002.04.08.] Added this section. [LDF 2002.04.12.] Created this file. Removed the code for Line from points.web and put it here.

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

§635  3DLDF-1.1.5.1  LINE (LINES.WEB) 175

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

636. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include #include #include

637. Line struct definition.

format Line Point

⟨ Define struct Line 637 ⟩ ≡ struct Line { public: Point position;

Point direction;

⟨ Declare Line constructors 639 ⟩ ⟨ Declare Line functions 643 ⟩

};

This code is used in sections 657 and 658.

638. Constructors. [LDF 2002.10.29.] The constructors and assignment operator take Point arguments for position and direction. If you want to get the Line between two Points, use Point ::get line( ).

Log

[LDF 2002.04.12.] It took me a while to figure out why I was having problems with Lines. The constructor was making the opposite assumption, namely, that it was supposed to calculate the Line from its arguments, rather than just taking them as they were. This caused a problem in Plane ::intersection line( ).

639. Default constructor. This constructor takes two optional Point arguments. The default for the Point arguments is origin. ⟨ Declare Line constructors 639 ⟩ ≡

Line(const Point &pos = origin, const Point &dir = origin);

See also section 641. This code is used in section 637.

640. ⟨ Define Line constructors 640 ⟩ ≡

Line ::Line(const Point &pos , const Point &dir )

: position(pos ), direction(dir ) { position.apply transform( ); direction.apply transform( );

}

See also section 642. This code is used in section 657.

641. Copy constructor. [LDF 2002.10.29.] Calling apply transform( ) on position and direction is probably unnecessary, because it will already have been called on l.position and l.direction when l was declared or assigned to. But maybe some function has affected l.position.transform or l.direction.transform, so I’m doing it just to be sure. ⟨ Declare Line constructors 639 ⟩ +≡

Line(const Line &l);

642. ⟨ Define Line constructors 640 ⟩ +≡

Line ::Line(const Line &l)

: position(l.position), direction(l.direction) { position.apply transform( ); direction.apply transform( );

}

643. Assignment. ⟨ Declare Line functions 643 ⟩ ≡

void operator=(const Line &l);

See also sections 646, 648, and 652. This code is used in section 637.

644. ⟨ Define Line functions 644 ⟩ ≡

void Line ::operator=(const Line &l)

{ position = l.position; direction = l.direction;

}

See also sections 649, 650, 651, 653, and 978. This code is used in sections 657 and 980.

645. Get Line. (Point function). LDF Undated. Declared in points.web. Must be defined here, because Line is an incomplete type there.

[LDF 2003.06.06.] get line( ) returns a Line l corresponding to the line from ∗this to p, where l.position is a Point on the Line, and l.direction is a direction vector. l.position will be ∗this , and l.direction will be pt − ∗this .

Log

[LDF 2003.06.06.] BUG FIX: Changed the call to Line( ), so that the argument for direction is pt − ∗this instead of pt .

⟨ Define Point functions 330 ⟩ +≡ Line Point ::get line(const Point &pt ) const {

Line l(∗this , (pt − ∗this )); return l;

}

646. Get Path. [LDF 2003.06.06.] Returns a linear Path consisting of two Points, and corresponding to the Line. Must be defined in paths.web, because Path is an incomplete type here.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Line functions 643 ⟩ +≡ Path get path(void) const;

647. Intersection. [LDF 2003.06.06.] Commented-out. This function doesn’t work. Using a different version, that finds the intersection points of the traces of the lines on two or all of the major axes. TO DO: Fix it!

LDF Undated. Declared in points.web, but must be defined here, because Line is an incomplete type in

points.web.

Log

[LDF 2002.04.12.] Moved this function definition here from points.web because it requires the use of Lines, and Line is an incomplete type there.

[LDF 2002.04.15.] Commented-out, because I’m having problems with it. Commented old version in points.web back in. I don’t quite understand this, because it seemed to be working.

[LDF 2002.04.22.] Changed return value to bool point, to correspond with the old version. This facilitates testing, since all I have to do is to comment-out whichever version I don’t want to use, and uncomment-out the other one. Made a few changes in the function definition in order to be able to return a bool point.

178  INTERSECTION  3DLDF-1.1.5.1 §647

⟨ Define Point functions 330 ⟩ +≡ #if 1 /∗ 0 ∗/

bool point Point ::intersection point (const Point &pp0 , const Point &pp1 , const Point

&qq0 , const Point &qq1 )

{ /∗ START HERE. DEBUGGING. [LDF 2003.06.24.] ∗/

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

Line l p = pp0 .get line(pp1 ); Line l q = qq0 .get line(qq1 ); if ( ) {

pp0 .show ( );

pp1 .show ( );

qq0 .show ( );

qq1 .show ( );

l p.show ( );

l q .show ( ); } bool real point brp = l p.get distance(l q ); if ( ) {

cout ≪ ␣ ␣ ≪ brp.b ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ brp.r ≪ endl ≪ flush;

brp.pt .show ( ); } if (brp.r ≠ 0 ∨ brp.b ≡ false ∨ brp.pt ≡ ) return ; bool point bp; bp.pt = brp.pt ; bool real br p = brp.pt .is on segment (pp0 , pp1 ); bool real br q = brp.pt .is on segment (qq0 , qq1 ); if ( ) {

cout ≪ ␣ ␣ ≪ br p.first ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ br p.second ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ br q .first ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ br q .second ≪ endl ≪ flush;

} bp.b = (br p.first ∧ br q .first ); if ( ) cout ≪ ␣ ; return bp;

} #endif

648. Get distance. [LDF 2002.04.22.] Renamed this get distance( ) from intersection point ( ). The old version of Point ::intersection point ( ), which I am currently using again, since the new version wasn’t working, returns a bool point, which is sensible. If I start using the commented-out version above again, I should have it return a bool point too, instead of a bool real point. This will make it easier to switch back to the old version, if I have problems again.

[LDF 2003.06.11.] START HERE. TO DO: get distance( ) may be working now, due to changes I’ve made to Line elsewhere. Read this through and see how it works. Then test. Also, check where it’s used. [LDF 2003.06.03.] When I’ve fixed it, add description to line.texi.

§648  3DLDF-1.1.5.1  GET DISTANCE 179

Log

[LDF 2002.04.10.] Added this function.

⟨ Declare Line functions 643 ⟩ +≡ bool real point get distance(const Line &l) const;

649. ⟨ Define Line functions 644 ⟩ +≡

bool real point Line ::get distance(const Line &l) const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

bool real point brp; Point normal = direction.cross product (l.direction); if ( ) normal .show ( ␣ ␣ ␣ ); Point normal unit = normal .unit vector ( ); if ( ) normal unit .show ( ); if (normal unit ≡ origin) {

if ( ) cout ≪ ␣ ␣ ≪ flush;

brp.b = false; /∗ No intersection. ∗/

brp.pt = ;

Point temp pt (l.position);

temp pt −= position;

temp pt = temp pt .cross product (direction);

brp.r = temp pt .magnitude( )/direction.magnitude( ); /∗ [LDF 2002.10.29.] Distance. ∗/ if ( ) {

cout ≪ ␣ ␣ ≪ brp.r ≪ endl ≪ flush; } if ( ) cout ≪ ␣ ; return brp;

} else { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; brp.r = fabs ((l.position − position).dot product (normal unit ));

if (  ) cout ≪  ␣  ␣ ≪ brp.r ≪ endl ≪ flush;

180  GET DISTANCE  3DLDF-1.1.5.1 §650

650. Lines have an intersection.

Log

[LDF 2003.08.27.] Commented-out the declarations of v x , v y , and v z , since they are not used. I haven’t deleted them, in case I need them someday.

⟨ Define Line functions 644 ⟩ +≡

if (brp.r < Point ::epsilon( )) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; brp.r = 0; brp.b = true; real a x = position.get x ( ); real a y = position.get y ( ); real a z = position.get z ( ); real b x = l.position.get x ( ); real b y = l.position.get y ( ); real b z = l.position.get z ( );

#if 0 real v x = direction.get x ( ); real v y = direction.get y ( ); real v z = direction.get z ( );

#endif real w x = l.direction.get x ( ); real w y = l.direction.get y ( ); real w z = l.direction.get z ( ); real u x = normal .get x ( ); real u y = normal .get y ( ); real u z = normal .get z ( ); real t; if (u z ≠ 0) {

if ( ) cout ≪ ␣ ␣ ␣ ␣ ;

t = (((b x − a x ) ∗ w y ) − ((b y − a y ) ∗ w x ))/u z ; } else if (u x ≠ 0) {

if ( ) cout ≪ ␣ ␣ ␣ ␣ ;

t = (((b y − a y ) ∗ w z ) − ((b z − a z ) ∗ w y ))/u x ; } else if (u y ≠ 0) {

if ( ) cout ≪ ␣ ␣ ␣ ␣ ;

t = (((b z − a z ) ∗ w x ) − ((b x − a x ) ∗ w z ))/u y ; } else {

cerr ≪  ␣     ␣  ≪  ␣  ≪

      ␣  ␣       ␣␣     ␣    ␣      ␣     ␣    ␣ ≪
      ␣      ␣  ␣         ␣  ␣      ␣  ≪

␣ ≪ flush;

return ; } if ( ) cout ≪ ␣ ␣ ≪ t ≪ endl ≪ flush; brp.pt = direction; brp.pt ∗= t; brp.pt += position; if ( ) {

brp.pt .show ( ␣ ); } if ( ) cout ≪ ␣ ; return brp;

}

651. Lines are not parallel, but do not intersect. ⟨ Define Line functions 644 ⟩ +≡

else { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ flush; brp.b = false; brp.pt = ; if ( ) cout ≪ ␣ ; return brp;

} } }

652. Show. ⟨ Declare Line functions 643 ⟩ +≡

void show (string text = );

653. ⟨ Define Line functions 644 ⟩ +≡

void Line ::show (string text ) {

if (text ≡ ) cout ≪ ;

else cout ≪ text ≪ endl ;

position.show ( );

direction.show ( ); }

654. Global constants for Line. ⟨ Line global constants 654 ⟩ ≡

extern const Line  (  ,  );

This code is used in section 657.

655. ⟨ Declarations for the header file 21 ⟩ +≡

extern const Line ;

656. Putting Line together.

657. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define struct Line 637 ⟩ ⟨ Define Line constructors 640 ⟩ ⟨ Line global constants 654 ⟩ ⟨ Define Line functions 644 ⟩ ⟨ Define Point functions 330 ⟩

182  PUTTING LINE TOGETHER  3DLDF-1.1.5.1 §658

658. This is what’s written to lines.h. ⟨ 658 ⟩ ≡

⟨ Define struct Line 637 ⟩

⟨ Declarations for the header file 21 ⟩

659. Plane (planes.web). [LDF 2002.10.29.] Planes are not Shapes. They are used for performing vector operations. A Plane is defined by a Point representing a point on the plane, a Point representing the normal to the plane, and the distance of the plane from the origin.

Log

[LDF 2002.04.12.] Created this file. Removed the code for Plane from points.web and put it here.

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

660. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include #include #include #include

661. Plane struct definition.

format Plane Line

⟨ Define struct Plane 661 ⟩ ≡ struct Plane { public: Point normal ;

Point point ; real distance; ⟨ Declare Plane functions 663 ⟩

};

This code is used in sections 694 and 695.

662. Constructors.

663. Default constructor. [LDF 2003.06.06.] Creates a degenerate Plane with point ≡normal ≡origin, and distance≡0. I could have made the Plane be equal to , but there’s probably no reason for doing so. A Plane constructed using this constructor will probably be set using the assignment operator or Path ::get plane( ) immediately, or very soon after being declared.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Plane functions 663 ⟩ ≡

Plane(void);

See also sections 665, 667, 669, 672, 674, 677, 679, 684, 686, 687, and 689. This code is used in section 661.

664. ⟨ Define Plane functions 664 ⟩ ≡

Plane ::Plane(void) {

normal = point = origin; distance = 0;

}

See also sections 666, 668, 670, 673, 675, 678, 680, 685, 688, 690, and 966. This code is used in sections 694 and 980.

665. Copy constructor.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ Plane(const Plane &p); 666. ⟨ Define Plane functions 664 ⟩ +≡

Plane ::Plane(const Plane &p)

{ ∗this = p; return;

}

667. Point arguments.

Log

[LDF 2003.06.03.] Changed this function. BUG FIX: distance is now calculated, instead of being passed as an argument. normal is now made a unit vector.

[LDF 2003.06.06.] Changed, so that if point or normal is equal to , the other one is also set to , and distance is set to .

[LDF 2003.06.06.] Arguments are no longer optional. I’ve made this change, because I’ve added a default constructor.

[LDF 2003.06.06.] Added conditional to test for case that point ≡normal . In this case, a warning message is printed to standard error, they are both set to , and distance is set to .

[LDF 2003.06.24.] BUG FIX: Formerly, was returned, if point ≡ normal . This has been changed, so that is returned, if normal ≡ origin. There is, of course, no reason why point shouldn’t be equal to normal .

⟨ Declare Plane functions 663 ⟩ +≡ Plane(const Point &p, const Point &n); 668. ⟨ Define Plane functions 664 ⟩ +≡

Plane ::Plane(const Point &p, const Point &n) : normal (n), point (p) {

point .apply transform( ); normal .apply transform( ); if (point ≡ ) {

normal = ;

distance = ;

return; } else if (normal ≡ ) {

point = ;

distance = ;

return; } else if (normal ≡ origin) {

  cerr ≪  ␣  ␣                ␣  ␣        ␣ ≪  ␣  ␣  ≪

flush; point = ; distance = ; return;

} normal .unit vector (true); distance = −point .dot product (normal ); if (fabs (distance) < Point ::epsilon( )) distance = 0; return;

}

669. Assignment.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ const Plane &operator=(const Plane &p);

186  ASSIGNMENT  3DLDF-1.1.5.1 §670

670. ⟨ Define Plane functions 664 ⟩ +≡

const Plane &Plane ::operator=(const Plane &p) {

if (this ≡ &p) /∗ Make sure it’s not self-assignment. [LDF 2003.06.06.] ∗/

return ∗this ; point = p.point ; normal = p.normal ; distance = p.distance; return p;

}

671. Comparing Planes.

Log

[LDF 2003.06.06.] Added this section.

672. Equality.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ bool operator≡(const Plane &p) const;

673. ⟨ Define Plane functions 664 ⟩ +≡

bool Plane ::operator≡(const Plane &p) const {

return ((point ≡ p.point ) ∧ (normal ≡ p.normal ) ∧ (distance ≡ p.distance)); }

674. Inequality.

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ bool operator≠(const Plane &p) const; 675. ⟨ Define Plane functions 664 ⟩ +≡

bool Plane ::operator≠(const Plane &p) const

{

return ¬(operator≡(p)); }

676. Get distance.

677. Point argument. [LDF 2003.06.03.] This function returns a real short r, where r.first is the distance of the Point from the Plane. r.first is always positive. r.second can take on the following values: 0 If the Point lies in the Plane. 1 If it lies on the side of the Plane pointed at by the normal to the Plane, considered to be the “outside”. -1 If it lies on the side of the Plane not pointed at by the normal to the Plane, considered to be the “inside”.

Log

[LDF 2003.06.03.] Changed the definition of this function. The old definition was incorrect. Also changed return type from real to real short.

[LDF 2003.06.04.] BUG FIX: In the case that r fabs < Point ::epsilon( ), now r fabs is set to 0. Previously, r was, which was wrong, because r fabs is returned, not r. Also, I now set r fabs and s to 0 separately, because they are of different types. I don’t believe any compiler would have trouble with this, but I think it’s cleaner if they are assigned to separately.

⟨ Declare Plane functions 663 ⟩ +≡ real short get distance(const Point &p) const;

678. ⟨ Define Plane functions 664 ⟩ +≡

real short Plane ::get distance(const Point &p) const

{ real r = (p − point ).dot product (normal ); real r fabs = fabs (r); signed short s; if (r fabs < Point ::epsilon( )) {

r fabs = 0; s = 0;

}

else s = static cast⟨signed short⟩(r/r fabs ); return real short(r fabs , s);

}

679. No argument. [LDF 2003.06.03.] This version of get distance( ) returns the data member distance and its sign, i.e., the distance of origin to the Plane, and which side of the Plane it lies on. I’m not using origin as the default for an optional Point argument, because of problems that may arise, when I implement user coordinates and view coordinates .

Log

[LDF 2003.06.03.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ real short get distance(void) const;

188  NO ARGUMENT  3DLDF-1.1.5.1 §680

680. ⟨ Define Plane functions 664 ⟩ +≡

real short Plane ::get distance(void) const

{ real f = fabs (distance); signed short s = static cast⟨signed short⟩(distance/f); return real short(f, s);

}

681. Point is on Plane. [LDF 2003.06.04.] This function returns true, if the Point lies on the Plane p, otherwise false. Declared in points.web. Must be defined here, because Plane is an incomplete type in that file.

Log

[LDF 2003.06.04.] Added this function.

⟨ Define Point functions 330 ⟩ +≡ bool Point ::is on plane(const Plane &p) const {

if (p.get distance(∗this ).second ≡ 0) return true;

else return false; }

682. Intersection.

683. Intersection with a line.

684. Point arguments.

Log

[LDF 2003.06.03.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ bool point intersection point (const Point &p0 , const Point &p1 ) const; 685. ⟨ Define Plane functions 664 ⟩ +≡

bool point Plane ::intersection point (const Point &p0 , const Point &p1 ) const {

bool point bp; real denominator = (p0 − p1 ).dot product (normal ); if (denominator ≡ 0) /∗ !! TO DO: Handle cases: Path is in Plane, and Path is in a parallel

Plane. [LDF 2003.06.03.] ∗/ {

cerr ≪  ␣  ␣                               ␣       ␣     ␣  ≪

      ␣  ␣  ␣␣      ␣       ␣ ≪  ␣  ␣      ␣  ␣      ␣  ␣        ␣

␣  ≪ endl ≪  ␣          ␣      ␣     ␣  ≪ endl ≪

␣ ≪ endl ≪ endl ≪ flush; return ;

} real numerator = p0 .dot product (normal ) + distance; bp.pt = p0 + ((numerator /denominator ) ∗ (p1 − p0 )); bp.b = (bp.pt ≠ ) ? true : false; return bp;

}

686. Path argument. [LDF 2003.06.03.] Defined in paths.web, because Path is an incomplete type in this file.

Log

[LDF 2003.06.03.] Added this function.

⟨ Declare Plane functions 663 ⟩ +≡ bool point intersection point (const Path &p) const;

687. Intersection of two Planes. [LDF 2002.10.29.] TO DO: Look up and explain!

Log

[LDF 2003.06.04.] Changed to const.

⟨ Declare Plane functions 663 ⟩ +≡ Line intersection line(const Plane &pl ) const;

190  INTERSECTION OF TWO PLANES  3DLDF-1.1.5.1 §688

688. ⟨ Define Plane functions 664 ⟩ +≡

Line Plane ::intersection line(const Plane &pl ) const {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

Point pl normal (pl .normal ); Point direction vector = normal .cross product (pl normal ); /∗ [LDF 2002.10.29.] Needed?? ∗/ if ( ) direction vector .show ( ); if (direction vector ≡ origin) {

cerr ≪ ␣ ≪ ␣ ␣ ; if (distance ≡ pl .distance) {

/∗ Ellipse ::intersection points (Ellipse &) calls this function to find out whether two Planes are coincident, so sometimes we don’t want to see these messages. I may decide to add an argument bool silent to this function. ?? Add bool silent ?? ∗/

    cerr ≪  ␣   ␣  ≪  ␣    ␣     ␣      ␣  ␣        ␣  ≪

␣ ␣ ␣ ≪ flush; return ;

}

else { cerr ≪ ␣ ␣ ␣ ≪ ␣ ≪ flush; return ;

} } /∗ Outer if . ∗/ if ( ) cout ≪ ␣ ␣ ␣ ≪ flush;

/∗ At least one of the x, y, or z components of direction vector must be non-zero, otherwise, this

function would have exited by now. ∗/ real x, y, z; real d = distance; real e = pl .distance; real nx = normal .get x ( ); real ny = normal .get y ( ); real nz = normal .get z ( ); real mx = pl .normal .get x ( ); real my = pl .normal .get y ( ); real mz = pl .normal .get z ( ); real vx = direction vector .get x ( ); real vy = direction vector .get y ( ); real vz = direction vector .get z ( ); if (direction vector .get x ( ) ≠ 0) {

x = 0;

y = −1 ∗ ((d ∗ mz − e ∗ nz )/vx );

z = (d ∗ my − e ∗ ny )/vx ; } else if (direction vector .get y ( ) ≠ 0) {

x = (d ∗ mz − e ∗ nz )/vy ;

y = 0;

z = −1 ∗ ((d ∗ mx − e ∗ nx )/vy ); } else {

x = −1 ∗ ((d ∗ my − e ∗ ny )/vz );

§688  3DLDF-1.1.5.1  INTERSECTION OF TWO PLANES 191

y = (d ∗ mx − e ∗ nx )/vz ;

z = 0; } Point point on line(x, y, z); if ( ) {

point on line.show ( );

direction vector .show ( );

getchar ( ); } if ( ) {

cout ≪ ␣ ;

getchar ( ); } return Line(point on line, direction vector );

}

689. Show.

Log

[LDF 2003.06.06.] Minor change to the conditional that handles text . [LDF 2003.06.06.] Made show ( ) const.

⟨ Declare Plane functions 663 ⟩ +≡ void show (string text = ) const;

690. ⟨ Define Plane functions 664 ⟩ +≡

void Plane ::show (string text ) const {

if (text ≡ ) text = ; cout ≪ text ≪ endl ; if (∗this ≡ ) {

cout ≪ ␣ ␣ ≪ endl ≪ endl ≪ flush; return;

} normal .show ( ); point .show ( ); cout ≪ ␣ ␣ ≪ distance ≪ endl ≪ endl ≪ flush;

}

691. Global constants for Plane. ⟨ Plane global constants 691 ⟩ ≡

extern const Plane  (  ,  );

This code is used in section 694.

692. ⟨ Declarations for the header file 21 ⟩ +≡

extern const Plane ;

693. Putting Plane together.

192  PUTTING PLANE TOGETHER  3DLDF-1.1.5.1 §694

694. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define struct Plane 661 ⟩ ⟨ Plane global constants 691 ⟩ ⟨ Define Plane functions 664 ⟩ ⟨ Define Point functions 330 ⟩

§695  3DLDF-1.1.5.1  PUTTING PLANE TOGETHER 193

695. This is what’s written to planes.h. ⟨ 695 ⟩ ≡

⟨ Define struct Plane 661 ⟩

⟨ Declarations for the header file 21 ⟩

696. Path (paths.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

format Path Shape

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

697. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include #include #include #include #include #include

698. Path class definition.

Log

[LDF 2002.09.18.] Added projective extremes . It contains the minimum and maximum values for x, y, and z of the Points in points . It’s used in Picture ::output ( ) for surface hiding.

[LDF 2002.4.8.] Added static variables for help lines and curves: help color , help dash pattern, do help lines . The variables for help lines (or curves) are part of Path’s interface and can be set anywhere by anyone.

⟨ Define class Path 698 ⟩ ≡ class Path : protected Shape { protected: bool line switch;

bool cycle switch; bool on free store; bool do output ; /∗ LDF 2002.09.18. Added. ∗/ signed short fill draw value; /∗ Variables for drawing and filling. ∗/ const Color ∗draw color ; const Color ∗fill color ; string dashed ;

194 PATH CLASS DEFINITION 3DLDF-1.1.5.1 §698

string pen;

bool arrow ; /∗ LDF 2003.01.15. Added. Needed for drawarrow ( ). ∗/ valarray⟨real⟩ projective extremes ; /∗ LDF 2002.09.18. Added. ∗/ vector⟨Point ∗⟩ points ; vector⟨string⟩ connectors ;

public: static const Color ∗help color ; static string help dash pattern; static bool do help lines ; ⟨ Declare Path functions 700 ⟩

};

This code is used in sections 980 and 981.

699. Static member variable definitions. ⟨ Define static class Path data members 699 ⟩ ≡

const Color ∗Path ::help color = &Colors ::red ;

string Path ::help dash pattern = ;

bool Path ::do help lines = true;

This code is used in section 980.

700. Assignment.

Log

[LDF 2002.10.23.] Now all of the data members of class Path are assigned to except for on free store. This has become necessary because of changes in Solid ::output ( ), where temporary Paths have to be created in order to sort them.

[LDF 2002.12.18.] Moved here. With the DEC compiler under Compaq Tru64 on the DEC Alpha computer, it worked to have this following the constructors. With the GNU C^{++} compiler (GCC) under GNU/Linux on the Intel i686 computer, it didn’t: The copy constructor used the default assignment operator instead of this function, presumably because this function wasn’t known at the time the copy constructor was compiled, although it had been declared previously! URGENT: Move assignment operators for the other classes before the constructors!

[LDF 2003.04.09.] ?? BUG FIX: Now resizing projective extremes , if after setting it to p.projective extremes , projective extremes .size( ) ≡ 0. This prevents a Memory Fault error at run-time. I don’t know why it should be necessary, though, since all of the constructors of Path and its derived classes resize projective extremes ; at least, I thought they did.

⟨ Declare Path functions 700 ⟩ ≡

virtual Path &operator=(const Path &p);

See also sections 704, 707, 709, 712, 714, 717, 719, 721, 726, 728, 730, 732, 735, 738, 740, 743, 745, 747, 749, 751, 756, 762, 764, 766, 768, 771, 773, 776, 778, 781, 783, 785, 790, 792, 794, 797, 799, 801, 805, 810, 812, 818, 820, 827, 829, 836, 838, 844, 846, 849, 851, 855, 857, 863, 866, 868, 872, 874, 877, 879, 882, 884, 888, 889, 891, 893, 895, 897, 899, 909, 911, 914, 916, 918, 920, 921, 922, 923, 925, 932, 934, 936, 938, 940, 946, 952, 955, 959, 961, 964, and 976.

This code is used in section 698.

701. ⟨ Define Path functions 701 ⟩ ≡

Path &Path ::operator=(const Path &p){

if (this ≡ &p) /∗ Make sure it’s not self-assignment. ∗/

return ∗this ; ⟨ Discard points and connectors 703 ⟩ line switch = p.line switch; cycle switch = p.cycle switch; do output = p.do output ; fill draw value = p.fill draw value; draw color = p.draw color ; /∗ [LDF 2002.10.23.] draw color and fill color point to the same

Color as p.draw color and p.fill color . No memory allocation is performed. ∗/ fill color = p.fill color ; dashed = p.dashed ; pen = p.pen; projective extremes = p.projective extremes ; /∗ LDF 2002.09.18. Added this line. ∗/ if (projective extremes .size( ) ≡ 0) /∗ LDF 2003.04.09. Added this conditional. ∗/

projective extremes .resize(6, 0); for (vector⟨Point ∗⟩::const iterator p iter = p.points .begin( ); p iter ≠ p.points .end ( ); p iter^{++})

points .push back ( create new < Point > (∗p iter ) ) ; for (vector⟨string⟩::const iterator c iter = p.connectors .begin( ); c iter ≠ p.connectors .end ( );

c iter^{++}) { connectors .push back (∗c iter );

} return ∗this ; }

See also sections 705, 708, 710, 713, 715, 718, 720, 722, 727, 729, 731, 733, 736, 739, 741, 744, 746, 748, 750, 752, 757, 763, 765, 767, 769, 772, 774, 777, 779, 782, 784, 786, 791, 793, 795, 798, 800, 802, 806, 807, 808, 809, 811, 813, 814, 819, 821, 828, 830, 837, 839, 845, 847, 850, 852, 856, 858, 864, 867, 869, 873, 875, 878, 880, 883, 885, 886, 887, 890, 892, 894, 896, 898, 900, 901, 902, 903, 904, 905, 906, 910, 912, 915, 917, 919, 924, 926, 927, 928, 929, 930, 933, 935, 937, 941, 942, 943, 944, 947, 953, 956, 957, 958, 960, 962, 965, and 977.

This code is used in section 980.

702. Constructors and setting functions. Each constructor taking an argument has a corresponding function for setting an already existing Path.

Log

[LDF 2003.04.06.] BUG FIX: Now setting dashed = , pen = , and arrow = false in all constructors and setting functions. This fixed a problem I was having with Icosahedron: One of the Reg Polygons was drawn with an arrow.

703. Discard points and connectors. This is useful in the setting functions. ⟨ Discard points and connectors 703 ⟩ ≡

if (points .size( ) > 0) {

for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); ^{++}iter ) {

delete ∗iter ; } points .clear ( );

} if (connectors .size( ) > 0) connectors .clear ( );

This code is used in sections 701, 710, 715, 720, and 729.

704. Default constructor. No arguments. ⟨ Declare Path functions 700 ⟩ +≡

Path( );

705. ⟨ Define Path functions 701 ⟩ +≡

Path ::Path( ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣      ␣        ␣  ≪ flush;

on free store = false; line switch = false; cycle switch = false; fill draw value = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; draw color = 0; fill color = 0; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ projective extremes .resize(6, 0); /∗ LDF 2002.09.18. Added this line. ∗/ if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; return;

}

706. Lines. [LDF 2002.10.15.] Lines in this sense are Paths containing two Points and the connector “^{−}” They should not be confused with the struct Line, which is for vector operations (where the word “vector” is used in its mathematical sense).

707. Constructor. ⟨ Declare Path functions 700 ⟩ +≡

Path(const Point &p0 , const Point &p1 ); 708. ⟨ Define Path functions 701 ⟩ +≡

Path ::Path(const Point &p0 , const Point &p1 ){ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣      ␣      ␣  ≪ flush;

on free store = false; line switch = true; cycle switch = false; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ projective extremes .resize(6, 0); /∗ LDF 2002.09.18. Added this line. ∗/ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; points .push back ( create new < Point > (p0 ) ) ; points .push back ( create new <

Point > (p1 ) ) ; connectors .push back ( ); if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; return; }

709. Setting function. ⟨ Declare Path functions 700 ⟩ +≡

void set (const Point &p0 , const Point &p1 );

710. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set (const Point &p0 , const Point &p1 ){ line switch = true; cycle switch = false; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; ⟨ Discard points and connectors 703 ⟩ projective extremes = 0; /∗ LDF 2002.09.18. Added this line. ∗/ points .push back ( create new < Point > (p0 ) ) ; points .push back ( create new < Point > (p1 ) ) ; connectors .push back ( ); line switch = true; }

711. Points and one type of connector. This constructor takes a variable number of Point ∗ arguments, but only allows one type of connector. The argument list must end with 0. If the order of the named arguments is reversed, the compiler can’t resolve certain calls to Path( ). It couldn’t resolve between Path(bool cycle, stringconnector …) and Path ( Point ∗first point ptr …). I don’t know why it should have had trouble, though, since pointers to Points are not bools.

[LDF 2002.4.6.] Probably it couldn’t distinguish between a pointer and an int on the one hand and a bool and an int on the other. I hope that bools are more efficiently implemented than as ints , though!

[LDF 2002.10.29.] ?? I don’t know why cweave needs instructions to put thin spaces after the “bool” in the declaration and definition below. Maybe it’s because of the “…”.

712. Constructor. ⟨ Declare Path functions 700 ⟩ +≡

Path(string connector , bool cycle …);

713. ⟨ Define Path functions 701 ⟩ +≡

Path ::Path(string connector , bool cycle …){ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣      ␣           ␣      ␣  ≪ flush;

on free store = false; line switch = false; cycle switch = cycle; connectors .push back (connector ); do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ projective extremes .resize(6, 0); /∗ LDF 2002.09.18. Added this line. ∗/ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; va list ap; /∗ For the variable length argument list. ∗/ va start (ap, cycle); Point ∗arg ptr ; while ((arg ptr = va arg (ap, Point ∗)) ≠ static cast⟨Point ∗⟩(0))

points .push back ( create new < Point > (arg ptr ) ) ; va end (ap); if ( ) cout ≪ ␣ ␣ ␣ ␣ ≪ flush; return; }

714. Setting function. ⟨ Declare Path functions 700 ⟩ +≡

void set (string connector , bool cycle …); 715. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set (string connector , bool cycle …){ on free store = false; line switch = false; cycle switch = cycle; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ ⟨ Discard points and connectors 703 ⟩ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; projective extremes = 0; /∗ LDF 2002.09.18. Added this line. ∗/ connectors .push back (connector ); va list ap; /∗ For the variable length argument list. ∗/ va start (ap, cycle); Point ∗arg ptr ; while ((arg ptr = va arg (ap, Point ∗)) ≠ static cast⟨Point ∗⟩(0))

points .push back ( create new < Point > (arg ptr ) ) ; va end (ap); }

716. Variable number of Points and connectors. These functions takes a variable number of alternating Point ∗ and connector arguments, starting with a Point ∗. The argument list must end with 0. We don’t need an argument for whether it’s a cycle or not, because if it is, it will have a connector at the end.

Log

[LDF 2002.10.29.] BUG FIX: No longer pushing first point ptr onto points . Copying it instead.

717. Constructor. ⟨ Declare Path functions 700 ⟩ +≡

Path ( Point ∗first point ptr …) ; 718. ⟨ Define Path functions 701 ⟩ +≡

Path ::Path ( Point ∗first point ptr …) { bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣      ␣        ␣  ≪ flush;

on free store = false; line switch = false; cycle switch = false; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ projective extremes .resize(6, 0); /∗ LDF 2002.09.18. Added this line. ∗/ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; points .push back ( create new < Point > (first point ptr ) ) ; va list ap; /∗ For the variable length argument list. ∗/ va start (ap, first point ptr ); Point ∗point ptr ; char ∗connector ptr ; string connector string ; while ((connector ptr = va arg (ap, char ∗)) ≠ static cast⟨char ∗⟩(0)) {

connectors .push back ((connector string = connector ptr )); if ((point ptr = va arg (ap, Point ∗)) ≡ static cast⟨Point ∗⟩(0)) {

cycle switch = true; break;

} points .push back ( create new < Point > (point ptr ) ) ; } va end (ap); if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; }

719. Setting function. ⟨ Declare Path functions 700 ⟩ +≡

void set ( Point ∗first point ptr …) ; 720. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set ( Point ∗first point ptr …) { on free store = false; line switch = false; cycle switch = false; do output = true; /∗ LDF 2002.09.18. Added this line. ∗/ ⟨ Discard points and connectors 703 ⟩ projective extremes = 0; /∗ LDF 2002.09.18. Added this line. ∗/ fill draw value = 0; draw color = 0; fill color = 0; dashed = ; /∗ LDF 2003.04.06. Added these three lines. ∗/ pen = ; arrow = false; points .push back ( create new < Point > (first point ptr ) ) ; va list ap; /∗ For the variable length argument list. ∗/ va start (ap, first point ptr ); Point ∗point ptr ; char ∗connector ptr ; string connector string ; while ((connector ptr = va arg (ap, char ∗)) ≠ (char ∗) 0) {

connectors .push back ((connector string = connector ptr )); if ((point ptr = va arg (ap, Point ∗)) ≡ static cast⟨Point ∗⟩(0)) {

cycle switch = true; break;

} points .push back ( create new < Point > (point ptr ) ) ; } va end (ap); }

721. Copy constructor. [LDF 2003.04.06.] ?? !! BUG: Got a memory fault when I tried to use this function. Haven’t tested it yet. It worked to use the default constructor and then the assignment operator. Maybe it’s not kosher to use “∗this = p” in a copy constructor.

Log

[LDF 2002.10.15.] Rewrote this function. The old version caused a memory fault when I tried to use it. I’ve taken code from the default constructor and the assignment operator and put it here without bothering to see what was causing the problem. Probably the old version didn’t account for changes I’ve made in other places, perhaps in the class definition.

[LDF 2002.11.03.] Rewrote this function. Now just using the assignment operator.

⟨ Declare Path functions 700 ⟩ +≡ Path(const Path &p); 722. ⟨ Define Path functions 701 ⟩ +≡

Path ::Path(const Path &p)

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣    ␣    ␣  ;

∗this = p;

on free store = false;

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; return;

}

723. Pseudo-constructor for dynamic allocation.

724. Pointer argument.

Log

[LDF 2002.10.29.] Added argument const Path ∗p. If p ≠ 0, the new Path is assigned to using the values from p.

[LDF 2003.12.30.] Replaced this version of Path ::create new path( ) with a specialization of template⟨class C⟩ C∗create new ( ).

[LDF 2003.12.30.] Changed the argument. It’s now a const Path ∗.

[LDF 2003.12.30.] Removed default argument “0”, because this caused a compiler error when using the DEC C^{++} compiler. Apparently, it suffices to declare a default argument in the template declaration.

⟨ Declare non-member template functions for Path 724 ⟩ ≡

Path ∗create new (const Path ∗p);

See also section 725. This code is used in sections 980 and 981.

725. Reference argument.

Log

[LDF 2002.10.29.] Added this function.

[LDF 2003.12.30.] Replaced this version of Path ::create new path( ) with a specialization of template⟨class C⟩ C∗create new ( ).

[LDF 2003.12.30.] Changed argument from Path to const Path &.

⟨ Declare non-member template functions for Path 724 ⟩ +≡ Path ∗create new (const Path &p);

726. Destructor.

Log

[LDF 2003.08.27.] Made virtual, because GCC with the “-Wall” option issued the following warning: “‘class Path’ has virtual functions but non-virtual destructor”.

⟨ Declare Path functions 700 ⟩ +≡ virtual ∼Path( );

§727  3DLDF-1.1.5.1  DESTRUCTOR 203

727. !! Make sure to delete anything else that I allocate dynamically! ⟨ Define Path functions 701 ⟩ +≡

Path ::∼Path( ) {

bool = false; /∗ true ∗/ if ( ) {

cout ≪ ␣ ≪ flush;

show ( );

getchar ( ); } for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) {

delete ∗iter ; } points .clear ( );

/∗ [LDF 2002.11.03.] This replaces a while loop in which pop back ( ) was used to empty points . ∗/ connectors .clear ( ); /∗ LDF 2002.11.03. Added. ∗/

/∗ LDF 2002.10.07. Added code for handling draw color and fill color . ∗/ if (draw color ≠ 0 ∧ draw color is on free store( ) ≡ true) {

if ( ) cout ≪ ␣ ;

delete draw color ;

draw color = 0; } else if ( ) {

cout ≪ ␣ ␣ ; } if (fill color ≠ 0 ∧ fill color is on free store( ) ≡ true) {

if ( ) cout ≪ ␣ ;

delete fill color ;

fill color = 0; } else if ( ) {

cout ≪ ␣ ␣ ; } if ( ) {

cout ≪ ␣ ≪ flush;

getchar ( ); }

}

728. Clear. LDF Undated. This function is needed because it’s a pure virtual function in Shape, and for getting rid of items in Picture ::clear ( ).

[LDF 2002.10.07.] clear ( ) is needed because it’s called on the Shapes that are stored in Pictures, and I don’t know of a way of overloading destructors. That is, in Picture ::clear ( ), the actual types of the Shapes are unknown, so I can’t call ∼Path( ), ∼Circle( ), or other destructors directly. But a named function such as clear ( ) can serve the same purpose.

Log

[LDF 2002.10.07.] Added code for deallocating the memory allocated for draw color and fill color , if any.

?? I tried calling ∼Path( ) inside Path : clear ( ), but I got a memory fault. Don’t know why. TO DO: Try to find out. However, this isn’t urgent.

204  CLEAR  3DLDF-1.1.5.1 §728

⟨ Declare Path functions 700 ⟩ +≡ virtual void clear ( );

729. ⟨ Define Path functions 701 ⟩ +≡

void Path ::clear ( ) {

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

⟨ Discard points and connectors 703 ⟩

/∗ LDF 2002.10.07. Added code for handling draw color and fill color . ∗/ if (draw color ≠ 0 ∧ draw color is on free store( ) ≡ true) {

if ( ) cout ≪ ␣ ;

delete draw color ;

draw color = 0; } else if ( ) {

cout ≪ ␣ ␣ ; } if (fill color ≠ 0 ∧ fill color is on free store( ) ≡ true) {

if ( ) cout ≪ ␣ ;

delete fill color ;

fill color = 0; } else if ( ) {

cout ≪ ␣ ␣ ; } if ( ) cout ≪ ␣ ;

}

730. Get copy.

Log

[LDF 2002.11.03.] Made virtual. Changed dynamic cast( ) to static cast( ). This may not work. [LDF 2003.01.29.] It seems to work. At least, I haven’t had any problems with it.

⟨ Declare Path functions 700 ⟩ +≡ virtual Shape ∗get copy ( ) const;

§731  3DLDF-1.1.5.1  GET COPY 205

731. ⟨ Define Path functions 701 ⟩ +≡

Shape ∗Path ::get copy ( ) const{ Path ∗p = create new < Path > (0); ∗p = ∗this ; return static cast⟨Shape ∗⟩(p); }

732. Set on free store.

Log

[LDF 2004.01.06.] Made non-inline.

⟨ Declare Path functions 700 ⟩ +≡ virtual bool set on free store(bool b = true);

733. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::set on free store(bool b)

{ on free store = b; return b;

}

734. Setting drawing and filling data.

735. Set fill draw value. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set fill draw value(const signed short s);

736. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set fill draw value(const signed short s)

{ fill draw value = s; return;

}

737. Set draw color.

738. Color version. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set draw color (const Color &c);

739. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set draw color (const Color &c)

{ draw color = &c; return;

}

206 COLOR POINTER VERSION 3DLDF-1.1.5.1 §740

740. Color pointer version. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set draw color (const Color ∗c);

741. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set draw color (const Color ∗c)

{

if (draw color ≠ 0 ∧ draw color is on free store( ) ≡ true) {

delete draw color ; } draw color = c; return;

}

742. Set fill color.

743. Color version. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set fill color (const Color &c);

744. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set fill color (const Color &c)

{ fill color = &c; return;

}

745. Color pointer version. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set fill color (const Color ∗c);

746. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set fill color (const Color ∗c)

{

if (fill color ≠ 0 ∧ fill color is on free store( ) ≡ true) {

delete fill color ; } fill color = c; return;

}

747. Set dash pattern. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set dash pattern(const string s = );

§748  3DLDF-1.1.5.1  SET DASH PATTERN 207

748. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set dash pattern(const string s)

{ dashed = s; return;

}

749. Set pen. ⟨ Declare Path functions 700 ⟩ +≡

virtual void set pen(const string s = );

750. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set pen(const string s)

{ pen = s; return;

}

751. Set connectors. [LDF 2003.02.08.] TO DO: Overload with a version taking a vector⟨string⟩ as its argument. arguments.

Log

[LDF 2003.02.08.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ virtual void set connectors (const string s = );

752. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set connectors (const string s)

{ connectors .clear ( ); connectors .push back (s);

}

753. Transformations. [LDF 2002.11.03.] All of the transformations return a Transform, so that the same Transform can be applied to multiple objects by chaining expressions.

754. Affine transformations.

755. Rotation.

756. Rotation around the main axes. ⟨ Declare Path functions 700 ⟩ +≡

virtual Transform rotate(const real x, const real y = 0, const real z = 0); 757. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::rotate(const real x, const real y, const real z) {

Transform t;

t.rotate(x, y, z);

return ∗this ∗= t; }

758. Rotatation around an arbitrary axis.

759. Transform version. Declared in transfor.web. Must be defined here, because Path is an incomplete type there.

Log

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

[LDF 2003.07.06.] Changed, so that is linear ( ) is used, instead of get line switch( ).

⟨ Define Transform functions 169 ⟩ +≡ Transform Transform ::rotate(const Path &p, const real angle) {

if (¬p.is linear ( )) {

cerr ≪  ␣  ␣                       ␣  ≪

        ␣  ␣   ␣       ␣␣         ␣  ;

return ; } Transform t; t.rotate(p.get point (0), p.get last point ( ), angle); return (∗this ∗= t);

§760  3DLDF-1.1.5.1  POINT VERSION 209

} 760. Point version. Declared in points.web. Must be defined here, because Path is an incomplete type there.

Log

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Define Point functions 330 ⟩ +≡ Transform Point ::rotate(const Path &p, const real angle) {

if (¬p.get line switch( )) {

cerr ≪  ␣  ␣                   ␣  ≪

          ␣  ␣   ␣ ␣      ␣␣         ␣  ;

return ; } Point pt0 = p.get point (0); Point pt1 = p.get point (1); return rotate(pt0 , pt1 , angle);

}

761. Path versions.

762. Point arguments.

Log

[LDF 2002.4.7.] Added default value for angle ≡ 180.

[LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now overloads rotate( ) with three real arguments.

⟨ Declare Path functions 700 ⟩ +≡ virtual Transform rotate(const Point &p0 , const Point &p1 , const real angle = 180);

763. TO DO: Change this, so that I use operator∗=(Transform) here and in the other transformation functions. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::rotate(const Point &p0 , const Point &p1 , const real angle)

{ Transform t; t.rotate(p0 , p1 , angle); return (∗this ∗= t);

}

210 PATH ARGUMENTS 3DLDF-1.1.5.1 §764

764. Path arguments.

Log

[LDF 2002.4.7.] Added default value for angle ≡ 180. [LDF 2002.11.03.] Got rid of local Points p0 and p1 . [LDF 2003.05.02.] Changed name of this function from rotate around ( ) to rotate( ). This function now

overloads rotate( ) with three real arguments.

[LDF 2003.07.13.] Changed, so that is linear ( ) is used instead of checking the return value of get line switch( ). Also, get last point ( ) passed as the second argument to rotate( ), instead of get point (1).

⟨ Declare Path functions 700 ⟩ +≡ Transform rotate(const Path &p, const real angle = 180);

765. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::rotate(const Path &p, const real angle) {

if (¬p.is linear ( )) {

cerr ≪  ␣  ␣                  ␣  ≪

        ␣  ␣   ␣ ␣      ␣␣         ␣  ;

return ; } return rotate(p.get point (0), p.get last point ( ), angle);

}

766. Scale. [LDF 2002.12.20.] TO DO: Make all of the transformations virtual! ⟨ Declare Path functions 700 ⟩ +≡

Transform scale(real x, real y = 1, real z = 1);

767. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::scale(real x, real y, real z) {

Transform t;

t.scale(x, y, z);

return (∗this ∗= t); }

768. Shear. ⟨ Declare Path functions 700 ⟩ +≡

Transform shear (real xy , real xz = 0, real yx = 0, real yz = 0, real zx = 0, real zy = 0);

§769  3DLDF-1.1.5.1  SHEAR 211

769. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::shear (real xy , real xz , real yx , real yz , real zx , real zy )

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ;

Transform t;

t.shear (xy , xz , yx , yz , zx , zy );

if ( ) cout ≪ ␣ ; return (∗this ∗= t);

}

770. Shift.

771. real arguments. ⟨ Declare Path functions 700 ⟩ +≡

Transform shift (real x, real y = 0, real z = 0);

772. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::shift (real x, real y, real z)

{ Transform t; t.shift (x, y, z); return (∗this ∗= t);

}

773. Point argument. ⟨ Declare Path functions 700 ⟩ +≡

Transform shift (const Point &p);

774. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::shift (const Point &p)

{

return shift (p.get x ( ), p.get y ( ), p.get z ( )); }

775. Shift times.

[LDF 2003.01.19.] shift times ( ) returns void, because Path doesn’t have a Transform data member, and there’s no guarantee that all of the Points on points will have identical transforms .

[LDF 2003.01.19.] Note that shift times ( ) will only have an effect on the Points on a Path if it’s called after a call to shift ( ) and before an operation is applied that causes Point ::apply transform( ) to be called.

212 REAL ARGUMENTS 3DLDF-1.1.5.1 §776

776. real arguments.

Log

[LDF 2003.01.19.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ virtual void shift times (real x, real y = 1, real z = 1);

777. ⟨ Define Path functions 701 ⟩ +≡

void Path ::shift times (real x, real y, real z)

{

for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); ^{++}iter )

(∗∗iter ).shift times (x, y, z); return;

}

778. Point argument.

Log

[LDF 2003.01.19.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ virtual void shift times (const Point &p);

779. ⟨ Define Path functions 701 ⟩ +≡

void Path ::shift times (const Point &p)

{

return shift times (p.get x ( ), p.get y ( ), p.get z ( )); }

780. Applying transformations.

781. Multiplying by a Transform. ⟨ Declare Path functions 700 ⟩ +≡

virtual Transform operator∗=(const Transform &t);

782. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::operator∗=(const Transform &t)

{ for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) (∗∗iter ) ∗= t; return t;

}

783. Applying transform to points. ⟨ Declare Path functions 700 ⟩ +≡

virtual void apply transform( );

§784  3DLDF-1.1.5.1  APPLYING TRANSFORM TO POINTS 213

784. ⟨ Define Path functions 701 ⟩ +≡

void Path ::apply transform( )

{

for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++})

(∗∗iter ).apply transform( ); return;

}

785. Projection. [LDF 2002.12.20.] TO DO: Make this function virtual! ⟨ Declare Path functions 700 ⟩ +≡

bool project (const Focus &f, const unsigned short proj , real factor );

786. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::project (const Focus &f, const unsigned short proj , real factor )

{

for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) {

if (¬(∗∗iter ).project (f, proj , factor )) {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ≪

␣ ≪ flush;

return false; } } return true;

}

787. Functions for lines.

788. Alignment with an axis.

789. For lines.

790. No assignment. (Axis argument only). [LDF 2002.11.03.] This function returns the Transform that would transform Path such that it would come to lie on the major axis indicated by its argument (by default, the z-axis). It does not actually perform the transformation on the Path.

Log

[LDF 2002.11.03.] Changed char argument to const char.

⟨ Declare Path functions 700 ⟩ +≡ Transform align with axis (const char axis = ) const;

214  NO ASSIGNMENT  3DLDF-1.1.5.1 §791

791. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::align with axis (const char axis ) const {

Transform t; if (¬get line switch( )) {

cerr ≪  ␣  ␣  ≪

      ␣  ␣   ␣ ␣      ␣␣         ␣  ;

return ; } Point p0 (∗points [0]); Point p1 (∗points [1]); return t.align with axis (p0 , p1 , axis );

}

792. With assignment. [LDF 2002.11.03.] This function should never be called with the bool argument assign ≡ false. It won’t cause any harm, though, since it will just call the const version above.

Log

[LDF 2002.11.03.] Added this function. [LDF 2003.07.18.] Changed, so that is linear ( ) is used, rather than get line switch( ). Also, changed the

way Transform t is set. The latter change was necessary, because GCC 3.3 couldn’t compile this file the way it was before.

⟨ Declare Path functions 700 ⟩ +≡ Transform align with axis (bool assign, const char axis = );

793. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::align with axis (bool assign, const char axis ) {

if (¬is linear ( )) {

cerr ≪  ␣  ␣  ≪

      ␣  ␣   ␣       ␣␣         ␣  ;

return ; } Transform t; t.align with axis (get point (0), get last point ( ), axis ); if (assign ≡ false) {

cerr ≪  ␣  ␣  ≪

      ␣    ␣    ␣        ␣    ␣   ␣          ␣ ≪
      ␣  ␣          ␣     ␣     ␣   ␣      ␣  ≪  ≪

flush; return t;

} return (∗this ∗= t);

}

§794  3DLDF-1.1.5.1  FOR NON-LINES 215

794. For non-lines. (Point and axis arguments). [LDF 2002.11.03.] This function finds the transformation that would align the line segment \overrightarrow{p_{0}p_{1}} with the major axis indicated by the axis argument, and applies it to ∗this . p0 and p1 are not changed.

Log

[LDF 2002.11.03.] Changed Point arguments to const Point & and char argument to const char.

⟨ Declare Path functions 700 ⟩ +≡ Transform align with axis (const Point &p0 , const Point &p1 , const char axis );

795. ⟨ Define Path functions 701 ⟩ +≡

Transform Path ::align with axis (const Point &p0 , const Point &p1 , const char axis = )

{ Transform t; t.align with axis (p0 , p1 , axis ); return (∗this ∗= t);

}

796. Adding Points to Paths.

797. With assignment.

Log

[LDF 2002.4.6.] Added this function. Currently, it doesn’t return a Path. If it turns out that it would be useful to return ∗this , I can change it.

⟨ Declare Path functions 700 ⟩ +≡ void operator+=(const Point &pt );

798. ⟨ Define Path functions 701 ⟩ +≡

void Path ::operator+=(const Point &pt ){ points .push back ( create new < Point > (pt ) ) ; return; }

799. Without assignment.

Log

[LDF 2002.4.6.] Added this function.

216  WITHOUT ASSIGNMENT  3DLDF-1.1.5.1 §800

⟨ Declare Path functions 700 ⟩ +≡ Path operator+(const Point &pt ) const; 800. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::operator+(const Point &pt ) const{ Path pa(∗this ); pa.points .push back ( create new

< Point > (pt ) ) ; return pa; }

801. Adding connectors to Paths.

Log

[LDF 2003.02.09.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ void operator+=(const string s);

802. ⟨ Define Path functions 701 ⟩ +≡

void Path ::operator+=(const string s)

{ connectors .push back (s); return;

}

803. Concatenating Paths.

804. Versions using “&”.

805. With assignment. This function appends the Path argument pa to ∗this .

Log

[LDF 2002.4.6.] Added this function.

[LDF 2002.11.03.] Made non-inline.

⟨ Declare Path functions 700 ⟩ +≡ void operator&=(const Path &pa);

806. ⟨ Define Path functions 701 ⟩ +≡

void Path ::operator&=(const Path &pa){ if (is cycle( ) ∨ pa.is cycle( )) /∗ Return if either one of the Paths is a cycle. ∗/ {

cerr ≪  ␣  ␣  ≪

           ␣  ␣   ␣     ␣   ␣ ␣      ␣     ␣  ≪  ␣  ;

return; } string last connector ; 807. [LDF 2002.4.6.] If there isn’t an explicit connector for every pair of Points in this points , then we have to fill up connectors so that there are enough. Otherwise, the “&” will be at the wrong place. We don’t have to worry about the connectors for pa. ⟨ Define Path functions 701 ⟩ +≡

if (connectors .size( ) ≡ 0) last connector = ; else last connector = connectors .back ( ); while (connectors .size( ) < points .size( ) − 1) connectors .push back (last connector );

808. [LDF 2002.4.6.] If the Paths don’t touch, they are joined using “..” instead of “&”. This mimics the behavior of METAFONT.

Log

[LDF 2002.11.03.] Now using ∗(points .back ( )) instead of get point (points .size( ) − 1).

⟨ Define Path functions 701 ⟩ +≡

if (∗(points .back ( )) ≠ pa.get point (0)) {

cerr ≪  ␣  ␣  ≪  ␣     ␣  ≪

      ␣      ␣  ␣     ␣    ␣       ␣  ␣  ≪ flush;

connectors .push back ( ); } else connectors .push back ( ); for (vector⟨Point ∗⟩::const iterator iter = pa.points .begin( );

/∗ [LDF 2002.4.6.] Copy the Points in pa and put the copies onto points . ∗/ iter ≠ pa.points .end ( ); iter^{++}) points .push back ( create new < Point > (∗iter ) ) ;

809. [LDF 2002.4.6.] Put the connectors from pa onto the new Path. Since they’re strings, and not pointers, we don’t have to copy them. I tested this to make sure it’s true. I don’t know how strings are implemented, but they seem to be handled like string literals. ⟨ Define Path functions 701 ⟩ +≡

for (vector⟨string⟩::const iterator iter = pa.connectors .begin( ); iter ≠ pa.connectors .end ( ); iter^{++}) {

connectors .push back (∗iter ); } return; }

810. Without assignment.

Log

[LDF 2002.4.6.] Added this function. It behaves the way the operator “&” does in METAFONT.

⟨ Declare Path functions 700 ⟩ +≡ Path operator&(const Path &pa) const; 811. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::operator&(const Path &pa) const

{ Path r(∗this ); r &= pa; return r;

}

812. Appending with a connector argument. [LDF 2002.4.7.] It would not have been possible to specify a connector if I’d defined this function as a binary operator, e.g., operator+=( ), so I’ve made it a named function. It can be useful when, for instance, rotation causes two Points, which should be identical, to differ by a small amount, like 1/10, 000 in one coordinate. This has actually happened, which is why I’ve added this function. METAPOST can recover gracefully by using “ ” instead of “&” to connect the paths, but it issues an error message and stops to wait for a response. Using this function can help to avoid such problems.

Log

[LDF 2002.4.7.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ Path append (const Path &pa, string connector = , bool assign = true);

813. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::append (const Path &pa, string connector , bool assign){ Path r(∗this );

string last connector ; /∗ [LDF 2002.4.6.] If there isn’t an explicit connector for every pair of Points in this points , then we have to fill up connectors so that there are enough. Otherwise, the “&” will be at the wrong place. We don’t have to worry about the connectors for pa. ∗/

if (r.connectors .size( ) ≡ 0) last connector = ;

else last connector = r.connectors .back ( );

while (r.connectors .size( ) < r.points .size( ) − 1) r.connectors .push back (last connector ); r.connectors .push back (connector );

/∗ [LDF 2002.4.6.] Copy the Points in pa and put the copies onto points . ∗/ for (vector⟨Point ∗⟩::const iterator iter = pa.points .begin( ); iter ≠ pa.points .end ( ); iter^{++})

r.points .push back ( create new < Point > (∗iter ) ) ;

814. Put the connectors from pa onto the new Path. Since they’re strings, and not pointers, we don’t have to copy them. I tested this to make sure it’s true. I don’t know how strings are implemented, but they seem to be handled like string literals. [LDF 2002.4.6.] ⟨ Define Path functions 701 ⟩ +≡

for (vector⟨string⟩::const iterator iter = pa.connectors .begin( ); iter ≠ pa.connectors .end ( ); iter^{++}) {

r.connectors .push back (∗iter ); } if (assign ≡ true) ∗this = r; return r; }

815. Drawing and filling.

816. Draw.

§817  3DLDF-1.1.5.1  PATH VERSIONS 219

817. Path versions.

818. Normal version.

Log

[LDF 2002.10.07.] Added code for handling draw color and fill color .

⟨ Declare Path functions 700 ⟩ +≡

virtual void draw (const Color &ddraw color = ∗Colors ::default color , const string ddashed = , const string ppen = , Picture &picture = current picture, bool aarrow = false) const;

819. ⟨ Define Path functions 701 ⟩ +≡

void Path ::draw (const Color &ddraw color , const string ddashed , const string ppen, Picture

&picture, bool aarrow ) const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t draw it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} Path ∗p = create new < Path > (∗this ); p fill draw value = ; p arrow = aarrow ; if ( )

cout ≪ ␣ ␣ ≪ ddraw color .get use name( ) ≪ endl ≪ flush; if (ddraw color .get use name( ) ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; Color ∗c = create new < Color > (0); ∗c = ddraw color ; p draw color = c; } else {

if ( ) cout ≪ ␣ ␣ ≪ ddraw color .get name( ) ≪ endl ≪ flush; p draw color = &ddraw color ;

} p fill color = Colors ::background color ; p dashed = ddashed ; p pen = ppen; picture += static cast⟨Shape ∗⟩(p);

/∗ LDF 2002.11.03. Changed dynamic cast( ) to static cast( ). ∗/ if ( ) cout ≪ ␣ ≪ flush; return; } 820. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. If I want to declare it inline, I must define it within the declaration of class Path. Otherwise, it causes a compiler error. I’ve decided to declare it non-inline, and hope that the compiler will inline it by itself. ⟨ Declare Path functions 700 ⟩ +≡

virtual void draw (Picture &picture, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = , bool aarrow = false) const;

821. ⟨ Define Path functions 701 ⟩ +≡

void Path ::draw (Picture &picture, const Color &ddraw color , string ddashed , string ppen, bool

aarrow ) const

{

draw (ddraw color , ddashed , ppen, picture, aarrow ); }

822. Point versions. Declared in points.web, but must be defined here, because Path is an incomplete type here.

[LDF 2002.11.03.] Unlike the Path versions of draw ( ), this function returns a Path. This can be useful, if you want to use the Path that it creates again for something else.

823. Normal version. ⟨ Define Point functions 330 ⟩ +≡

Path Point ::draw (const Point &p, const Color &ddraw color , string ddashed , string ppen, Picture

&picture, bool aarrow ) const

{ Path pa(∗this , p); pa.draw (ddraw color , ddashed , ppen, picture, aarrow ); return pa;

}

824. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. ⟨ Define Point functions 330 ⟩ +≡

Path Point ::draw (Picture &picture, const Point &p, const Color &ddraw color , string

ddashed , string ppen, bool aarrow )

{

return draw (p, ddraw color , ddashed , ppen, picture, aarrow ); }

825. Draw arrow.

826. Path versions.

§827  3DLDF-1.1.5.1  NORMAL VERSION 221

827. Normal version.

Log

[LDF 2003.01.15.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡

virtual void drawarrow (const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = , Picture &picture = current picture) const;

828. ⟨ Define Path functions 701 ⟩ +≡

void Path ::drawarrow (const Color &ddraw color , string ddashed , string ppen, Picture &picture)

const

{

draw (ddraw color , ddashed , ppen, picture, true); }

829. Picture argument first.

Log

[LDF 2003.01.15.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡

virtual void drawarrow (Picture &picture, const Color &ddraw color = ∗Colors ::default color , string ddashed = , string ppen = ) const;

830. ⟨ Define Path functions 701 ⟩ +≡

void Path ::drawarrow (Picture &picture, const Color &ddraw color , string ddashed , string ppen)

const

{

draw (picture, ddraw color , ddashed , ppen, true); }

831. Point versions.

832. Normal version.

Log

[LDF 2003.01.15.] Added this function. [LDF 2003.06.03.] Made drawarrow ( ) const.

⟨ Define Point functions 330 ⟩ +≡

Path Point ::drawarrow (const Point &p, const Color &ddraw color , string ddashed , string

ppen, Picture &picture) const

{ Path pa(∗this , p); pa.drawarrow (ddraw color , ddashed , ppen, picture); return pa;

} 833. Picture argument first.

Log

[LDF 2003.01.15.] Added this function.

[LDF 2003.06.03.] Made drawarrow ( ) const.

⟨ Define Point functions 330 ⟩ +≡

Path Point ::drawarrow (Picture &picture, const Point &p, const Color &ddraw color , string

ddashed , string ppen) const

{

return drawarrow (p, ddraw color , ddashed , ppen, picture); }

834. Draw help.

Log

[LDF 2002.05.10.] Changed the way the default arguments are handled. The way it was didn’t work for both versions, i.e., the Path version and the Point version.

[LDF 2002.4.8.] Added this section. !! It would be nice to do something to make sure that the help lines and curves are not drawn over by filling commands. Maybe it will be possible to take care of this when I implement the hidden surface algorithm in output ( ). [LDF 2002.11.03.] I could have help lines outputted last, if I put them on a vector of their own.

[LDF 2003.07.13.] Made all versions of draw help( ) const.

835. Path versions. [LDF 2002.12.20.] ?? Could these functions be const?

836. Normal version. [LDF 2002.4.8.] Added this function. ⟨ Declare Path functions 700 ⟩ +≡

void draw help(const Color &ddraw color = ∗help color , string ddashed = help dash pattern, string ppen = , Picture &picture = current picture) const;

837. ⟨ Define Path functions 701 ⟩ +≡

void Path ::draw help(const Color &ddraw color , string ddashed , string ppen, Picture &picture)

const

{ if (do help lines ≡ false) return; draw (ddraw color , ddashed , ppen, picture);

}

838. Picture argument first. ⟨ Declare Path functions 700 ⟩ +≡

void draw help(Picture &picture, const Color &ddraw color = ∗help color , string ddashed = help dash pattern, string ppen = ) const; 839. ⟨ Define Path functions 701 ⟩ +≡

void Path ::draw help(Picture &picture, const Color &ddraw color , string ddashed , string ppen)

const

{

draw help(ddraw color , ddashed , ppen, picture); }

840. Point versions.

841. Normal version. [LDF 2002.4.8.] Added this function. Declared in points.web, but must be defined here, because Path is an incomplete type here. ⟨ Define Point functions 330 ⟩ +≡

Path Point ::draw help(const Point &pt , const Color &ddraw color , string ddashed , string

ppen, Picture &picture) const

{ Path pa(∗this , pt ); pa.draw help(ddraw color , ddashed , ppen, picture); return pa;

}

842. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument.

[LDF 2002.10.26.] Declared in points.web. Must be defined here, because Path is an incomplete type there. ⟨ Define Point functions 330 ⟩ +≡

Path Point ::draw help(Picture &picture, const Point &pt , const Color &ddraw color , string

ddashed , string ppen) const

{

return draw help(pt , ddraw color , ddashed , ppen, picture); }

843. Fill.

!! [LDF 2003.02.02.] Filling doesn’t use a pen!! Change everywhere!!.

844. Normal version.

Log

[LDF 2002.10.07.] Added code for handling and fill color .

⟨ Declare Path functions 700 ⟩ +≡

224  NORMAL VERSION  3DLDF-1.1.5.1 §845

void fill (const Color &ffill color = ∗Colors ::default color , Picture &picture = current picture) const; 845. ⟨ Define Path functions 701 ⟩ +≡

void Path ::fill (const Color &ffill color , Picture &picture) const{ bool = false;

/∗ true ∗/ if ( ) cout ≪ ␣ ≪ flush; if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t fill it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} Path ∗p = create new < Path > (0); ∗p = ∗this ; p fill draw value = ; if ( )

cout ≪ ␣ ␣ ≪ ffill color .get use name( ) ≪ endl ≪ flush; if (ffill color .get use name( ) ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; Color ∗c = create new < Color > (0); ∗c = ffill color ; p fill color = c; } else {

if ( ) cout ≪ ␣ ␣ ≪ ffill color .get name( ) ≪ endl ≪ flush; p fill color = &ffill color ;

} p pen = ; p dashed = ; p draw color = Colors ::background color ; picture += static cast⟨Shape ∗⟩(p); if ( ) cout ≪ ␣ ≪ flush; return; }

846. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. ⟨ Declare Path functions 700 ⟩ +≡

void fill (Picture &picture, const Color &ffill color = ∗Colors ::default color ); 847. ⟨ Define Path functions 701 ⟩ +≡

void Path ::fill (Picture &picture, const Color &ffill color )

{

fill (ffill color , picture); }

848. Filldraw.

[LDF 2002.03.25] ([LDF 2002.11.03.] Revised the following text). At the present time, filldraw ( ) differs from the filldraw command in METAFONT and METAPOST: In the default case, the outline is drawn in the default color (currently black) and the Path is filled with the background color (currently white by default). This makes it possible to hide objects that are behind the Path by using the painter’s algorithm when rendering. If you want a Path to be filled with another color, you will have to use explicit arguments for ddraw color and ffill color . Either or both of these can be , which causes the default color (currently black) to be used. Of course, plain fill ( ) followed by plain draw ( ) will produce the same result.

Log

[LDF 2003.07.16.] Made both versions const.

849. Normal version.

Log

[LDF 2002.10.07.] Added code for handling draw color and fill color .

⟨ Declare Path functions 700 ⟩ +≡

void filldraw (const Color &ddraw color = ∗Colors ::default color , const Color &ffill color = ∗Colors ::background color , string ddashed = , string ppen = , Picture &picture = current picture) const; 850. ⟨ Define Path functions 701 ⟩ +≡

void Path ::filldraw (const Color &ddraw color , const Color &ffill color , string ddashed , string

ppen, Picture &picture) const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t filldraw it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} Path ∗p = create new < Path > (0); ∗p = ∗this ; p fill draw value = ; if ( )

cout ≪ ␣ ␣ ≪ ddraw color .get use name( ) ≪ endl ≪ flush; if ( )

cout ≪ ␣ ␣ ≪ ffill color .get use name( ) ≪ endl ≪ flush; if (ddraw color .get use name( ) ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; Color ∗c = create new < Color > (0); ∗c = ddraw color ; p draw color = c; } else {

if ( ) cout ≪ ␣ ␣ ≪ ddraw color .get name( ) ≪ endl ≪ flush; p draw color = &ddraw color ;

} if (ffill color .get use name( ) ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; Color ∗c = create new < Color > (0); ∗c = ffill color ; p fill color = c; } else {

if ( ) cout ≪ ␣ ␣ ≪ ffill color .get name( ) ≪ endl ≪ flush; p fill color = &ffill color ;

} p dashed = ddashed ; p pen = ppen; picture += static cast⟨Shape ∗⟩(p); if ( ) cout ≪ ␣ ≪ flush; return; }

851. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. ⟨ Declare Path functions 700 ⟩ +≡

void filldraw (Picture &picture, const Color &ddraw color = ∗Colors ::default color , const Color &ffill color = ∗Colors ::background color , string ddashed = , string ppen = ) const; 852. ⟨ Define Path functions 701 ⟩ +≡

void Path ::filldraw (Picture &picture, const Color &ddraw color , const Color &ffill color , string

ddashed , string ppen) const

{

filldraw (ddraw color , ffill color , ddashed , ppen, picture); }

853. Undraw.

854. Path versions.

855. Normal version. ⟨ Declare Path functions 700 ⟩ +≡

void undraw (string ddashed = , string ppen = , Picture &picture = current picture);

856. ⟨ Define Path functions 701 ⟩ +≡

void Path ::undraw (string ddashed , string ppen, Picture &picture){

if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t undraw it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush;

return; } Path ∗p = create new < Path > (this ); p fill draw value = ; p draw color = 0; p fill color = 0; p dashed = ddashed ; p pen = ppen; picture += static cast⟨Shape ∗⟩(p); }

857. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. ⟨ Declare Path functions 700 ⟩ +≡

void undraw (Picture &picture, string ddashed = , string ppen = );

858. ⟨ Define Path functions 701 ⟩ +≡

void Path ::undraw (Picture &picture, string ddashed , string ppen)

{

undraw (ddashed , ppen, picture); }

859. Point versions.

860. Normal version. This function is declared in points.web, but must be defined here, because Path is an incomplete type here.

Log

[LDF 2002.4.8.] Added this function. [LDF 2002.11.03.] Changed this function, so that it returns the Path pa, instead of void.

⟨ Define Point functions 330 ⟩ +≡ Path Point ::undraw (const Point &pt , string ddashed , string ppen, Picture &picture) {

Path pa(∗this , pt );

pa.undraw (ddashed , ppen, picture);

return pa; }

861. Picture argument first.

Log

[LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument.

⟨ Define Point functions 330 ⟩ +≡ Path Point ::undraw (Picture &picture, const Point &pt , string ddashed , string ppen) {

return undraw (pt , ddashed , ppen, picture); }

862. Unfill.

863. Normal version. ⟨ Declare Path functions 700 ⟩ +≡

void unfill (Picture &picture = current picture); 864. ⟨ Define Path functions 701 ⟩ +≡

void Path ::unfill (Picture &picture){

if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t unfill it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} Path ∗p = create new < Path > (this ); p fill draw value = ; p draw color = 0; p fill color = 0; p dashed = ; p pen = ; picture += static cast⟨Shape ∗⟩(p); }

865. Unfilldraw.

866. Normal version. ⟨ Declare Path functions 700 ⟩ +≡

void unfilldraw (const Color &ddraw color = ∗Colors ::background color , string ddashed = , string ppen = , Picture &picture = current picture); 867. ⟨ Define Path functions 701 ⟩ +≡

void Path ::unfilldraw (const Color &ddraw color , string ddashed , string ppen, Picture &picture){

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t unfilldraw it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} Path ∗p = create new < Path > (this ); p fill draw value = ;

/∗ LDF 2002.10.07. Added code for handling draw color and fill color . Will get rid of this if I do

actually change it to make it act more like unfilldraw in METAPOST. ∗/ if (ddraw color .get use name( ) ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; Color ∗c = create new < Color > (0); ∗c = ddraw color ; p draw color = c; } else {

if ( ) cout ≪ ␣ ␣ ≪ ddraw color .get name( ) ≪ endl ≪ flush; p draw color = &ddraw color ;

} p fill color = 0; p dashed = ddashed ; p pen = ppen; picture += static cast⟨Shape ∗⟩(p); if ( ) cout ≪ ␣ ≪ flush; return; }

868. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. ⟨ Declare Path functions 700 ⟩ +≡

void unfilldraw (Picture &picture, const Color &ddraw color = ∗Colors ::background color , string ddashed = , string ppen = ); 869. ⟨ Define Path functions 701 ⟩ +≡

void Path ::unfilldraw (Picture &picture, const Color &ddraw color , string ddashed , string ppen) {

unfilldraw (ddraw color , ddashed , ppen, picture); }

870. Labelling.

871. Label.

Log

[LDF 2002.03.25.] Added argument dot and changed definition of dotlabel ( ) below so that it just calls label ( ).

[LDF 2003.04.01.] BUG FIX: Got rid of the first argument unsigned int i, and made the third argument short text short the first argument. Formerly, the Points in Paths were always numbered starting from 0, because the argument text short was passed to Point ::label ( ), not i. Also changed the following versions of label ( ) and dotlabel ( ), that call this function.

872. Normal version.

Log

[LDF 2003.05.06.] Changed the conditional, where text short is compared with , , etc. I had to change it, because I’ve added , etc. Now, the conditional tests for ≤text short ≤ . Of course, this makes an assumption about the values that are used to signal that coordinate values should be used for the label, but I think it’s worth it, to avoid testing text short against each value individually.

[LDF 2003.07.09.] Made position string and dot arguments const.

⟨ Declare Path functions 700 ⟩ +≡

void label (short text short = 0, const string position string = , const bool dot = false, Picture &picture = current picture) const; 873. ⟨ Define Path functions 701 ⟩ +≡

void Path ::label (short text short , const string position string , const bool dot , Picture &picture)

const

{

bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪  ≪ flush;

if (Label :: ≡ false) return; if (points .size( ) ≡ 0)

/∗ LDF 2002.09.27. Added this error handling code. If the Path is empty, don’t label it. ∗/ {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush; return;

} for (vector⟨Point ∗⟩::const iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) {

(∗∗iter ).label (text short , position string , dot , picture);

if (text short ≤ Point :: ∧ text short ≥ Point :: )

/∗ LDF 2003.05.06. Changed this conditional. ∗/ ; /∗ Do nothing. ∗/

else ^{++}text short ; } if ( ) cout ≪ ␣ ≪ ≪ flush;

}

874. Picture argument first. [LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument.

[LDF 2003.07.09.] Made position string and dot arguments const.

Log

⟨ Declare Path functions 700 ⟩ +≡

void label (Picture &picture, short text short = 0, const string position string = , const bool dot = false) const;

875. ⟨ Define Path functions 701 ⟩ +≡

void Path ::label (Picture &picture, short text short , const string position string , const bool dot )

const

{

label (text short , position string , dot , picture); }

876. Dotlabel.

877. Normal version.

Log

[LDF 2003.07.09.] Made text short and position string arguments const.

⟨ Declare Path functions 700 ⟩ +≡

void dotlabel (const short text short = 0, const string position string = , Picture &picture = current picture) const;

878. ⟨ Define Path functions 701 ⟩ +≡

void Path ::dotlabel (const short text short , const string position string , Picture &picture) const {

label (text short , position string , true, picture); }

879. Picture argument first.

Log

[LDF 2002.09.17.] Added this function. It’s convenient for when I want to pass a Picture argument. [LDF 2003.07.09.] Made text short and position string arguments const.

⟨ Declare Path functions 700 ⟩ +≡

void dotlabel (Picture &picture, const short text short = 0, const string position string = ) const;

880. ⟨ Define Path functions 701 ⟩ +≡

void Path ::dotlabel (Picture &picture, const short text short , const string position string ) const {

dotlabel (text short , position string , picture); }

881. Outputting.

882. Extract. This is needed for outputting a Picture.

[LDF 2003.01.31.] ?? Do I need to call Point ::project ( ) on the Points here and in Path ::project ( )?

Log

[LDF 2002.09.17.] Added const Focus &f argument and error handling code. Now, if any of the Points on vector⟨Point ∗⟩ points cannot be projected onto the projection plane using the Focus f, the Path is not put onto the vector⟨Shape ∗⟩ Picture ::elements , and consequently never reaches Picture ::output ( ) and Path ::output ( ).

[LDF 2003.05.09.] Rewrote this function. It now calls Point ::extract ( ) instead of calling apply transform( ) and project ( ) on the Points directly. This makes much more sense, since any changes to Point ::extract ( ) would otherwise not have been applied to Points on Paths.

⟨ Declare Path functions 700 ⟩ +≡ vector⟨Shape ∗⟩ extract (const Focus &f, const unsigned short proj , real factor );

234  EXTRACT  3DLDF-1.1.5.1 §883

883. ⟨ Define Path functions 701 ⟩ +≡

vector⟨Shape ∗⟩ Path ::extract (const Focus &f, const unsigned short proj , real factor )

{ bool = false; /∗ true ∗/ vector⟨Shape ∗⟩ v; int i = 0; for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) {

if ( ) cout ≪ ␣ ≪ i^{++} ≪ ≪ endl ;

v = (∗∗iter ).extract (f, proj , factor );

if ( ) cout ≪ endl ;

if (v.size( ) ≡ 0) /∗ Point ::extract ( ) failed. LDF 2003.05.09. ∗/

return v; } vector⟨Shape ∗⟩ r; r.push back (this ); return r;

}

884. Set extremes. [LDF 2002.09.18.] set extremes ( ) doesn’t check that the projective coordinates in all of the Points on the Path are valid. This is done already in project ( ) and extract ( ), so I don’t think it’s necessary to repeat it here, since extract ( ) (which invokes project ( )), is called before set extremes ( ) in Picture ::output ( ). The latter is the only place where set extremes ( ) is invoked.

[LDF 2002.09.17.] Added this function. ⟨ Declare Path functions 700 ⟩ +≡

virtual bool set extremes ( );

885. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::set extremes ( ){ bool = false; /∗ true ∗/

if ( )

cout ≪ ␣ ≪ endl ≪ flush; /∗ If there are no Points on the Path, set all the elements of projective extremes to and return false. ∗/

if (points .size( ) ≤ 0) {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ≪

␣ ␣ ␣ ␣ ␣ ≪ flush;

projective extremes = ;

return false; } 886. [LDF 2002.09.18.] Added this routine. Set the minimum values to and the maximum values to − . This way, any valid perspective coordinates will replace them on the first iteration of the for loop.

[LDF 2002.09.18.] I had some difficulty debugging this because instead of using − , I defined and used = numeric limits⟨real⟩::min( ). However, this isn’t the negative real with the largest magnitude, but the smallest positive real. ⟨ Define Path functions 701 ⟩ +≡

projective extremes [0] = ; /∗ Minima. ∗/ projective extremes [2] = ; projective extremes [4] = ; projective extremes [1] = − ; /∗ Maxima. ∗/ projective extremes [3] = − ; projective extremes [5] = − ; for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); ^{++}iter ) {

if ( ) { cout ≪ ␣ ␣ ␣ ≪ projective extremes [0] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ projective extremes [1] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get x ( ) ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get x ( , false, false) ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ projective extremes [2] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ projective extremes [3] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get y ( ) ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get y ( , false, false) ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ projective extremes [4] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ projective extremes [5] ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get z ( ) ≪ endl ; cout ≪ ␣ ␣ ␣ ≪ (∗∗iter ).get z ( , false, false) ≪ endl ;

} projective extremes [0] = min(projective extremes [0], (∗∗iter ).get x ( , false, false)); /∗ Min x ∗/ projective extremes [2] = min(projective extremes [2], (∗∗iter ).get y ( , false, false)); /∗ Min y ∗/ projective extremes [4] = min(projective extremes [4], (∗∗iter ).get z ( , false, false)); /∗ Min z ∗/ projective extremes [1] = max (projective extremes [1], (∗∗iter ).get x ( , false, false)); /∗ Max x ∗/ projective extremes [3] = max (projective extremes [3], (∗∗iter ).get y ( , false, false)); /∗ Max y ∗/ projective extremes [5] = max (projective extremes [5], (∗∗iter ).get z ( , false, false)); /∗ Max z ∗/

} if ( ) {

for (int i = 0; i < 6; i^{++})

cout ≪ ≪ i ≪ ␣ ␣ ≪ projective extremes [i] ≪ endl ≪ flush; }

236  SET EXTREMES  3DLDF-1.1.5.1 §887

887. [LDF 2002.09.18.] Added this error handling code. There is a remote chance that a valid Point could have a coordinate ≡ or ± , however, it is virtually impossible that it would be projectable. If it’s the x or y-coordinate, it would probably lie outside the limits defined for the invocation of Picture ::output ( ), and if it was the z, it would either be behind the Focus or so far away as to be practically invisible. I believe that this is the case, even though the z-coordinates are made smaller by applying the equation z_{p} = z/(z + p). ⟨ Define Path functions 701 ⟩ +≡

for (int i = 0; i < 6; i += 2) { if (projective extremes [i] ≡ /∗ Minima ∗/ ∨ projective extremes [i + 1] ≡ − ) /∗ Maxima ∗/ {

if ( ) { cout ≪ ␣ ␣ ≪ i ≪ endl ≪ flush; cout ≪ ≪ i ≪ ␣ ␣ ≪ projective extremes [i] ≪ endl ≪ flush;

}

      cerr ≪  ␣  ␣  ≪  ␣   ␣      ␣      ␣   ␣  ␣   ␣
          ␣ ≪  ␣    ␣   ␣   ␣           ␣   ␣         ␣  ≪ flush;

projective extremes = ;

return false;

break; }

}

if ( ) cout ≪ ␣ ≪ endl ≪ flush; return true; }

888. Get extremes. [LDF 2002.09.18.] Added this function. Any code that calls get extremes ( ) must ensure that project ( ) has been invoked first. ⟨ Declare Path functions 700 ⟩ +≡

virtual inline const valarray⟨real⟩ get extremes ( ) const

{

return projective extremes ; }

889. Get minimum z. [LDF 2003.05.16.] Added this function. ⟨ Declare Path functions 700 ⟩ +≡

virtual real get minimum z ( ) const;

§890  3DLDF-1.1.5.1  GET MINIMUM Z 237

890. ⟨ Define Path functions 701 ⟩ +≡

real Path ::get minimum z ( ) const {

bool = false; /∗ true ∗/

if ( ) { cout ≪ ␣ ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ projective extremes [4] ≪ endl ≪ flush; cout ≪ ␣ ≪ endl ≪ flush;

}

return projective extremes [4]; }

891. Get maximum z. [LDF 2002.09.17.] Added this function. ⟨ Declare Path functions 700 ⟩ +≡

virtual real get maximum z ( ) const;

892. ⟨ Define Path functions 701 ⟩ +≡

real Path ::get maximum z ( ) const {

bool = false; /∗ true ∗/

if ( ) { cout ≪ ␣ ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ projective extremes [5] ≪ endl ≪ flush; cout ≪ ␣ ≪ endl ≪ flush;

}

return projective extremes [5]; }

893. Get mean z. [LDF 2003.05.16.] Added this function. ⟨ Declare Path functions 700 ⟩ +≡

virtual real get mean z ( ) const;

894. ⟨ Define Path functions 701 ⟩ +≡

real Path ::get mean z ( ) const

{

return ((projective extremes [4] + projective extremes [5])/2); }

895. Suppress output. [LDF 2002.09.18.] Added this function. It’s needed because trying to erase a Shape ∗ from elements in Picture ::output ( ) causes a memory fault. ⟨ Declare Path functions 700 ⟩ +≡

virtual void suppress output ( );

238  SUPPRESS OUTPUT  3DLDF-1.1.5.1 §896

896. ⟨ Define Path functions 701 ⟩ +≡

void Path ::suppress output ( )

{

do output = false; }

897. Unsuppress output. [LDF 2002.09.18.] Added this function. It’s needed because trying to erase a Shape ∗ from elements in Picture ::output ( ) causes a memory fault. ⟨ Declare Path functions 700 ⟩ +≡

virtual void unsuppress output ( );

898. ⟨ Define Path functions 701 ⟩ +≡

void Path ::unsuppress output ( )

{

do output = true; }

899. Output. [LDF 2002.09.17.] Removed error checking code to extract ( ). Now output ( ) assumes that all of the Points in points can be projected using focus . If they can’t be, extract ( ) will already have ensured that the Path is not on vector⟨Shape ∗⟩ elements in the Picture.

Log

[LDF 2003.01.15.] Added code for writing “drawarrow” to out stream, if arrow ≡ true. This is for the drawarrow ( ) functions for Path and Point that I’ve added today.

⟨ Declare Path functions 700 ⟩ +≡ virtual void output ( );

900. ⟨ Define Path functions 701 ⟩ +≡

void Path ::output ( ){ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪  ≪ flush;

if (do output ≡ false) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ flush; return;

§901  3DLDF-1.1.5.1  OUTPUT 239

} 901. [LDF 2002.09.27.] Added this error handling code. If the Path is empty, don’t output it. This code should never be reached, because the case of a Path containing no Points should be caught in Path ::draw ( ) and the other drawing and filling commands. If it should reach set extremes ( ) and Picture ::output ( ), which also shouldn’t be possible, they would catch it, too. ⟨ Define Path functions 701 ⟩ +≡

if (points .size( ) ≡ 0) {

cerr ≪  ␣     ␣       ␣ ␣  ␣  ≪

        ␣    ␣      ␣      ␣  ␣  ≪  ␣ ␣   ␣  ␣     ␣  ␣        ␣␣ ≪

␣ ␣ ␣ ≪ flush;

getchar ( );

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪

␣ ␣ ≪ flush;

return; } 902. ⟨ Define Path functions 701 ⟩ +≡

vector⟨Point ∗⟩::iterator point iter = points .begin( ); vector⟨string⟩::iterator connector iter = connectors .begin( ); string connector string ; if (connectors .size( ) > 0) connector string = ∗connector iter^{++}; else connector string = ; if (fill draw value ≡ ) {

if ( ) cout ≪ ≪ flush; if (arrow ≡ true) out stream ≪ ␣ ≪ ∗∗point iter^{++}; else out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ /∗ [LDF 2002.09.26.] Comparing pointers seems to work here. I think it

should, but I wasn’t sure that it really would. ∗/ if (draw color ≠ Colors ::default color ) {

out stream ≪ ␣ ␣ ≪ ∗draw color ; } if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

} else if (fill draw value ≡ ) {

if ( ) cout ≪ ≪ flush; out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (fill color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗fill color ; out stream ≪ ≪ flush;

} else if (fill draw value ≡ ) { if ( ) cout ≪ ≪ flush; if (draw color ≡ fill color ) {

out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (draw color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗draw color ; if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

} else /∗ We have two different colors, so we have to fill once and draw once. ∗/ { out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ out stream ≪ ␣ ␣ ≪ ∗fill color ; out stream ≪ ≪ flush; point iter = points .begin( ); 903.

Log

[LDF 2002.05.10.] Added the code in this section. It fixes a bug. If it’s not done, then the correct connectors are not used when the Path is output the second time.

⟨ Define Path functions 701 ⟩ +≡ connector iter = connectors .begin( ); if (connectors .size( ) > 0) connector string = ∗connector iter^{++}; else connector string = ;

904. ⟨ Define Path functions 701 ⟩ +≡

if (arrow ≡ true) out stream ≪ ␣ ≪ ∗∗point iter^{++}; else out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (draw color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗draw color ; if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush; } } else

if (fill draw value ≡ ) { if ( ) cout ≪ ≪ flush; out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

}

else if (fill draw value ≡ ) { if ( ) cout ≪ ≪ flush; out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ out stream ≪ ≪ flush;

} 905. Filldraw case.

Log

[LDF 2003.03.25.] Changed this section, so that the outline of the Path is drawn, if draw color ≠ Colors ::background color .

⟨ Define Path functions 701 ⟩ +≡

else

if (fill draw value ≡ ) { if ( ) cout ≪ ≪ flush; if (draw color ≡ Colors ::background color ) {

out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

} else {

out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ out stream ≪ ≪ flush; point iter = points .begin( ); connector iter = connectors .begin( ); if (connectors .size( ) > 0) connector string = ∗connector iter^{++}; else connector string = ; out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (draw color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗draw color ; if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

}

}  /∗ End of  case. [LDF 2003.03.25.] ∗/

906. Default case. [LDF 2003.03.25.] ⟨ Define Path functions 701 ⟩ +≡

else /∗ Use DRAW as default. [LDF 2003.03.25.] ∗/ {

cerr ≪ ␣ ␣ ␣ ≪ fill draw value ≪ ␣ ␣ ≪

flush;

#if 0 /∗ !! Define a class for information on the run state. ∗/

if (¬Run State ::non stop) getchar ( ); #endif

if (arrow ≡ true) out stream ≪ ␣ ≪ ∗∗point iter^{++}; else out stream ≪ ␣ ≪ ∗∗point iter^{++}; ⟨ Output Path 907 ⟩ if (draw color ≠ Colors ::default color ) out stream ≪ ␣ ␣ ≪ ∗draw color ; if (dashed ≠ ) out stream ≪ ␣ ␣ ≪ dashed ; if (pen ≠ ) out stream ≪ ␣ ␣ ≪ pen; out stream ≪ ≪ flush;

} if ( ) cout ≪ ␣ ≪ ≪ flush; return; } 907. When fill color and draw color are different, this will have to be performed twice, so I’ve made it a named section.

Log

[LDF 2002.11.03.] counter is now initially set to 2 instead of 1. This makes each line have at most two Points. Previously, the first line had 3 Points (if the Path had at least three Points on it).

[LDF 2002.12.20.] Using the manipulator “fixed ” below. It solves the problem of Points being output in scientific format, which Metapost doesn’t understand.

[LDF 2002.12.20.] I had to add preprocessor code for conditional compilation, because “fixed ” is unknown to the GNU C^{++} Compiler. However, it doesn’t need it in this case, since the problem only occurred when using the DEC C^{++} compiler on a DEC Alpha computer under Compaq Tru64.

⟨ Output Path 907 ⟩ ≡ if ( ) cout ≪ ␣ ␣ ≪ flush; for (unsigned short counter = 2; point iter ≠ points .end ( ); ) {

out stream ≪ ␣ ≪ connector string ≪ ␣ ≪ ∗∗point iter^{++}; /∗ This breaks the line and indents after two points ∗/

if (counter ≡ 2 ∧ point iter ≠ points .end ( )) { out stream ≪ ␣␣ ; counter = 1;

} else {

++counter ; } if (connector iter ≠ connectors .end ( )) connector string = ∗connector iter^{++};

}

if (is cycle( )) out stream ≪ ␣ ≪ connector string ≪ ␣ ;

if (  ) cout ≪  ␣      ␣  ≪ flush;

This code is used in sections 902, 904, 905, and 906.

908. Showing.

909. Show.

Log

[LDF 2003.07.13.] Commented-out the line that prints fill draw value to stdout .

[LDF 2003.08.20.] Now printing points .size( ) and connectors .size( ) to stdout . If the latter is 0, a message is printed, that will be used as the connector.

⟨ Declare Path functions 700 ⟩ +≡

void show (string text = , char coords = , const bool do persp = true, const bool do apply = true, Focus ∗f = 0, const unsigned short proj = Projections :: , const real factor = 1) const; 910. ⟨ Define Path functions 701 ⟩ +≡

void Path ::show (string text , char coords , const bool do persp, const bool do apply , Focus

∗f, const unsigned short proj , const real factor ) const

{ if (text ≡ ) text = ; cout ≪ text ≪ endl ;

#if 0

cout ≪ ␣ ␣ ≪ fill draw value ≪ endl ≪ flush; #endif

coords = tolower (coords ); if (coords ≡ ) ; /∗ Do nothing. ∗/

else if (coords ≡ ) cout ≪  ␣  ≪ flush;
else if (coords ≡ ) cout ≪  ␣  ≪ flush;
else if (coords ≡ ) cout ≪  ␣  ≪ flush;

else {

  cerr ≪  ␣  ␣         ␣ ≪  ␣         ␣    ␣      ␣  ≪

␣ ␣ ≪ flush; coords = ;

} valarray⟨real⟩ v; v.resize(4, 0); /∗ LDF 2002.12.13. Added this line. Needed for porting to Intel Linux (i686). ∗/ string connector string ; vector⟨string⟩::const iterator connectors iter = connectors .begin( ); cout ≪ ␣ ␣ ≪ points .size( ) ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ connectors .size( ) ≪ endl ≪ flush; if (connectors .size( ) ≡ 0) {

cout ≪ ␣ ␣ ␣ ≪ flush;

connector string = ; } {

int loop ctr = 0;

for (vector⟨Point ∗⟩::const iterator points iter = points .begin( ); points iter ≠ points .end ( );

++points iter ) { if (points iter ≠ points .begin( )) {

cout ≪ ␣ ≪ connector string ≪ ␣ ; } if (connectors iter ≠ connectors .end ( )) connector string = ∗connectors iter^{++}; if (loop ctr ≡ 2) /∗ Break each line after 2 Points. ∗/ {

cout ≪ endl ; loop ctr = 0;

}

++loop ctr ; v = (∗∗points iter ).get all coords (coords , do persp, do apply , f, proj , factor ); cout ≪ ≪ v[0] ≪ ␣ ≪ v[1] ≪ ␣ ≪ v[2] ≪ ;

} } if (cycle switch) {

if (connectors iter ≠ connectors .end ( )) connector string = ∗connectors iter^{++};

cout ≪ ␣ ≪ connector string ≪ ␣ ≪ endl ; } else cout ≪ ;

}

911. Show Colors. ⟨ Declare Path functions 700 ⟩ +≡

void show colors (bool stop = false);

912. ⟨ Define Path functions 701 ⟩ +≡

void Path ::show colors (bool stop) {

if (draw color ≠ 0) draw color show ( ); else cout ≪ ␣ ␣ ; if (fill color ≠ 0) fill color show ( ); else cout ≪ ␣ ␣ ; if (stop) getchar ( );

}

913. Returning elements and information.

914. Is on free store.

Log

[LDF 2004.01.06.] Made non-inline.

⟨ Declare Path functions 700 ⟩ +≡ bool is on free store( ) const;

915. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::is on free store( ) const {

return on free store; }

916. Is planar. [LDF 2002.11.05.] is planar ( ) uses the return value of get normal ( ) to determine whether ∗this lies in a plane or not. If it does, is planar ( ) returns true, otherwise, it returns false. If ∗this is linear, is planar ( ) issues a warning and returns true.

Log

[LDF 2002.11.03.] Rewrote this function. It should now work for all Paths. [LDF 2002.11.05.] Rewrote this function again. It now uses the new version of get normal ( ). [LDF 2002.11.06.] Added optional const bool verbose and string text arguments for writing a message

to the standard output.

[LDF 2003.08.14.] Made verbose non-const. Setting it to true if is true. Added to pspglb.web today.

⟨ Declare Path functions 700 ⟩ +≡ virtual bool is planar (bool verbose = false, string text = ) const;

§917  3DLDF-1.1.5.1  IS PLANAR 247

917. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::is planar (bool verbose, string text ) const {

bool = false; /∗ true ∗/ if ( ) verbose = true; if ( ∨ verbose) cout ≪ ␣ ; Point p(get normal ( )); if (p ≡ ) {

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; if (verbose) {

if (text ≡ ) text = ;

cout ≪ text ≪ ␣ ␣ ; } return false;

} else if (p ≡ origin) {

cerr ≪  ␣  ␣  ≪  ␣  ␣       ␣␣         ␣  ≪

flush; if (verbose) {

if (text ≡ ) text = ;

cout ≪ text ≪ ␣ ␣ ; } return true;

} else {

if (verbose) { if (text ≡ ) text = ; cout ≪ text ≪ ␣ ␣ ;

} if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; return true;

} }

918. Is linear. [LDF 2003.04.09.] is linear ( ) first checks whether line switch is true. If it is, it returns true right away. Otherwise, it uses the return value of get normal ( ) to determine whether ∗this is linear or not. If it is, is linear ( ) returns true, otherwise, it returns false.

Log

[LDF 2002.11.05.] Added this function. [LDF 2002.11.06.] Added optional const bool verbose and string text arguments for writing a message

to the standard output.

[LDF 2003.04.09.] Now checking whether line switch is true before calling get normal ( ). !! If a Path whose line switch ≡ true is modified such that it’s no longer linear, the programmer must ensure that line switch is set to false!

[LDF 2003.08.14.] Made verbose non-const. Setting it to true if is true. Added to pspglb.web today.

⟨ Declare Path functions 700 ⟩ +≡ bool is linear (bool verbose = false, string text = ) const;

248  IS LINEAR  3DLDF-1.1.5.1 §919

919. ⟨ Define Path functions 701 ⟩ +≡

bool Path ::is linear (bool verbose, string text ) const {

bool = false; /∗ true ∗/ if ( ) verbose = true; if ( ∨ verbose) cout ≪ ␣ ; if (line switch) /∗ LDF 2003.04.09. Added this conditional. ∗/

return true; Point p(get normal ( )); if (p ≡ origin) {

if (verbose) { if (text ≡ ) text = ; cout ≪ text ≪ ␣ ␣ ;

}

if ( ) cout ≪ ␣ ␣ ≪ ␣ ≪ flush; return true;

} else {

if (verbose) { if (text ≡ ) text = ; cout ≪ text ≪ ␣ ␣ ;

}

if ( ) cout ≪ ␣ ␣ ≪ ␣ ≪ flush; return false;

} }

920. Get line switch. [LDF 2002.11.03.] This function returns true for Paths that are created or set using two Points only, and no connectors, as arguments.

Log

[LDF 2002.11.03.] Renamed this function get line switch( ) from is line( ). About to add is linear ( ), which will test whether all the Points are colinear or not.

⟨ Declare Path functions 700 ⟩ +≡ inline bool get line switch( ) const {

return line switch; }

921. Test for cycles. ⟨ Declare Path functions 700 ⟩ +≡

inline bool is cycle( ) const {

return cycle switch; }

922. Size (number of points). ⟨ Declare Path functions 700 ⟩ +≡

§922  3DLDF-1.1.5.1  SIZE (NUMBER OF POINTS) 249

inline int size( )

{

return points .size( ); }

923. Slope. [LDF 2002.11.05.] slope( ) can only be used for linear Paths. It returns a real value representing the slope of the trace of a line on the major plane represented by the char arguments, or , if the Path is non-linear. For example, if \overrightarrow{p_{0}p_{1}} is a Path p and \overrightarrow{q_{0}q_{1}} is the trace of p on the x-y plane, then p.slope( , ) returns a real m such that m = (b − y)/x where b is the y-intercept of \overrightarrow{q_{0}q_{1}} and x and y are the x and y-coordinates of points on \overrightarrow{q_{0}q_{1}}.

Log

[LDF 2002.11.05.] Changed this function, so that is linear ( ) is used instead of get line switch( ) (formerly “is line( )”). Now, it can be used for all linear Paths, not just ones created using the constructor for lines. Also, it was commented-out.

⟨ Declare Path functions 700 ⟩ +≡ real slope(char a = , char b = );

924. ⟨ Define Path functions 701 ⟩ +≡

real Path ::slope(char a, char b)

{

if (¬is linear ( )) {

      cerr ≪  ␣  ␣              ␣    ␣  ␣   ␣  ≪

␣ ≪ flush;

return ; } return points [1] slope(∗points [0], a, b);

}

925. Subpath. [LDF 2002.11.05.] subpath( ) returns a new Path using points [start ] through points [end − 1] from ∗this . If the optional bool argument cycle is used, then the new Path will be a cycle, whether ∗this is or not. One optional connector argument can be used. If it is, it will be the only connector. Otherwise, the connectors from ∗this are used.

[LDF 2002.11.05.] start must be < end . It is not possible to have start > end , even if ∗this is a cycle.

Log

[LDF 2002.11.05.] Rewrote this function. Made subpath( ) itself and its arguments const. Added error handling code.

[LDF 2003.07.16.] Please note that start and end cannot be made const.

[LDF 2003.08.27.] Changed int i to size t i in the for loops that compare i to start and end . The way it was before caused GCC with the “-Wall” option to issue a warning.

⟨ Declare Path functions 700 ⟩ +≡ Path subpath(size t start , size t end , const bool cycle = false, const string connector = ) const;

250  SUBPATH  3DLDF-1.1.5.1 §926

926. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::subpath(size t start , size t end , const bool cycle, const string connector ) const{ bool

= false; /∗ true ∗/ Path p;

927. [LDF 2002.11.05.] There is no “ ”, so I return an empty one, if start ≥ end . Since operator≡( ) currently doesn’t exist, there’s not much point in defining , since there’s no way to compare another Path to it. ⟨ Define Path functions 701 ⟩ +≡

if (start ≥ end ) {

  cerr ≪  ␣  ␣  ≪  ␣         ␣        ␣  ␣ ␣   ␣

␣  ≪  ␣     ␣  ≪ flush;

return p; }

928. [LDF 2002.11.05.] More error handling. In these cases, it’s possible to recover. ⟨ Define Path functions 701 ⟩ +≡

if (start > points .size( ) − 1) {

  cerr ≪  ␣  ␣  ≪  ␣        ␣   ␣ ␣            ␣
      ␣  ≪  ␣   ␣  ␣       ␣  ␣       ␣     ␣ ␣  ≪ flush;

start = 0; } if (end > points .size( )) {

cerr ≪  ␣  ␣  ≪  ␣        ␣   ␣ ␣  ≪

      ␣   ␣  ␣       ␣  ␣       ␣   ␣ ␣  ≪ flush;

end = points .size( ); }

929. [LDF 2002.11.05.] If a connector argument is specified, all we have to do is put the appropriate Points from points onto p.points , put connector onto p.connectors , and return p. ⟨ Define Path functions 701 ⟩ +≡

if (connector ≠ ) { for (size t i = start ; i < end ; i^{++}) { if (i ≥ points .size( )) {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ≪

␣ ␣ ␣ ≪ flush; break;

} p.points .push back ( create new < Point > (points [i]) ) ; } p.connectors .push back (connector ); p.set cycle(cycle); return p; }

§930  3DLDF-1.1.5.1  SUBPATH 251

930. [LDF 2002.11.05.] If no connector argument is specified, then we have to get the appropriate connectors from ∗this . This is slightly tricky, because connectors doesn’t have to contain a connector for each pair of Points that is joined in a Path. So, first we must fill up p.connectors so that we can tell which ones to use.

[LDF 2002.11.05.] Actually, with the constructors that exist, there will either be only one connector or a connector for each pair of Points that need to be joined. However, it would be easy to write functions that add or remove connectors, so it’s best to have this routine. ⟨ Define Path functions 701 ⟩ +≡

p = ∗this ; unsigned short a = points .size( ); if (¬cycle) a −= 1; int i; string s = connectors .back ( ); for (i = connectors .size( ); i < a; i^{++}) {

p.connectors .push back (s); } if ( ) cout ≪ ␣ ␣ ≪ p.connectors .size( ) ≪ endl ≪ flush; Path q; for (size t i = start ; i < end ; i^{++}) { q.points .push back ( create new < Point > (p.points [i])

) ; if (i < p.connectors .size( )) q.connectors .push back (p.connectors [i]); } q.set cycle(cycle); return q; }

931. Get point.

932. non-const version.

Log

[LDF 2002.11.05.] Made non-inline. Changed return value to const Point &. [LDF 2003.11.28.] BUG FIX: Changed, so that apply transform( ) is called on the Point. This entailed

making this function non-const. Added const version below. This may actually be a bug, rather than a bug fix, depending on how this function is used elsewhere. However, I really think apply transform( ) should be called.

⟨ Declare Path functions 700 ⟩ +≡ const Point &get point (const unsigned short a); 933. ⟨ Define Path functions 701 ⟩ +≡

const Point &Path ::get point (const unsigned short a) {

if (a < points .size( )) { (points [a]) apply transform( ); return ∗points [a];

}

else {

    cerr ≪  ␣  ␣  ≪  ␣  ␣  ␣     ␣  ␣  ≪

␣ ≪ flush;

return ; }

}

934. const version.

Log

[LDF 2003.11.28.] Added this version.

⟨ Declare Path functions 700 ⟩ +≡ Point get point (const unsigned short a) const;

935. ⟨ Define Path functions 701 ⟩ +≡

Point Path ::get point (const unsigned short a) const {

if (a < points .size( )) { Point p = ∗(points [a]); p.apply transform( ); return p;

}

else {

    cerr ≪  ␣  ␣  ≪  ␣  ␣  ␣     ␣  ␣  ≪

␣ ≪ flush;

return ; }

}

936. Get last point.

Log

[LDF 2002.05.10.] Added this function. [LDF 2002.11.05.] Made non-inline. Changed return value to const Point &.

⟨ Declare Path functions 700 ⟩ +≡ const Point &get last point ( ) const;

§937  3DLDF-1.1.5.1  GET LAST POINT 253

937. ⟨ Define Path functions 701 ⟩ +≡

const Point &Path ::get last point ( ) const {

if (points .size( ) ≠ 0) return ∗points [points .size( ) − 1]; else {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ≪

␣ ≪ flush;

return ; }

}

938. Get size. ⟨ Declare Path functions 700 ⟩ +≡

virtual inline size t get size( ) const {

return points .size( ); }

939. Get normal.

254 PATH VERSION 3DLDF-1.1.5.1 §940

940. Path version. [LDF 2002.11.05.] get normal ( ) returns a unit vector representing the normal to the plane of the Path ∗this , if ∗this is planar. If the Points on ∗this are colinear and there are no connectors that could make the Path non-linear, then origin ((0, 0, 0)) is returned. If the Path is neither planar nor linear, get normal ( ) returns .

[LDF 2002.11.05.]

• get normal ( ) first checks whether a Path contains no Points or only one Point. If so, get normal ( ) returns .

• Then it checks whether the Path has connnectors that might make the Path non-planar, even if the Points lie in a plane. If it does, it returns . Note that there is no guarantee that the connectors actually will make the Path non-planar.

• Then it checks whether the Path has only two Points. If it does, get normal ( ) returns the Point (0, 0, 0), because the Path will be linear.

• Then it gets the cross product b_{0} of \overrightarrow{p_{0}p_{1}} and \overrightarrow{p_{0}p_{2}}, where p_{0} and p_{1} are the first and second Points on the Path, and p_{2} is the next Point on the Path such that b_{0} ≠ (0, 0, 0). If no Points on the Path fulfill this condition, then all of the Points are colinear, so get normal ( ) returns origin.

• If, however, b_{0} ≠ (0, 0, 0) exists, then cross products b_{x} are calculated using \overrightarrow{p_{0}p_{1}} and the direction vectors \overrightarrow{p_{0}p_{x}} for the rest of the Points p_{x} on the Path. If and only if b_{x} = b_{0}, or b_{x} = −b_{0}, or b_{x} = (0, 0, 0) for all b_{x}, then the Path is planar, and get normal ( ) returns −b_{0} (see explanation of sign below). Otherwise, the Path is non-planar, and get normal ( ) returns . [LDF 2003.06.04.] Reversing the sign of b_{0} ensures that the normal will point in the direction of the positive

y-axis, when a plane figure is created in the x-z plane, using one of the constructors taking a Point argument for the center, real arguments for the dimensions, and three real arguments for the rotation about the major axes. If non-zero arguments are used for rotation, the normal will be rotated accordingly. This direction considered to be “outside”. In 3DLDF, the constructors generally generate Points moving about the figure in the counter-clockwise direction (as seen from a Point with a positive y-coordinate). However, according to Huw Jones, Computer Graphics Through Key Mathematics, p. 197, “outside” is considered to be the side of a plane, where the Points are meant to be traversed in the clockwise direction. !! Watch out for problems that may arise from this discrepancy!

Log

[LDF 2002.11.05.] Rewrote this function.

[LDF 2003.06.04.] Changed sign of the normal, when it’s returned, in the cases where a proper normal is found (not or origin). See explanation above.

⟨ Declare Path functions 700 ⟩ +≡ virtual Point get normal ( ) const;

941. ⟨ Define Path functions 701 ⟩ +≡

Point Path ::get normal ( ) const{ bool  = false;  /∗ true ∗/
if (  ) cout ≪  ␣  ≪ flush;

if (points .size( ) ≤ 0) {

cerr ≪  ␣  ␣  ≪

           ␣  ␣     ␣  ␣        ␣    ␣   ␣       ␣ ≪  ␣  ≪

flush; return ;

}

§942  3DLDF-1.1.5.1  PATH VERSION 255

942. [LDF 2002.11.05.] Connectors other than the ones in the conditional below could cause the Path to be non-linear or non-planar, even if the Points lie on a line or in a plane. ⟨ Define Path functions 701 ⟩ +≡

for (vector⟨string⟩::const iterator iter = connectors .begin( ); iter ≠ connectors .end ( ); ^{++}iter ) {

if (¬(∗iter ≡  ∨ ∗iter ≡  ∨ ∗iter ≡  ∨ ∗iter ≡  )) {

      cerr ≪  ␣  ␣  ≪  ␣   ␣    ␣     ␣          ␣  ␣

␣ ≪ ∗iter ≪ endl ≪  ␣  ≪ flush;

return ; }

}

943. [LDF 2002.11.05.] Two points determine a line. ⟨ Define Path functions 701 ⟩ +≡

if (points .size( ) ≡ 2) {

cerr ≪  ␣  ␣  ≪

        ␣   ␣ ␣       ␣ ␣         ␣  ≪ flush;

return origin; } 944. ⟨ Define Path functions 701 ⟩ +≡

vector⟨Point ∗⟩::const iterator iter = points .begin( ); Point p0 (∗∗iter^{++}); Point p1 (∗∗iter^{++}); Point p2 ; Point a0 (p1 − p0 ); Point a1 ; Point b0 ; while (b0 ≡ origin ∧ iter ≠ points .end ( )) {

p2 = ∗∗iter^{++};

a1 = p2 − p0 ;

b0 = a0 .cross product (a1 ); } if (iter ≡ points .end ( ) ∧ b0 ≡ origin) {

if ( ) cout ≪ ␣ ␣ ≪ ␣ ␣ ␣ ≪

␣ ≪ flush; return origin;

} if ( ) b0 .show ( ); b0 .unit vector (true); if (iter ≡ points .end ( ) ∧ b0 ≠ origin) {

if ( ) {

    cout ≪  ␣                   ␣ ≪  ␣   ␣   ␣        ␣      ␣   ␣  ≪

␣ ≪ flush;

}

return −b0 ; } Point b1 ; if ( ) cout ≪ ␣ ␣ ≪ flush; while (iter ≠ points .end ( )) {

p2 = ∗∗iter^{++};

a1 = p2 − p0 ;

b1 = a0 .cross product (a1 );

if (b1 ≠ origin)

/∗ [LDF 2002.11.03.] This if merely prevents a warning from being issued by unit vector ( ). ∗/ b1 .unit vector (true);

if ( ) b1 .show ( );

if (¬(b1 ≡ origin ∨ b1 ≡ b0 ∨ b1 ≡ −b0 )) {

if ( )

cout ≪ ␣ ␣ ≪ ␣ ≪ flush; return ;

} } if ( ) cout ≪ ␣ ␣ ≪ ␣ ≪ flush; return −b0 ; } 945. Point version. Point ::get normal ( ) is declared points.web, but it must be defined here, because it calls Path ::get normal ( ). [LDF 2003.07.11.]

Log

[LDF 2003.07.11.] Added this function.

⟨ Define Point functions 330 ⟩ +≡ Point Point ::get normal (const Point &p, const Point &q) const {

Path r; r.set connectors ( ); r += ∗this ; r += p; r += q; if (¬r.is planar ( )) {

cerr ≪  ␣  ␣  ≪

      ␣      ␣  ␣   ␣         ␣ ␣  ≪  ␣  ≪ flush;

return ; } else return r.get normal ( );

}

946. Get plane.

Log

[LDF 2002.11.05.] Rewrote this function to correspond to the new definition of get normal ( ).

⟨ Declare Path functions 700 ⟩ +≡ virtual Plane get plane( ) const;

258  GET PLANE  3DLDF-1.1.5.1 §947

947. ⟨ Define Path functions 701 ⟩ +≡

Plane Path ::get plane( ) const

{ Point normal (get normal ( )); if (normal ≡ ∨ normal ≡ origin) {

cerr ≪  ␣  ␣  ≪

          ␣  ␣   ␣ ␣      ␣         ␣  ≪ flush;

return ; } Point point (get point (0)); return Plane(point , normal );

}

948. Point lies within triangle. [LDF 2003.06.11.] Declared in points.web. Must be defined here, because Path is an incompletely defined type there.

Log

[LDF 2003.06.11.] Added this function.

[LDF 2003.06.24.] Removed the argument test points . Now, planarity is always tested.

[LDF 2003.06.24.] BUG FIX: When the Points all lay in the x-z plane, or a plane parallel to it, lambda denominator was 0. This caused is in triangle( ) to return false, even when ∗this did lie in the triangle. Now, if lambda denominator or mu denominator is equal to 0, the y and z-coordinates are exchanged, and lambda denominator and mu denominator are recalculated. If either of the new values is 0, the x and z-coordinates are exchanged (based on the original coordinate values), and lambda denominator and mu denominator are again recalculated. Only one exchange has been needed in the cases I’ve tested so far.

[LDF 2003.08.14.] Setting verbose to true if  is true. Added  to

pspglb.web today.

⟨ Define Point functions 330 ⟩ +≡

bool Point ::is in triangle(const Point &p0 , const Point &p1 , const Point &p2 , bool verbose)

const{ bool = false; /∗ true ∗/ if ( ) verbose = true; Path q; q += p0 ; q += p1 ; q += p2 ; Plane q pl = q.get plane( ); if (q pl ≡ ) {

if (verbose) {

cerr ≪  ␣  ␣  ≪

             ␣     ␣         ␣  ␣   ␣         ␣ ␣  ≪  ␣  ≪

flush; } return false;

}

else if (¬is on plane(q pl )) { if (verbose) {

§948  3DLDF-1.1.5.1  POINT LIES WITHIN TRIANGLE 259
cerr ≪  ␣  ␣  ≪

        ␣       ␣   ␣   ␣   ␣     ␣          ␣ ≪ ␣   ␣  ≪

␣ ≪ flush;

}

return false; } Point t(∗this ); Point c(p0 ); Point d(p1 ); Point e(p2 ); t.apply transform( ); c.apply transform( ); d.apply transform( ); e.apply transform( ); if ( ) {

show ( ); c.show ( ); d.show ( ); e.show ( );

} real t x = t.world coordinates [0]; real t y = t.world coordinates [1]; real t z = t.world coordinates [2]; real c x = c.world coordinates [0]; real c y = c.world coordinates [1]; real c z = c.world coordinates [2]; real d x = d.world coordinates [0]; real d y = d.world coordinates [1]; real d z = d.world coordinates [2]; real e x = e.world coordinates [0]; real e y = e.world coordinates [1]; real e z = e.world coordinates [2]; real lambda denominator = (((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x ))); real mu denominator = ((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x )); bool exchange y z = false; bool exchange x z = false; if (lambda denominator ≡ 0 ∨ mu denominator ≡ 0) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ≪

␣ ␣ ␣ ≪ flush; real temp; temp = t y ; t y = t z ; t z = temp; temp = c y ; c y = c z ; c z = temp; temp = d y ; d y = d z ; d z = temp; temp = e y ; e y = e z ; e z = temp;

260 POINT LIES WITHIN TRIANGLE 3DLDF-1.1.5.1 §948

lambda denominator = (((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x ))); mu denominator = ((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x )); if (¬(lambda denominator ≡ 0 ∨ mu denominator ≡ 0)) {

if (  ) cout ≪  ␣ ␣   ␣             ␣  ≪

           ␣    ␣             ␣    ␣  ␣      ␣  ≪ flush;

exchange y z = true; } else { if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ≪

␣ ␣ ␣ ≪ flush;

949. First, put things back the way they were. It’s wasteful, but less confusing. [LDF 2003.06.24.] ⟨ Define Point functions 330 ⟩ +≡

temp = t y ; t y = t z ; t z = temp; temp = c y ; c y = c z ; c z = temp; temp = d y ; d y = d z ; d z = temp; temp = e y ; e y = e z ; e z = temp; 950. Now, exchange the x and z-coordinates. [LDF 2003.06.24.] ⟨ Define Point functions 330 ⟩ +≡

temp = t x ; t x = t z ; t z = temp; temp = c x ; c x = c z ; c z = temp; temp = d x ; d x = d z ; d z = temp; temp = e x ; e x = e z ; e z = temp; lambda denominator = (((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x ))); mu denominator = ((e x − c x ) ∗ (d y − c y )) − ((e y − c y ) ∗ (d x − c x )); if (¬(lambda denominator ≡ 0 ∨ mu denominator ≡ 0)) {

if (  ) cout ≪  ␣ ␣   ␣             ␣  ≪

        ␣    ␣             ␣    ␣  ␣      ␣  ≪ flush;

exchange x z = true; } else {

if (verbose ∨ ) {

cerr ≪  ␣  ␣  ≪
␣   ␣             ␣   ␣  ≪  ␣  ≪ flush;

}

return false; } } } real lambda = (((t x − c x ) ∗ (d y − c y )) − ((t y − c y ) ∗ (d x − c x )))/lambda denominator ; real mu = −((((t x − c x ) ∗ (e y − c y )) − ((t y − c y ) ∗ (e x − c x )))/mu denominator ); if ( ) {

cout ≪ ␣ ␣ ≪ lambda ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ mu ≪ endl ≪ flush;

cout ≪ ␣ ␣ ␣ ␣ ≪ lambda + mu ≪ endl ≪ flush;

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ (lambda ≥ 0 ∧ mu ≥

0 ∧ ((lambda + mu) ≤ 1)) ≪ endl ≪ flush; } bool b = (lambda ≥ 0 ∧ mu ≥ 0 ∧ ((lambda + mu) ≤ 1)); if (verbose) {

cout ≪ ␣ ;

if (b) cout ≪  ␣     ␣    ␣       ␣   ␣         ␣ ≪  ␣  ;
else cout ≪  ␣     ␣       ␣    ␣      ␣   ␣         ␣ ≪  ␣  ;

cout ≪ endl ≪ endl ≪ flush; } return b; }

951. Manipulating Paths.

952. Set cycle.

Log

[LDF 2002.4.7.] Changed, so that the argument bool c is true by default.

262  SET CYCLE  3DLDF-1.1.5.1 §952

[LDF 2002.11.05.] Made bool c argument const.

⟨ Declare Path functions 700 ⟩ +≡ void set cycle(const bool c = true);

953. ⟨ Define Path functions 701 ⟩ +≡

void Path ::set cycle(const bool c)

{

cycle switch = c; }

954. Reverse.

955. With assignment.

Log

[LDF 2002.4.6.] Added this function.

[LDF 2003.07.16.] Added error handling code for the case that this function is called with assign ≡ false. I’ve now added a const version, so there’s no need to call this version with assign ≡ false. If assign is false, the const version is called, so I could simplify the code in this version.

⟨ Declare Path functions 700 ⟩ +≡ Path reverse(bool assign);

956. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::reverse(bool assign){ bool = false; /∗ true ∗/ if (is cycle( )) /∗ Return ∗this if ∗this is a cycle. ∗/ {

        cerr ≪  ␣  ␣  ≪  ␣  ␣ ␣      ␣      ␣  ≪
           ␣  ;

return ∗this ; } if (¬assign) {

cerr ≪  ␣  ␣  ≪  ␣  ␣      ␣

           ␣    ␣    ␣        ␣ ≪  ␣     ␣  ␣   ␣  ≪
           ␣         ␣        ␣  ␣        ␣  ≪  ␣  ≪

flush; return reverse( );

} 957. [LDF 2002.4.6.] If there is more than one connector, but there isn’t an explicit connector for every pair of Points in points , then we have to fill up connectors so that there is one for each pair of Points. Otherwise, the connectors and the Points won’t match up properly when we reverse them. ⟨ Define Path functions 701 ⟩ +≡

if (connectors .size( ) > 1 ∧ connectors .size( ) ≠ points .size( ) − 1) { string last connector ; last connector = connectors .back ( ); while (connectors .size( ) < points .size( ) − 1) connectors .push back (last connector );

}

958. [LDF 2002.4.7.] If I don’t explicitly refer to the std namespace here, this function is called, and since the arguments are different from the one used for this function, this causes an error at compile time. ⟨ Define Path functions 701 ⟩ +≡

if ( ) cout ≪ ␣ ␣ ␣ ≪ flush; std ::reverse(connectors .begin( ), connectors .end ( )); std ::reverse(points .begin( ), points .end ( )); if ( ) {

cout ≪ ␣ ;

for (vector⟨string⟩::iterator iter = connectors .begin( ); iter ≠ connectors .end ( ); iter^{++})

cout ≪ ∗iter ≪ endl ; cout ≪ ␣ ; for (vector⟨Point ∗⟩::iterator iter = points .begin( ); iter ≠ points .end ( ); iter^{++}) (∗∗iter ).show ( ); getchar ( );

} /∗ if ( ) ∗/

return ∗this ; }

959. No assignment. This version merely copies ∗this and calls reverse(true) on the copy, returning the return value of that function call.

Log

[LDF 2003.07.16.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ Path reverse(void) const;

960. ⟨ Define Path functions 701 ⟩ +≡

Path Path ::reverse(void) const

{ Path p = ∗this ; return p.reverse(true);

}

961. Equality. TO DO: I’ll need to make all connectors explicit in order to make this work. See operator&( ) for an example of how to make this work. ⟨ Declare Path functions 700 ⟩ +≡ #if 0

virtual bool operator≡(Path &p); #endif

264  EQUALITY  3DLDF-1.1.5.1 §962

962. ⟨ Define Path functions 701 ⟩ +≡ #if 0

virtual bool Path ::operator≡(Path &p)

{ } #endif

963. Intersection.

964. Intersection of two linear Paths. If ∗this is a line and the argument pa is a line, intersection point ( ) calls the version for Points in points.web.

Other kinds of Paths and other classes will need their own versions of this function.

I may have a problem with the constancy of ∗this and pa. If I do, just remove it.

Log

[LDF 2002.04.15.] Changed return value from bool real point to bool point, since I’ve had to commentout the version of Point ::intersection point ( ) that uses the Line version.

[LDF 2002.04.10.] Changed return type to bool real point to correspond with the same change to Point ::intersection point ( ).

[LDF 2003.07.04.] Added trace argument. Added conditional using trace to choose which version of Point ::intersection point ( ) should be called. Changed so that is linear ( ) is used instead of get line switch( ). Now using get last point ( ) instead of ∗points [1].

⟨ Declare Path functions 700 ⟩ +≡ bool point intersection point (const Path &pa, const bool trace = false) const;

§965  3DLDF-1.1.5.1  INTERSECTION OF TWO LINEAR PATHS 265

965. ⟨ Define Path functions 701 ⟩ +≡

bool point Path ::intersection point (const Path &pa, const bool trace) const

{

if (is linear ( ) ∧ pa.is linear ( )) {

if (trace) return Point ::intersection point (∗points [0], get last point ( ), ∗pa.points [0],

pa.get last point ( ), trace); else return Point ::intersection point (∗points [0], get last point ( ), ∗pa.points [0], pa.get last point ( ),

trace);

} else {

cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ ␣ ≪ flush; return ;

} }

966. Intersection of a linear Path with a Plane. [LDF 2003.06.03.] This function must be defined here, because Path is an incomplete type in planes.web.

Log

[LDF 2003.06.03.] Added this function.

⟨ Define Plane functions 664 ⟩ +≡ bool point Plane ::intersection point (const Path &p) const {

if (p.is linear ( )) return intersection point (p.get point (0), p.get last point ( )); else {

cerr ≪ ␣ ␣ ␣ ≪ endl ≪

␣ ␣ ␣ ␣␣ ␣ ≪ endl ≪ endl ≪ flush; return ;

} }

967. Drawing axes. This function draws and labels arrows for the main axes at the origin. It can be helpful for determining whether the “up” direction is correct for a Focus.

[LDF 2003.04.01.] Sometimes placeholders are needed for the dist and position arguments. If dist is a number x ≤ 0, then it’s set to the default, currently 2.5. If a position argument (pos x , pos y , or pos z ) is , it’s set to the default.

Log

[LDF 2003.02.05.] Moved this function from main.web to here, so I can use it in my examples for the Texinfo documentation. Also, added additional arguments specifying the positions of labels and suppressing drawing the axes (and their labels).

[LDF 2003.04.01.] Added arguments for dash pattern (ddashed ) and pen (ppen). Rearranged order of arguments. Also, got rid of the arguments suppress x , suppress y , and suppress z . Now using the empty string ( ) in the arguments pos x , pos y , and pos z to indicate that the corresponding axes should be suppressed. Added error handling code that prints a warning to stderr if all axes are suppressed. ([LDF 2003.05.06.] Note that will never be needed for labelling an axis, because putting the label on top of the Point would interfere with the arrow.)

[LDF 2003.04.01.] Added arguments shift x , shift y , and shift z for adjusting the position of the labels. Note that the adjustment affects the position of the three-dimensional Point within the Label, not the two-dimensional projected point. Therefore, it’s not possible to adjust the position of the Label precisely

266  DRAWING AXES  3DLDF-1.1.5.1 §967

without changing the Metapost code. TO DO: Change label ( ), so that it’s possible to adjust the position of the points in the projection! This may open a can of worms, though, especially if the same code is used to generate drawings using different projections and/or different Focuses .

[LDF 2003.07.13.] Made ddashed and ppen const in both versions.

968. Length argument first. ⟨ Declare draw axes ( ) 968 ⟩ ≡

void draw axes (real dist = 2.5, string pos x = , string pos y = , string pos z = , const Color &ddraw color = ∗Colors ::default color , const string ddashed = , const string ppen = , const Point &shift x = origin, const Point &shift y = origin, const Point &shift z = origin, Picture &picture = current picture);

See also section 973. This code is used in section 981.

969. ⟨ Define draw axes ( ) 969 ⟩ ≡

void draw axes (real dist , string pos x , string pos y , string pos z , const Color &ddraw color , const string ddashed , const string ppen, const Point &shift x , const Point &shift y , const Point &shift z , Picture &picture){

See also sections 970, 971, 972, and 974. This code is used in section 980.

970. Remember to change this if you change any of the defaults!

Log

[LDF 2003.04.01.] Added this section.

⟨ Define draw axes ( ) 969 ⟩ +≡ if (dist ≤ 0) dist = 2.5; if (pos x ≡ ) pos x = ; if (pos y ≡ ) pos y = ; if (pos z ≡ ) pos z = ;

971.

Log

[LDF 2003.04.01.] Added this error handling code.

⟨ Define draw axes ( ) 969 ⟩ +≡

if (pos x ≡ ∧ pos y ≡ ∧ pos z ≡ ) {

cerr ≪ ␣ ␣ ≪ endl ≪ ␣ ␣ ␣ ␣ ≪

endl ≪ endl ≪ flush; return;

}

§972  3DLDF-1.1.5.1  LENGTH ARGUMENT FIRST 267

972. ⟨ Define draw axes ( ) 969 ⟩ +≡

if (pos x ≠ ) { Point x0 (−dist ); Point x1 (dist ); x0 .drawarrow (x1 , ddraw color , ddashed , ppen, picture); x1 += shift x ; x1 .label ( , pos x , false, picture);

} if (pos y ≠ ) {

Point y0 (0, −dist ); Point y1 (0, dist ); y0 .drawarrow (y1 , ddraw color , ddashed , ppen, picture); y1 += shift y ; y1 .label ( , pos y , false, picture);

} if (pos z ≠ ) {

Point z0 (0, 0, −dist ); Point z1 (0, 0, dist ); z0 .drawarrow (z1 , ddraw color , ddashed , ppen, picture); z1 += shift z ; z1 .label ( , pos z , false, picture);

} return; }

973. Color argument first.

Log

[LDF 2003.05.02.] Added this function.

⟨ Declare draw axes ( ) 968 ⟩ +≡

void draw axes (const Color &ddraw color , real dist = 2.5, string pos x = , string pos y = , string pos z = , const string ddashed = , const string ppen = , const Point &shift x = origin, const Point &shift y = origin, const Point &shift z = origin, Picture &picture = current picture);

268 COLOR ARGUMENT FIRST 3DLDF-1.1.5.1 §974

974. ⟨ Define draw axes ( ) 969 ⟩ +≡

void draw axes (const Color &ddraw color , real dist , string pos x , string pos y , string pos z , const string ddashed , const string ppen, const Point &shift x , const Point &shift y , const Point &shift z , Picture &picture)

{

draw axes (dist , pos x , pos y , pos z , ddraw color , ddashed , ppen, shift x , shift y , shift z , picture); }

975. Paths and Lines.

Log

[LDF 2003.06.06.] Added this heading.

976. Get Line. Returns a Line corresponding to ∗this , if ∗this is linear. Otherwise, get line( ) returns .

Log

[LDF 2003.06.06.] Added this function.

⟨ Declare Path functions 700 ⟩ +≡ Line get line(void) const;

977. ⟨ Define Path functions 701 ⟩ +≡

Line Path ::get line(void) const {

if (is linear ( )) return points .front ( ) get line(∗(points .back ( )));

else {

    cerr ≪  ␣  ␣  ≪  ␣  ␣   ␣       ␣         ␣

≪ flush;

return ; }

}

978. Get Path. Declared in lines.web. Must be defined here, because Path is an incomplete type there.

Log

[LDF 2003.06.06.] Added this function.

⟨ Define Line functions 644 ⟩ +≡ Path Line ::get path(void) const {

Point p(position + direction);

return Path(position, p); }

979. Putting Path together.

§980  3DLDF-1.1.5.1  PUTTING PATH TOGETHER 269

980. This is what’s compiled.

⟨ Include files 6 ⟩ ⟨ Version control identifier 5 ⟩ ⟨ Define class Path 698 ⟩ ⟨ Define static class Path data members 699 ⟩ ⟨ Define Transform functions 169 ⟩ ⟨ Define Point functions 330 ⟩ ⟨ Define Plane functions 664 ⟩ ⟨ Define Path functions 701 ⟩ ⟨ Define Line functions 644 ⟩ ⟨ Define draw axes ( ) 969 ⟩ ⟨ Declare non-member template functions for Path 724 ⟩

270  PUTTING PATH TOGETHER  3DLDF-1.1.5.1 §981

981. This is what’s written to paths.h. ⟨ 981 ⟩ ≡

⟨ Define class Path 698 ⟩

⟨ Declare draw axes ( ) 968 ⟩

⟨ Declare non-member template functions for Path 724 ⟩

982. Curves (curves.web).

Log

[LDF 2003.11.12.] Removed the version control identifiers from the CWEB files for the distribution of 3DLDF 1.1. They’re still used in my development versions.

[LDF 2003.12.10.] Put the version control identifiers back into my release versions for 3DLDF 1.1.4. I’ve already put some of them back in, now I’m doing the rest of them. However, the release versions are now in their own RCS repository.

format Curve Path

⟨ Version control identifier 5 ⟩ +≡ static string rcs id = ␣ ␣ ␣ ␣ ␣ ␣ ␣ ;

983. Include files. ⟨ Include files 6 ⟩ +≡ #include #include #include #include #include #include #include #include #include #include #include

984. Regular closed plane curve.

Log

[LDF 2002.11.12.] Changed the name “Regular Closed Plane Curve” to “Reg Cl Plane Curve”, because the former caused too many “Overfull boxes” when running cweave.

985. Reg Cl Plane Curve class definition. A Reg Cl Plane Curve is assumed to be closed, planar, convex, and have at least 3 points. The functions that create and modify Reg Cl Plane Curves must ensure that these assumptions are correct!

[LDF 2002.11.05.] Reg Cl Plane Curve is intended to be used as a base class. No objects of type Reg Cl Plane Curve should be defined, however, it is not an abstract class, so it is possible to do so.

format Reg Cl Plane Curve Curve

⟨ Define class Reg Cl Plane Curve 985 ⟩ ≡ class Reg Cl Plane Curve : public Path { protected: Point center ;

unsigned short number of points ; public: ⟨ Declare Reg Cl Plane Curve functions 987 ⟩

§985  3DLDF-1.1.5.1  REG CL PLANE CURVE CLASS DEFINITION 271

};

This code is used in sections 1015 and 1016.

986. Returning elements and information. [LDF 2002.11.05.] The virtual functions in this section are meant to be overloaded by member functions of types derived from Reg Cl Plane Curve.

Log

[LDF 2002.11.03.] Removed Reg Cl Plane Curve ::is planar ( ). A Reg Cl Plane Curve can be manipulated into a non-planar state, so it’s safer to use the Path version, which tests whether it’s really planar or not.

987. Is quadratic. ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ ≡

inline virtual bool is quadratic( ) const {

return false; }

See also sections 988, 989, 990, 991, 992, 994, 997, 1008, 1011, 1013, and 1014. This code is used in section 985.

988. Is cubic. ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

inline virtual bool is cubic( ) const {

return false; }

989. Is quartic. ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

inline virtual bool is quartic( ) const {

return false; }

990. Get coefficients. ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

inline virtual real triple get coefficients (real, real) const {

return real triple( , , ); }

991. Solve. [LDF 2002.11.05.] This virtual function is meant to be overloaded by member functions of types derived from Reg Cl Plane Curve. ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

inline virtual pair⟨real, real⟩ solve(char, real) const {

272  LOCATION OF A POINT  3DLDF-1.1.5.1 §992

return pair⟨real, real⟩( , ); } 992. Location of a point. location( ) returns a signed short indicating the location of its Point argument with respect to the Reg Cl Plane Curve.

[LDF 2002.11.05.] TO DO: Currently, the programmer must ensure that a Reg Cl Plane Curve is planar. It might be worthwhile to check that it really is by using Path ::get normal ( ), since some manipulations may cause a Reg Cl Plane Curve to become non-planar.

[LDF 2002.11.05.] The number of Points in a Reg Cl Plane Curve must be a multiple of 4, and that the Point number of points /4 must be at 90^{∘} to Point 0. Also, ref pt can’t be Point 0.

[LDF 2003.07.16.] Reg Cl Plane Curve now has a data member named center . However, a Reg Cl Plane Curve need not have a meaningful center. Usually, when an object of a class derived from Reg Cl Plane Curve calls this function, its center will be passed as the ref pt argument. However, this need not be the case.

TO DO: Check whether it will work if pt0 .x < 0. I think it should.

[LDF 2003.06.14.] !! CHECK. Bug, when Reg Cl Plane Curve is rotated about x and z-axes only. The following values are returned if the Point is in the same plane as ∗this and this function has worked

properly:

-1 The Point lies outside the Reg Cl Plane Curve.

0 The Point lies on the perimeter of the Reg Cl Plane Curve.

1 The Point lies inside the perimeter of the Reg Cl Plane Curve.

These values are returned in cases where errors have occurred:

-2 The Point is not in the same plane as the Reg Cl Plane Curve.

-3 Something has gone terribly wrong.

-4 The normal to the Reg Cl Plane Curve has 0 magnitude, i.e., the Points on the Reg Cl Plane Curve are colinear.

-5 An error occurred in putting the Reg Cl Plane Curve in one of the major planes.

-6 The Reg Cl Plane Curve is non-planar.

Log

[LDF 2002.04.03.] Added and tested all cases. Seems to work properly.

[LDF 2002.11.12.] Added “ ” after the arguments to “ ” in the TEX code above in order to suppress a space at the beginning of the first line of the following indented paragraph. I couldn’t figure out a way of suppressing the space within the definition of (which is currently “ ” to ).

[LDF 2003.06.03.] Changed the line where Plane ::get distance( ) is called below. It now returns a real short, so “. first ” has to be added, in order to get the real value.

[LDF 2003.06.13.] Changed pt0 .epsilon( ) to Point ::epsilon( ).

[LDF 2003.06.14.] Added error handling code for the case that get plane( ) fails.

[LDF 2003.06.14.] No longer taking absolute value of the real value r0 returned by Plane ::get distance( ), since it will always be positive, anyway. Comment at place below, where I made this change.

[LDF 2003.07.01.] Added argument suppress warnings .

[LDF 2003.07.16.] Changed name of center argument to ref pt , because I’ve made center a data member of Reg Cl Plane Curve.

§993  3DLDF-1.1.5.1  LOCATION OF A POINT 273

⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡ virtual signed short location(Point ref pt , Point pt0 , const bool suppress warnings = false) const; 993. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ ≡

signed short Reg Cl Plane Curve ::location(Point ref pt , Point pt0 , const bool suppress warnings )

const

{ bool = false; /∗ true ∗/ if ( ) {

cout ≪ ␣ ;

ref pt .show ( );

pt0 .show ( ); } unsigned short orientation; const unsigned short = 0; const unsigned short = 1; const unsigned short = 2; Plane pl (get plane( )); if (pl ≡ ) /∗ LDF 2003.06.14. Added this error handling code. ∗/ {

cerr ≪  ␣  ␣  ≪
␣                  ␣  ␣  ≪  ␣  ≪ flush;

return −6; } real r0 = pl .get distance(pt0 ).first ; if (r0 > Point ::epsilon( ))

/∗ LDF 2003.06.14. Changed. r0 will always be positive, so I now longer take its absolute value. ∗/ {

if (¬suppress warnings ) cerr ≪  ␣  ␣  ≪

        ␣  ␣   ␣  ␣      ␣  ␣       ␣       ␣     ␣  ≪

␣ ≪ flush;

return −2; } Reg Cl Plane Curve copy (∗this ); if (ref pt ≠ origin) pt0 ∗= ref pt ∗= copy .shift (−ref pt ); /∗ LDF 2002.11.05. Simplified. ∗/ Point copy normal = copy .get normal ( ); if ( ) copy normal .show ( ); if (copy normal .magnitude( ) ≡ 0) {

cerr ≪ ␣ ␣ ≪

␣ ␣ ␣ ␣ ␣ ≪ flush; return −4;

} else if (fabs (copy normal .get x ( )) < Point ::epsilon( )∧fabs (copy normal .get y ( )) < Point ::epsilon( ))

{

if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ; orientation = ;

} else if (fabs (copy normal .get x ( )) < Point ::epsilon( )∧fabs (copy normal .get z ( )) < Point ::epsilon( ))

{

if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ; orientation = ;

} else if (fabs (copy normal .get z ( )) < Point ::epsilon( )∧fabs (copy normal .get y ( )) < Point ::epsilon( ))

{ if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ; orientation = ;

} else {

if ( ) cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ; Transform t1 ; t1 .align with axis (ref pt , copy .get point (0), ); copy ∗= ref pt ∗= pt0 ∗= t1 ; Point pt c4 (copy .get point (number of points /4)); Transform t2 ; t2 .align with axis (ref pt , pt c4 , ); copy ∗= ref pt ∗= pt0 ∗= t2 ; orientation = ;

} if ( ) {

cout ≪ ␣ ␣ ≪ orientation ≪ endl ≪ flush; copy .draw (Colors ::blue); copy .show ( ); ref pt .dotlabel ( ); pt0 .dotlabel ( ); pt0 .show ( );

} Transform t3 ; Point pt1 = copy .get point (0); pt1 −= ref pt ; pt1 .unit vector (true); Point x axis (1, 0, 0); Point z axis (0, 0, 1); if (orientation ≡ ∨ orientation ≡ ) {

if (pt1 ≠ x axis ∧ pt1 ≠ −x axis ) { t3 .align with axis (ref pt , pt1 , ); copy ∗= ref pt ∗= pt0 ∗= t3 ;

} } else if (orientation ≡ ) {

if (pt1 ≠ z axis ∧ pt1 ≠ −z axis ) { t3 .align with axis (ref pt , pt1 , ); copy ∗= t3 ; ref pt ∗= t3 ; pt0 ∗= t3 ;

} } real pair rr ; real pt0 v ; /∗ [LDF 2002.11.05.] Vertical. ∗/ real pt0 h; /∗ [LDF 2002.11.05.] Horizontal. ∗/ if (orientation ≡ ) {

pt0 h = pt0 .get x ( ); pt0 v = pt0 .get y ( ); } else if (orientation ≡ ) {

pt0 h = pt0 .get x ( ); pt0 v = pt0 .get z ( );

} else if (orientation ≡ ) {

pt0 h = pt0 .get z ( ); pt0 v = pt0 .get y ( );

} else {

cerr ≪  ␣  ␣  ≪
␣   ␣        ␣      ␣ ≪ orientation ≪  ␣  ≪ flush;

return −5; } rr = solve( , pt0 h); /∗ [LDF 2002.11.05.] TO DO: Explain. ∗/ if (rr .first ≡ ∧ rr .second ≡ ) {

if ( ) {

  cout ≪  ␣  ␣       ␣       ␣      ␣     ␣       ␣ ≪  ␣  ;

cout ≪  ␣  ;

} return −1;

} else if ((fabs (fabs (pt0 v )−fabs (rr .first )) < Point ::epsilon( ))∨(fabs (fabs (pt0 v )−fabs (rr .second )) <

Point ::epsilon( ))) { if ( ) {

  cout ≪  ␣  ␣  ␣       ␣      ␣     ␣       ␣ ≪  ␣  ≪
      ␣  ;

getchar ( ); } return 0;

} else if (fabs (pt0 v ) < fabs (rr .first )) {

if ( ) {

  cout ≪  ␣  ␣      ␣       ␣      ␣     ␣       ␣ ≪  ␣  ;

cout ≪  ␣  ;

getchar ( ); } return 1;

} else if (fabs (pt0 v ) > fabs (rr .first ))

/∗ This case should never occur, I believe. [LDF 2002.11.05.] Why not?? ∗/ {

if ( ) {

  cout ≪  ␣  ␣       ␣       ␣      ␣     ␣       ␣ ≪  ␣  ≪
      ␣  ;

getchar ( ); } return −1;

} else {

cerr ≪ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪ flush; getchar ( ); if ( ) cout ≪ ␣ ; return −3;

} }

See also sections 995, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1009, and 1012. This code is used in section 1015.

994. Angle point. [LDF 2003.01.05.] TO DO: Find out why this function isn’t const! ⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

virtual Point angle point (real angle);

§995  3DLDF-1.1.5.1  ANGLE POINT 277

995. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

Point Reg Cl Plane Curve ::angle point (real angle)

{

cerr ≪  ␣  ␣  ≪

        ␣       ␣        ␣       ␣    ␣ ␣     ␣          ␣   ␣ ≪

␣ ␣ ≪ flush;

return ; }

996. Intersection points. [LDF 2002.11.05.] Intersection with a line. intersection points ( ) returns a bool point pair. The bool in a bool point indicates whether the Point is on the line segment in question. If one of the bools is false, but the Point is not ≡ , then the line (as opposed to the segment) does intersect the Reg Cl Plane Curve, and the Point indicates one of the intersection points. So, intersection points ( ) can be used whether you want to restrict the intersection points to ones that are actually on a particular line segment or not.

TO DO: [LDF 2002.04.12.] In the specializations, I should check whether the intersection points are on the curve in question. I should also write a version of this for Lines, where there’s no test for whether the intersection points are on the segment, since there’s no segment.

The versions of intersection points ( ) belonging to classes derived from Reg Cl Plane Curve will most likely call on the functions described in this section, passing center as the ref pt argument. However, this need not be the case, and Reg Cl Plane Curves need not have a meaningful center . ref pt in these functions merely refers to the Point which should be placed at the origin by the transformation. [LDF 2003.07.16.]

997. Point arguments.

Log

[LDF 2003.06.20.] Rewrote this function. The perpendicular and non-parallel, non-coplanar cases are handled in exactly the same way. In these cases, there can only be one intersection point. Plane ::intersection point ( ) and Reg Cl Plane Curve ::location( ) are now used to find it, if it exists.

[LDF 2003.06.20.] The coplanar case was the one that was causing difficulty. The copy of ∗this is now always put into the x-z plane, even if it is in one of the major planes, or in a plane parallel to one of these. The advantage of this, is that it simplifies the code. The disadvantage is, that additional rotations reduce the accuracy of the calculation of the intersection points.

[LDF 2003.06.20.] Transform ::align with axis ( ) is no longer used for putting the copy of ∗this and the line into the x-z plane. It might be possible to use it, but I used Point ::angle( ) while debugging, in order to see what was happening better. It might be possible to go back to using Transform ::align with axis , but I don’t see any advantage to doing so.

[LDF 2003.06.20.] I’ve tested this function for coplanar lines for planes with various orientations. I hope that it works properly for all planes now!

[LDF 2003.07.01.] Added true as silent argument to unit vector ( ) when I call it on cross . This prevents unit vector ( ) from issuing a warning message, when cross has magnitude 0, which occurs when surface vector and pt vector are colinear. Since this case is handled correctly, the warning messages are unnecessary and distracting.

[LDF 2003.07.01.] BUG FIX: Made changes to the way on segment is used in the coplanar case. The way it was before handled certain cases wrong.

[LDF 2003.07.04.] Removed unreachable statement at end of function: return bpp. GCC didn’t complain, but the DEC compiler issued a warning.

[LDF 2003.07.16.] Changed name of center argument to ref pt , because I’ve made center a data member of Reg Cl Plane Curve.

⟨ Declare Reg Cl Plane Curve functions 987 ⟩ +≡

278 POINT ARGUMENTS 3DLDF-1.1.5.1 §997

virtual bool point pair intersection points (Point ref pt , Point p0 , Point p1 ) const;

998. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

bool point pair Reg Cl Plane Curve ::intersection points (Point ref pt , Point pt0 , Point pt1 )

const{ bool = false; /∗ true ∗/ if ( )

cout ≪ ␣ ␣ ␣ ≪ ≪ flush; bool point pair bpp = ; Plane pl = get plane( ); if ( ) pl .normal .show ( ); Point surface vector = (get point (0) − ref pt ); surface vector .unit vector (true); Point pt vector (pt1 − pt0 ); pt vector .unit vector (true); Point cross = surface vector .cross product (pt vector ); cross .unit vector (true, true); if ( ) {

surface vector .show ( );

pt vector .show ( );

cross .show ( );

pl .normal .show ( ); } short distance = pl .get distance(pt0 ).second ;

999. Degenerate cases, error handling. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

if (pt vector ≡ ∨ pl .normal ≡ ∨ pt vector ≡ origin ∨ pl .normal ≡ origin) {

cerr ≪  ␣  ␣  ≪

  ␣  ␣     ␣     ␣   ␣  ;

pt vector .show ( ); pl .normal .show ( );

cerr ≪  ␣  ≪ flush;
if (  ) cout ≪  ␣  ≪ flush;

return ; }

1000. Parallel and coplanar cases. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

§1001  3DLDF-1.1.5.1  COPLANAR CASE 279

else if (surface vector ≡ pt vector ∨surface vector ≡ −pt vector ∨cross ≡ pl .normal ∨cross ≡ −pl .normal ) { 1001. Coplanar case. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

if (distance ≡ 0) { if ( ) cout ≪ ␣ ␣ ␣ ␣ ; Transform t0 ; Reg Cl Plane Curve copy (∗this ); Point curve 0 = copy .get point (0); if ( ) {

cout ≪ ␣ ≪ endl ;

show ( );

copy .show ( );

curve 0 .show ( ); } t0 ∗= curve 0 ∗= pt0 ∗= pt1 ∗= copy .shift (−ref pt ); if ( ) {

cout ≪ ␣ ≪ endl ;

copy .show ( );

curve 0 .show ( );

pt0 .show ( );

pt1 .show ( ); } if (curve 0 .get x ( ) < 0) {

t0 ∗= curve 0 ∗= pt0 ∗= pt1 ∗= copy .rotate(0, 0, 180); } if ( ) {

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ;

copy .show ( );

curve 0 .show ( );

pt0 .show ( );

pt1 .show ( ); } Point trace x z 0 = curve 0 ; trace x z 0 .shift (0, −(curve 0 .get y ( ))); Point x axis pt (1); real ang = trace x z 0 .angle(x axis pt ); if ( ) {

cout ≪ ␣ ␣ ≪ ang ≪ endl ≪ flush; } if (ang ≠ 0) {

if (curve 0 .get z ( ) > 0) ang ∗= −1;

t0 ∗= curve 0 ∗= pt0 ∗= pt1 ∗= copy .rotate(0, ang ); } if ( ) {

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ; copy .show ( ); curve 0 .show ( ); pt0 .show ( ); pt1 .show ( );

280  COPLANAR CASE  3DLDF-1.1.5.1 §1001

} ang = curve 0 .angle(x axis pt ); if (ang ≠ 0) {

if (curve 0 .get y ( ) > 0) ang ∗= −1;

t0 ∗= curve 0 ∗= pt0 ∗= pt1 ∗= copy .rotate(0, 0, ang ); } if ( ) {

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ; copy .show ( ); pt0 .show ( ); pt1 .show ( );

} Point curve 4 = copy .get point (number of points /4); Point z axis pt (0, 0, 1); ang = curve 4 .angle(z axis pt ); if ( ) {

curve 4 .show ( );

cout ≪ ␣ ␣ ≪ ang ≪ endl ≪ flush; } if (ang ≠ 0) {

if (curve 4 .get y ( ) > 0) ang ∗= −1;

t0 ∗= curve 4 ∗= pt0 ∗= pt1 ∗= copy .rotate(ang ); } if ( ) {

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ≪ endl ; copy .show ( ); curve 4 .show ( ); pt0 .show ( ); pt1 .show ( );

} if ( ) {

copy .draw (Colors ::blue);

pt0 .draw (pt1 , Colors ::black , );

for (int i = 0; i < 16; i += 4) copy .get point (i).dotlabel (i); #if 0

pt0 .dotlabel ( );

pt1 .dotlabel ( );

copy .get center ( ).dotlabel ( ␣ ); #endif

draw axes ( ); } real pt0 h = pt0 .get x ( ); real pt0 v = pt0 .get z ( ); real pt1 h = pt1 .get x ( ); real pt1 v = pt1 .get z ( ); /∗ pt1 v isn’t used. Leaving it here, just in case. [LDF 2003.08.27.] ∗/ real Slope = pt1 .slope(pt0 , , ); if ( ) cout ≪ ␣ ␣ ≪ Slope ≪ endl ≪ flush; real pair rr ; /∗ BEGIN ∗/ 1002. Slope is 0 (line is horizontal). ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

if (Slope ≡ 0) /∗ v is known, h is unknown. ∗/ {

if ( ) {

cout ≪ ␣ ␣ ≪ endl ≪ flush; } rr = solve( , pt0 v ); if (rr .first ≠ ) {

bpp.first .pt .set (rr .first , 0, pt0 v ); } else bpp.first .pt = ; if (rr .second ≠ ) {

bpp.second .pt .set (rr .second , 0, pt0 v ); } else bpp.second .pt = ; if ( ) {

bpp.first .pt .show ( ); bpp.second .pt .show ( );

} } /∗ End Slope ≡ 0. ∗/

1003. Slope is undefined (line is vertical). ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

else

if (Slope ≡ ) {

if ( ) {

cout ≪ ␣ ␣ ; } rr = solve( , pt1 h); if (rr .first ≠ ) {

bpp.first .pt .set (pt0 h, 0, rr .first ); } else bpp.first .pt = ; if (rr .second ≠ ) {

bpp.second .pt .set (pt0 h, 0, rr .second ); } else bpp.second .pt = ;

}  /∗ End Slope ≡  . ∗/

1004. Slope ∈ real is defined and ≠ 0. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

else { real v intercept ; v intercept = pt0 v − (Slope ∗ pt0 h); if ( ) cout ≪ ␣ ␣ ≪ v intercept ≪ endl ≪ flush; real triple coeffs = get coefficients (Slope, v intercept ); /∗ New h-values. ∗/ if (is quadratic( )) {

if ( ) {

cout ≪ ␣ ≪ flush; } rr = solve quadratic(coeffs .first , coeffs .second , coeffs .third );

} else {

cout ≪ ␣ ␣ ␣ ≪ ␣ ␣ ␣ ␣ ≪ flush; } real v coord ; if (rr .first ≠ ) {

v coord = (Slope ∗ rr .first ) + v intercept ;

bpp.first .pt .set (rr .first , 0, v coord ); } else bpp.first .pt = ; if (rr .second ≠ ) {

v coord = (Slope ∗ rr .second ) + v intercept ;

bpp.second .pt .set (rr .second , 0, v coord ); } else bpp.second .pt = ;

} 1005. Common code for the “coplanar” case. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

bool real on segment ; if (bpp.first .pt ≡ ) {

on segment .first = false;

on segment .second = ; } else on segment = bpp.first .pt .is on segment (pt0 , pt1 ); if ( ) {

cout ≪ ␣ ␣ ≪ on segment .first ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ on segment .second ≪ endl ≪ flush;

} if (on segment .first ≡ true) bpp.first .b = true; else bpp.first .b = false; Transform t inverse; t inverse = t0 .inverse( ); if (bpp.first .pt ≠ ) {

if ( ) cout ≪ ␣ ≪ flush;

bpp.first .pt ∗= t inverse; } else {

if ( ) cout ≪ ␣ ␣ ≪ flush; } if (bpp.second .pt ≡ ) {

on segment .first = false;

on segment .second = ; } else on segment = bpp.second .pt .is on segment (pt0 , pt1 ); if (on segment .first ≡ true) bpp.second .b = true; else bpp.second .b = false; if ( ) {

cout ≪ ␣ ␣ ≪ on segment .first ≪ endl ≪ flush; cout ≪ ␣ ␣ ≪ on segment .second ≪ endl ≪ flush;

} if (bpp.second .pt ≠ ) {

if ( ) cout ≪ ␣ ≪ flush; bpp.second .pt ∗= t inverse;

} else {

bpp.second .pt = ;

if ( ) cout ≪ ␣ ␣ ≪ flush; } if ( ) {

cout ≪ ␣ ␣ ≪ rr .first ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ rr .second ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ bpp.first .b ≪ endl ≪ flush;

cout ≪ ␣ ␣ ≪ bpp.second .b ≪ endl ≪ flush;

bpp.first .pt .show ( );

bpp.second .pt .show ( ); } return bpp; } /∗ End of coplanar case. ∗/

284  PARALLEL CASE  3DLDF-1.1.5.1 §1006

1006. Parallel case. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

else {

cerr ≪  ␣  ␣  ≪

    ␣   ␣                  ␣   ␣  ␣        ␣  ≪

␣ ␣ ␣ ≪ endl ≪ endl ≪ flush; return ;

} } /∗ End of parallel and coplanar cases. ∗/

1007. Perpendicular and non-coplanar cases. [LDF 2003.06.13.] These cases are handled in exactly the same way. ⟨ Define Reg Cl Plane Curve functions 993 ⟩ +≡

else {

if (pl .normal ≡ pt vector ∨ pl .normal ≡ −pt vector ) {

if ( )

cout ≪ ␣ ␣ ␣ ␣ ␣ ␣ ≪ ≪ flush; } else {

if ( )

cout ≪ ␣ ␣ ␣ ␣ ␣ ≪ ␣ ≪ flush; } bool point bp = pl .intersection point (pt0 , pt1 ); if ( ) {

bp.pt .show ( ); } short s = location