## OVERVIEW

The 3d-canvas widget is a Tk widget that provides a way to draw and
manipulate three-dimensional scenes. It is in many ways similar to the core
canvas widget that provides for two-dimensional drawing.

The actual rendering of a scene is done by the systems OpenGL library.

The X-Y-Z coordinate system used is the same as that used OpenGL.

## TECHNICAL SCOPE

Superficially, the 3dcanvas widget is a Tcl interface to OpenGL. The
following items roughly outline the gap between OpenGL and 3dcanvas widget
functionality. These are things that will have to be implemented as part of
the widget itself:

* Normal vectors. OpenGL requires that normal vectors be supplied for
  surfaces to work correctly with lighting effects. 3dcanvas calculates
  these automatically where required.

* 3dcanvas stores the current scene (primitives, lighting and camera
  position data) internally. The internal representation of the scene can
  be manipulated by the user at any time. For example, a transformation may
  be applied to a subset of scene primitives. 3dcanvas keeps the rendering
  up to date with the internal model by issuing OpenGL calls. The scene can
  be manipulated in the following ways:

    + Lighting elements may be added.
    + Lighting elements may be deleted.
    + Primitives may be added.
    + Primitives may be deleted.
    + Transformations may be applied to primitives.
    + Other properties of primitives may be modified (surface mode etc.)
    + The camera orientation and other properties may be changed.

* Primitives and lighting elements may be referenced by a unique 'id'
  assigned by 3dcanvas when the primitive/element is created. Groups of
  primitives may be collectively referenced by 'tag groups'. A primitive
  may be added to or removed from a tag group at any time. Referring to
  primitives using either ids or tags must be fast, even when there are
  many primitives or tag groups. (i.e. tags must use an index of some
  description).

* Geometric functions. The current location of a given primitive or set of
  primitives in three-dimensional may be queried as follows:

    + It is possible to query for the bounding sphere of a primitive or set
      of primitives. The bounding sphere is the smallest possible sphere
      that entirely encompasses the primitive or primitives.
    + Given 2-dimensional viewport (widget) coordinates, it is possible to
      query for the list of primitives which encapsulate the specified
      point when projected onto the 2-d viewport. The returned list is
      sorted based on distance from the camera point, closest to furthest.
      Hence, the first element of the queried list is the primitive visible
      at the specified viewport coordinates. This kind of query doesn't
      need to be very fast (i.e. can do a complete scan of all primitives,
      doesn't need an index).

  This feature complicates the internal model a bit, because the widget has
  to know where in three-dimensional space things lie after transformations
  have been applied, and how this maps into two dimensional space. It's not
  clear right now how much OpenGL will help us with this (see gluProject(),
  gluUnProject()). This is potentially a big deal.

* Tag group, id and line-of-sight queries may be combined into complex
  expressions using AND, OR, NOT and XOR operators. Such expressions can be
  used by all commands that refer to sets of primitives in the internal
  model (i.e. transformations, setting other properties, deleting
  primitives).

* New primitive types (macros) can be created in terms of the existing
  primitives. Primitive types created using the macro command behave in the
  same way as the built-in primitive types. It is not possible to refer to
  the constituent primitives of a macro primitive seperately.

* OpenGL has a couple of restrictions on polygons: (a) the polygon
  may not be convex, and (b) all points of a polygon must lie on a common
  plane. Maybe we should look at ways of decomposing all polygons into
  triangles internally to get around this. Or not support a polygon
  primitive, just offer triangle.

## INTERFACE

3dcanvas NAME ?OPTIONS?

NAME configure ?OPTIONS?
NAME cget OPTIONS

    Standard stuff.

NAME create surface COORDS ?OPTIONS?
NAME create polygon COORDS ?OPTIONS?
NAME create line COORDS ?OPTIONS?
NAME create point COORDS ?OPTIONS?
NAME create light COORDS ?OPTIONS?
NAME create macro ?OPTIONS?

NAME copy ID

NAME camera center ?X Y Z?
NAME camera direction ?X Y Z?
NAME camera location ?X Y Z?
NAME camera vantagepoint B-SPHERE
NAME camera sightline X Y
NAME camera viewingangle ?DEGREES?
NAME camera pan X Y Z

NAME itemconfigure TAGORID OPTIONS
NAME itemcget TAGORID OPTION
NAME addtag SEARCH TAG-TO-ADD
NAME dtag TAGORID TAG-TO-DELETE
NAME find SEARCH
NAME delete TAGORID...
NAME boundingsphere TAGORID
NAME gettags TAGORID
NAME transform TAGORID move|rotate|scale X Y Z ...
NAME type TAGORID

TRANSFORM ::= move|rotate|scale X Y Z ?TRANSFORM?

TAGORID ::= all
TAGORID ::= ID
TAGORID ::= TAG
TAGORID ::= ( TAGORID )
TAGORID ::= TAGORID || TAGORID
TAGORID ::= TAGORID && TAGORID
TAGORID ::= TAGORID ^ TAGORID
TAGORID ::= ! TAGORID

SEARCH ::= withtag TAGORID
SEARCH ::= all
SEARCH ::= sightline X Y
SEARCH ::= SEARCH and SEARCH
SEARCH ::= SEARCH or SEARCH
SEARCH ::= not SEARCH
