And further...

For type checking of point parameters, you are allowed to use the SET-POINT?-! primitive to change the point type. For instance, the following code would allow points to be a pair of real (this is done automatically when you use SET-WORLD!).


(define (real-point point) ; Type-checking for points 

(and (pair? point)
(number? (car point))
(number? (cdr point))))

(set-point?-! real-point) ; Use the real-coordinates system

Now imagine you want to draw a bar chart using an exponential scale. Instead of adding a call to the LOG function before each call to BGI routine, you can define your own coordinates-conversion function. Call SET-COORDINATES! with three functions as parameters, one extracting the device's X-coordinate from a point, one extracting the Y-coordinate, and the reverse procedure which returns the point corresponding to given device coordinates:



(set-coordinates! my-x my-y reverse-xy) 
(define (my-x point) 		 ; X-coord scaled from 0 to 1 

(round ; Return a whole number
(* (car point) ; Multiply the given X-coordinate...
(car (get-max-xy))))) ; ...by the maximum X-coordinate

(define (my-y point) ; Y-coord log: 1 (bottom) to 1000
(round ; Return a whole number
(* (- 1 (log (cdr point) 1000)) ; Log of reversed y-coordinate...
(cdr (get-max-xy))))) ; ...times the maximum y-coordinate

(define (reverse-xy xy) ; Reverse procedure, used when BGI
(let ((max-xy (get-max-xy))) ; wants to return a coordinate
(cons ; Return a point (a pair)
(/ (car xy) (car max-xy))
(expt 1000 (- 1 (/ (cdr xy) (cdr max-xy)))))))

(set-coordinates! my-x my-y reverse-xy) ; Use the vertical-logarithmic system

Don't forget to call SET-POINT?-!, because SET-COORDINATES! won't call it for you (the example above assumes you've already typed in the SET-POINT?-! example).

Note that using this coordinate system, the same call to a function such as LINE-REL can have different results, depending on where the pen is:



(move-to {\itt '(0.5 .\ 100)}) 
(move-to {\itt '(0.5 .\ 1)}) 

(line-rel {\itt '(0 .\ 10)}) ; length = 1/3 of total height

(move-to {\itt '(0.5 .\ 100)}) ; goes up into log scale...
(line-rel {\itt '(0 .\ 10)}) ; length = 1/72 of total height

Of course, you don't need to assume that a point is a pair; why not a list of numbers, in a three- or four-dimensional space? Just write the functions that extract a projection out of a vector, and you're done!

Do you like Euclid? If you don't, you can also define how to calculate distances, almost the same way you defined the coordinates. SET-DISTANCES! accepts three parameters: the X distance extractor, the Y distance extractor and the unary distance extractor. These three functions receive the point from which the distance is to be calculated and the user-desired distance. X & Y distances are used for the following functions: MOVE-REL, LINE-REL, ELLIPSE, FILL-ELLIPSE and SECTOR, while the unary distance is used by ARC, CIRCLE and PIE-SLICE (``unary'' means that the function receives distances as a number and returns a number; while X and Y distances receive a fictive point which is the displacement between two points).

All these coordinate-manipulation primitives return the previous version of all the procedures they change, so you can restore them later. In particular, SET-WORLD! returns all of seven procedures, in the order POINT?, X, Y, REVERSE-XY, X-DIST, Y-DIST, and UNARY-DIST; and all can be restored in one single call to RESTORE-WORLD!:



(let ((old-sys (set-world! {\itt '(0 .\ 0)} {\itt '(1 .\ 1)}))) ; change and remember 

...
(restore-world! old-sys))

If you want to restore procedures by yourself, note the following example:



(let* ((old-sys (set-world! {\itt '(0 .\ 0)} {\itt '(1 .\ 1)})) ; change and remember 

(old-point? (car old-sys))
(old-coord (cdr old-sys))
(old-dist (cdddr old-coord)))
...
(set-point?-! old-point?)
(set-coordinates! (car old-coord) (cadr old-coord) (caddr old-coord))
(set-distances! (car old-dist) (cadr old-dist) (caddr old-dist))

Always restore procedures in this order, since SET-COORDINATES! modifies the distance-functions to adapt them to the new given system.