Implementing the Object Functions
For this Creating a new Graphic Object Class, you created a header file that declares the new class and the necessary overloaded member functions.
This section explains the code for the functions implemented in the file shadellp.cpp.
computeInvertedPalette Member Function
void ShadowEllipse::computeInvertedPalette() { IlvPalette* newPalette = getDisplay()->getInvertedPalette(getPalette()); newPalette->lock(); if (_invertedPalette) _invertedPalette->unLock(); _invertedPalette = newPalette; } |
The member function computeInvertedPalette computes the inverted palette from the one we get by means of the call to the member function getPalette. We create this inverted palette, unlock the previous one (if there was one), and lock the new one.
This function is called whenever the original palette is modified (by overloading the appropriate member functions), and when the object is originally created.
Creating this second palette may seem strange. In the member function draw, the second palette is used only when calling two IlvDisplay drawing member functions. Another method could have been to call the member function invert before we call these member functions and then bring the palette to its original state by another call to invert. Developing with Views shows that this is not an efficient way of manipulating objects. Palette management is one of the very efficient tasks performed by Views and you should not hesitate to use palette management when needed.
Destructor
ShadowEllipse::~ShadowEllipse() { _invertedPalette->unLock(); } |
In the destructor, we need to release the inverted palette to the display, so it can be deleted if not used by any other object.
draw Member Function
The member function draw fills the two ellipses, then draws the topmost ellipse border. The global bounding rectangle (_rect) actually covers both ellipses.
Now we can show the member function draw. It demonstrates that drawing an object is merely a call to some of the primitive member functions of the IlvDisplay class:
void
ShadowEllipse::draw(IlvPort* dst, const IlvTransformer* t,
const IlvRegion* clip) const
{
// Transform the bounding rectangle ______________________________
IlvRect rect = _rect;
if (t)
t->apply(rect);
// Set the gradient bounding box _________________________________
IlvGradientGraphicBBoxManager(palette,
IL_CONSTCAST(ShadowEllipse*, this),
t);
// Store both the display and palette ____________________________
IlvPalette* palette = getPalette();
// Find a correct value for thickness ____________________________
IlUShort thickness = _thickness;
if ((rect.w() <= thickness) || (rect.h() <= thickness))
thickness = IlMin(rect.w(), rect.h());
// Compute actual shadow rectangle _______________________________
rect.grow(-thickness, -thickness);
IlvRect shadowRect = rect;
shadowRect.translate(thickness, thickness);
#if defined(USE_2_PALETTES)
// Set the clipping region for both palettes _____________________
if (clip) {
palette->setClip(clip);
_invertedPalette->setClip(clip);
}
// Set the gradient bounding box _________________________________
IlvGradientGraphicBBoxManager(_invertedPalette,
IL_CONSTCAST(ShadowEllipse*, this),
t);
// Fill shadow Ellipse ___________________________________________
dst->fillArc(palette, shadowRect, 0., 360.);
// Fill inverted Ellipse _________________________________________
dst->fillArc(_invertedPalette, rect, 0., 360.);
// Draw ellipse __________________________________________________
dst->drawArc(palette, rect, 0., 360.);
if (clip) {
palette->setClip();
_invertedPalette->setClip();
}
#else /* !USE_2_PALETTES */
// Set the clipping region for both palettes _____________________
if (clip)
palette->setClip(clip);
// Fill shadow ellipse ___________________________________________
dst->fillArc(palette, shadowRect, 0., 360.);
// Compute inverted palette and fill inverted ellipse ____________
palette->invert();
dst->fillArc(palette, rect, 0., 360.);
palette->invert();
// Draw elliptic border __________________________________________
dst->drawArc(palette, rect, 0., 360.);
// Set the clipping region for both palettes _____________________
if (clip)
palette->setClip();
#endif /* !USE_2_PALETTES */
}
We do not need the transformer t to perform our drawing work, because we want the thickness to be the same whatever the transformation is.
The clip parameter can be used when complex drawing is to take place (which is not the case here). You must reset the clipping region of all affected palettes to an empty region before you return from this function.
boundingBox Member Function
The member function boundingBox simply transforms the global bounding rectangle.
void ShadowEllipse::boundingBox(IlvRect& rect, const IlvTransformer* t) const { rect = _rect; if (t) t->apply(rect); } |
Note
The bounding box must contain the complete drawing to avoid erasing errors. |
contains Member Function
The member function contains returns IlTrue if the point is inside one of the two ellipses. All the coordinates are given in terms of the view’s coordinate system.
static IlBoolean
IsPointInEllipse(const IlvPoint& p, const IlvRect& bbox)
{
if (!bbox.contains(p))
return IlFalse;
IlUInt rx = bbox.w() / 2,
ry = bbox.h() / 2;
IlUInt dx = (p.x() - bbox.centerx()) * (p.x() - bbox.centerx()),
dy = (p.y() - bbox.centery()) * (p.y() - bbox.centery()),
rrx = rx*rx,
rry = ry*ry;
return (rrx * dy + rry * dx <= rrx * rry) ? IlTrue : IlFalse;
}
IlBoolean
ShadowEllipse::contains(const IlvPoint&, const IlvPoint& tp,
const IlvTransformer* t) const
{
IlvRect rect = _rect;
if (t)
t->apply(rect);
if ((rect.w() <= _thickness) || (rect.h() <= _thickness))
return IsPointInEllipse(tp, rect);
else {
rect.grow(-_thickness, -_thickness);
IlvRect shadowRect = rect;
shadowRect.translate(_thickness, _thickness);
return (IlBoolean)(IsPointInEllipse(tp, rect) ||
IsPointInEllipse(tp, shadowRect));
}
}
You can see that contains calls the static function IsPointInEllipse which tests whether the point parameter is inside the ellipse defined by the rectangle parameter.
applyTransform Member Function
The applyTransform member function applies the transformer to the rectangle of the graphic.
void ShadowEllipse::applyTransform(const IlvTransformer* t)
{
if (t)
t->apply(_rect);
}