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);

}