TIP 164: Add Rotate Subcommand to the Canvas Widget

Login
Author:         Arjen Markus <[email protected]>
Author:         Dimitrios Zachariadis <[email protected]>
Author:         Donal K. Fellows <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        17-Nov-2003
Post-History:   
Keywords:       Tk,canvas
Tcl-Version:    8.7
Tk-Branch:      tip-164
Votes-For:      DKF, JN, FV, SL, AK
Votes-Against:  none
Votes-Present:  none

Abstract

This TIP proposes to add a rotate subcommand to the canvas widget to facilitate rotating items in very much the same way as is now possible with scaling and moving.

Rationale

The canvas currently allows a programmer to scale and move items, but the third common affine transformation, rotation, is not supported. This can in itself be simulated by a script (simply get the coordinates of all items involved, transform them and set the new coordinates), but if you have several hundreds or even thousands of items this gets very slow.

Rotation is easy for polygons and lines: simply transform the coordinates.

Implementing rotation should consider what to do with items that can not (easily) be rotated: rectangles, non-circular ovals and arcs, widgets, bitmaps and images. For the items that only define a single coordinate, the anchor point, we just transform that anchor point. (It would require major work to Tk's rendering engine to allow rotated embedded images, and rotated windows would be even more complex than that.)

For rectangles and general ovals and arcs there are two choices:

Text items can be rotated, but they are often used with rectangles to make labelled boxes so the rotation of them with respect to their anchor is left for user code. Similarly, arc items have angles associated with them for where they start and end, but it isn't clear how those should be rotated when the item itself cannot be rotated (since we don't allow choosing angles for the major and minor axes of the underlying ellipse). Circular arcs could be handled simply, but we do not detect that case.

Proposal

Canvases will have a new subcommand, rotate, which will rotate the coordinates of chosen items by a specified angle about a specified point.

canvas rotate itemOrTag x y angle

Note that most of the arguments are very similar to the canvas's scale subcommand. The angle is measured in degrees, with positive values indicating anti-clockwise rotation.

Canvas Item C API Alterations

The Tk_ItemType structure gains a new field, Tk_ItemRotateProc *rotateProc, which comes after the nextPtr field. This field allows the creator of the item type to define a callback that handles rotation; if defined as NULL, which it is by default in most existing code, then the default rotation algorithm is applied, which simply rotates the coordinate list using the coordProc.

The definition of Tk_ItemRotateProc is:

typedef void (Tk_ItemRotateProc)(
    Tk_Canvas canvas,
    Tk_Item *itemPtr,
    double originX,
    double originY,
    double angleRadians);

The canvas and itemPtr are the usual arguments for these item callbacks. The originX and originY describe the point about which rotation is to be done. The angleRadians is the amount to rotate, in radians (i.e., suitable for directly using with sin() and cos()).

Reference Implementation

See the tip-164 branch.

Future Work

Should we also consider the possibility of reflections in a line?

Should we also consider more general linear transformations (to be specified via a 2x2 matrix)? What about full affine transformations (i.e. with the translation components)?

If we implement these from the start, we need to do only a little more work.

Comments

It might be useful to utilize the -anchor Tk option in all canvas items and add a new -anchoroffset $x,$y option, where $x and $y be canvas distances relevant to the anchor position. Once defined, or with their default values, the -anchor and -anchoroffset values combined will provide the item's center, for placement and rotation purposes. Item sets, constituting symbols, can then be manipulated easily.

It could probably be beneficial to add an -angle option (and an accompanying -angleunit one), to persist a rotation angle in the configuration database. The presence of an angle value other than zero would help negate rotation, thus re-instating the item to its initial orientation.

Copyright

This document is placed in the public domain.