/* TEACH GO_LOCATED                             Ben Rabau, 27th Aug 1993

This file refers to located objects in Poplog/GO. This is the most basic
mixin which allows objects to have a location of their own. A special
case is a screen object which can also be represented on the screen (see
TEACH * GO_SCREEN_OBJECT).

Most of this teach file will use screen objects of the go_polygon class
( see TEACH * GO_POLYGON ) to demonstrate the concepts of the go_located
mixin. Extra indications are given where methods of the go_screen_object
class or go_polygon class are used.

For more general detailed information see

HELP * GO
REF * GO

 */

/*
-- Introduction -------------------------------------------------------

A located object has its own local coordinate system. This means that
it has an origin to which all its coordinates are relative. The object
can have its own scaling and even rotation (see TEACH * GO_ROTATABLE)
which all influence the representation in the "world". These world
coordinates are the same for all objects and can therefore be used to
interchange data.

Transformations are done using:
    go_transxyout(x, y, object)        from local to world coordinates
    go_translistout(list, object)      from local to world coordinates
    go_transxyin(x, y, object)         from world to local coordinates
    go_translistin(list, object)       from world to local coordinates
Important methods are:
    go_local_coords                    in local coordinates
    go_world_coords                    in world coordinates
    go_xorigin                         in world coordinates
    go_yorigin                         in world coordinates
    go_xcentre                         in world coordinates
    go_ycentre                         in world coordinates
    go_xscale                          in degrees (-360 to 360)
    go_yscale                          in degrees (-360 to 360)

Note: The origin is expressed in world coordinates to allow the objects
coordinates to be transformed to world coordinates. The centre is the
position of the centre of the bounding box. For simplicitiy all built in
classes keep the bounding box centred around the origin. This means that
the centre is the origin after rotation, e.g. around a point (see also
TEACH * GO_ROTATABLE). For non-rotatable objects this simply means that
the centre and the origin are equal concepts.

The world coordinates can also be transformed to the final destination
which is normally a go_pane (see TEACH * GO_PANE). These coordinates are
highly device dependent and the same object can be represented simultaneously
in different panes all with their own coordinate transformations.

The same transformation methods are used: e.g.
    go_transxyout(x, y, pane)           from local to world coordinates
Important extra methods are:
    go_screen_coords                    in screen coordinates

Many simple calculations do not require the correct shape of the object
but only a rough estimate. In Poplog/GO the concept of a bounding box is
used. The bounding box is a rectangle in world coordinates which fits
around the object. The bounding box is therefore always slightly bigger
than the object itself. It is completely described by a symmetrical
width and height around the centre:
    go_xcentre                         in world coordinates
    go_ycentre                         in world coordinates
    go_bounding_width                  in world coordinates
    go_bounding_height                 in world coordinates
Convenience methods:
    go_xloc                            left corner in world coordinates
    go_yloc                            lower corner in world coordinates

Note that for rotatable objects the real bounding box is the rectangle
that fits around the object without rotation (angle zero). When rotated
the bounding box becomes big enough to encompass the real bounding box
Thus the bounding box is not always a tight fit (see TEACH * GO_ROTATABLE).

    +----+                 +--+----+
    |    |                 | /     +
    |    |                 |/     /|  (original vertical sides shown only)
    +----+                 +     / |
                           +----+--+
   original          rotated over 30 degrees


The example below tries to show that an object can have its own coordinate
system, its own world coordinate representation and several screen
coordinate representations.

 */


/*
-- Requirements -------------------------------------------------------
 */
;;; This requires the following files to be loaded:
uses go;
uses go_located;

;;; It also requires an active go_pane (see TEACH * GO_PANE and
;;; TEACH * GO_RC_WINDOW):
go_init_rc();


/*
-- Example ------------------------------------------------------------
 */
;;; Create a polygon (see TEACH * GO_POLYGON) and visualise it on the
;;; newly created go_pane (see TEACH * GO_PANE/go_add_to):

vars poly1 = newgo_polygon();
go_add_to( poly1 , go_default_pane );

;;; The local coordinate system is a perfect triangle. With the scales
;;; set to 1 and no rotation we can show it a screen:
1 -> go_scale( poly1 );               ;;; see further
1 -> go_scale( go_default_pane );     ;;; see further

;;; The world coordinates can be shown after adding some local scaling
;;; and rotation:
0.5 -> go_yscale( poly1 );            ;;; see further
45 -> go_angle( poly1 );              ;;; see further

;;; Note that local scaling didn't change the basic shape of a triangle
;;; flattened by a vertical scale (it remains a perfect needle shape).

;;; Compare this with an extra scaling to result in screen coordinates:
0.50 -> go_yscale( go_default_pane );

;;; Note that this time the shape changes! Try the following under some
;;; combinations of local scaling and scaling of the pane:
1 -> go_yscale( poly1 );
0.5 -> go_yscale( go_default_pane );
go_rotate( 360, 15, poly1 );          ;;; see REF * go_rotatable/go_rotate

/*
-- Geometry -----------------------------------------------------------
 */
;;; You can retrieve or interact with the general geometry of objects
;;; by influencing its bounding box. The dimensions of an object are
;;; always within the bounding box dimensions:
go_bounding_box( poly1 ) =>

;;; This bounding box is visualized during the go_drag operations but can
;;; also be visualized separately (belongs to GO_SCREEN_OBJECT):
go_draw_bounding_box( poly1 ) ;

;;; Make sure that the screen is restored afterwards (belongs to
;;; GO_SCREEN_OBJECT):...
go_clear_bounding_box( poly1 ) ;

;;; You can also retrieve the width or go_bounding_height of an object
;;; directly:
go_bounding_width( poly1 ) =>
go_bounding_height( poly1 ) =>

;;; For all objects (including polygons) you can change the width of the
;;; bounding box immediately. This will scale the object to horizontally
;;; fit the new bounding width (see go_xscale later):
;;; WARNING: THIS CURRENTLY ONLY WORKS CORRECTLY FOR NON-ROTATED OBJECTS!
go_bounding_width( poly1 ) / 2 -> go_bounding_width(poly1);
go_bounding_width( poly1 ) * 2 -> go_bounding_width(poly1);

/*
-- scaling ------------------------------------------------------------
 */
;;; You can scale the go_polygon by changing the x or y scale:
vars poly2;
newgo_polygon() -> poly2;
go_add_to( poly2 , go_default_pane );
0.5 -> go_xscale( poly2 );
0.5 -> go_yscale( poly2 );

;;; to scale both the x and y direction at once, you can use the
;;; convenience function scale():
1 -> go_scale( poly2 );

;;; You can simulate a rotation around the Z-axes by using scaling between
;;; -1 and 1...
vars rot_angle = 0;
define fake_rotation();
    (rot_angle + 15 /* degrees */ ) mod 360 -> rot_angle;
    cos( rot_angle ) -> go_xscale( poly2 );
    1e5 -> sys_timer( fake_rotation );
enddefine;

;;; To start the rotation do:
1e5 -> sys_timer( fake_rotation );

;;; To end the rotation do:
false -> sys_timer( fake_rotation );


/*
-- Motion -------------------------------------------------------------
 */
;;; The reference point of an object is the centre of its bounding-box.
;;; As an extra refrence point there also is the x/y location of the
;;; start of the bounding-box. The former is better because all changes
;;; in size or shape (rotation, scaling, etc...) will keep that reference
;;; centre point constant. The x/y location of a corner of the bounding
;;; box will change however.
;;; The origin and the centre can be updated in several ways:

;;; You can move the object around by using the programmatical motion
;;; interface methods: go_position_of_centre() or go_centre_to():
go_position_of_centre( poly1 ) =>           ;;; current centre
(40, 40) -> go_position_of_centre( poly1 ); ;;; centre to x = y =  40
go_refresh();                               ;;; make changes visible

;;; Or with the active method (convenience function):
go_centre_to(100, 100,  poly1 ) ;           ;;; centre to x = y = 100
go_centre_to( 40,  40,  poly1 ) ;           ;;; centre to x = y =  40

;;; These methods are currently the only commands where the underlying
;;; slots are not active. The current value of the X- or Y-position can
;;; be retrieved by using the go_xcentre() or go_ycentre() methods:
go_xcentre( poly1 ) =>
go_ycentre( poly1 ) =>

;;; Updates to the go_xcentre() or go_ycentre() methods are not immediately
;;; reflected on the screen.
;;; This was done because these slots are frequently updated and most
;;; updates do not require the immediate update of the screen.

;;; The same exists for the origin: go_position_of_origin(), go_origin_to(),
;;; go_xorigin() and go_yorigin() methods.

;;; eof;

--- C.all/lib/proto/go/teach/go_located
--- Copyright University of Sussex 1993. All rights reserved.
