This section provides information on IMGraphic subclasses, attributes and bundles, transformations and bounds.
To provide application specific behavior, you can create concrete IMGraphic subclasses. The following are the two most common ways to derive classes from IMGraphic:
In addition to these two approaches, you can derive classes to create application specific subclasses, building application specific behavior into each of the subclasses. This is the most flexible approach. Use it to make classes more efficient for your specific applications.
NOTE: All concrete subclasses of IMGraphic must define, at minimum, the following pure virtual member functions:
virtual void draw(IGrafPort&) const = o;
virtual void transformBy(const IGrafMatrix&) = 0;
virtual IGRect2D geometricBounds() const = 0;
In addition to these mandatory member functions, subclasses should override some of the base implementations for performance gains, for example, translateBy, rotateBy, scaleBy, and so on.
The properties that determine how a 2D graphic is drawn, such as fill color, frame color, and pen width, are called attributes. There are a number of classes for creating attribute bundles. Attribute bundles are instantiated and passed to a graphic to define the attributes for a particular graphic. If a graphic does not have an attribute bundle, the default graphic state of the root drawing port defines the graphic's attributes. See "2D Graphics Attributes and Bundles" for a detailed discussion of attributes.
The graphic bundle is heavyweight, so it is expensive to copy. Use adoptBundle() and orphanBundle() semantics when changing and modifying the IMGraphic bundle. These semantics limit applications to create objects on the heap only. Once adopted, the IMGraphic object takes full responsibility to properly destroy the bundle when the IMGraphic object is destroyed.
To modify an attribute of an IMGraphic object:
This process keeps the IMGraphic base class simple and avoids duplicating IGrafBundle functions.
The IMGraphic base class provides default implementations for all bundle related member functions. Subclasses need not override this functionality, unless they have an attribute-based cache which needs to be invalidated or updated whenever the bundle is adopted and orphaned. For example, the result of looseFitBounds, when cached, needs to be invalidated (or reevaluated) when the attributes change. For performance reasons, subclasses should use lazy evaluation for rebuilding the caches.
IMGraphic has functions to adopt, browse, and orphan bundles.
Transformation is the process of altering every point in a graphic to resize (scale), reorient (rotate), or move (translate) the graphic.
Transformations can alter an IMGraphic's shape (by scaling and perspective transformation) and position (by rotating and moving). The transformation methods allow applications to change an existing IMGraphic's shape and location without having to recreate the IMGraphic.
IMGraphic transformation functions, translateBy, rotateBy, and scaleBy, provided for convenience and performance, let you transform a 2D graphic without using a matrix. You supply the values, and functions' default implementations create a temporary matrix and call the transformBy function, which takes an instance of IGrafMatrix as a parameter. Subclasses should override the default implementations to optimize for specific geometry and usage. Transformations change the points of the 2D geometry directly (except in the case of IEllipse) without copying the original points. IGrafMatrix is a 3-by-3 matrix for performing algebraic operations on a set of coordinate points (regular points, rational points, or vectors) that define a 2D graphic. IGrafMatrix is described at length in "2D Graphics Transformations."
The figure displays a star undergoing various transformations:
Subclasses of IMGraphic can implement these transformations in two ways:
All IMGraphic subclasses are "closed" to arbitrary transformations. An IGPolygon2D, when transformed by an arbitrary transformation, is still remains an IGPolygon2D. However certain 2D graphics geometries do not possess this closure property. For example, an IGRect2D when transformed by a perspective matrix is no longer a rectangle, and has no meaning of either width or height. The original specification of the rectangle (top left and the bottom right corner) are not sufficient to describe the transformed version of the rectangle. (IMGraphic does not support IRect for precisely this reason, however an IGRect2D can be represented by an IGPolygon2D.) All IMGraphic subclasses must be closed to arbitrary transformations.
All transformations applied are relative; you cannot "untransform" a transformed IMGraphic by passing an identity matrix to the IMGraphic member function transformBy(). If your application must be capable of undoing the last transformation, transform the IMGraphic object by the inverse of the matrix used for the relative transformations. For example, undo transformBy(matrix) by the call transformBy (matrix.invert()) or rotateBy(30.0) by rotateBy(-30.0). The matrix must be invertible and round-off errors can occur.
All 2D graphics classes have bounds. The bounds of a graphic are defined by the smallest IGRect2D that encloses the geometry of the graphic.
The IMGraphic inquiry member functions allow you to inquire about certain specific properties of the graphics object without modifying the object itself. Any graphical representation of a geometry has at least two different types of bounds:
The most common use of the inquiry functions is to detect whether a graphic is selected (hit or picked). The geometricBounds and looseFitBounds functions are fast and suitable when speed is more important than accuracy.
The 2D Graphics framework uses both the supported bounds inquiry member functions frequently, so the functions must be fast and efficient. Your concrete subclasses should cache these bounds if computing them is expensive.
These methods do not follow the strict guidelines of bit wise consts and are labeled as abstract const methods. Because they are abstract consts, they are unsafe when stored either in shared memory or in ROM (specially used for servers).
This figure displays the IMGraphic used in discussions of bounds mechanisms:
![]()