Reputation: 3
I have came across this sticky situation here so basically I am asked to write a function that should return a pointer to a figure if the point I clicked lies in the figure and null if the point doesn't lie in any figure.
CFigure *ApplicationManager::GetFigure(int x, int y) const
{
//If a figure is found return a pointer to it.
//if this point (x,y) does not belong to any figure return NULL
int c = 0;
for (size_t i = 0; i < FigCount; i++)
{
if (dynamic_cast<CRectangle*> (FigList[i]))
{
CFigure* basepointer = FigList[i];
Point A = static_cast<CRectangle*>(basepointer)->GetCorner1();
Point B = static_cast<CRectangle*>(basepointer)->GetCorner2();
if ((x>=A.x && x<=B.x) || (x<=A.x && x>=B.x))
{
if ((y >= A.y && x <= B.y) || (y <= A.y && x >= B.y))
{
c++;
}
}
}
else if (dynamic_cast<CCircle*> (FigList[i]))
{
CFigure* basepointer = FigList[i];
Point A = static_cast<CCircle*>(basepointer)->getCntr();
int B = static_cast<CCircle*>(basepointer)->GetRadius();
double distance = sqrt(pow((x - A.x), 2) + pow((y - A.y), 2));
if (distance<=(double)B)
{
c++;
}
}
else if (dynamic_cast<CLine*> (FigList[i]))
{
CFigure* basepointer = FigList[i];
Point A = static_cast<CLine*>(basepointer)->getPoint1();
Point B = static_cast<CLine*>(basepointer)->getpoint2();
double distance1 = sqrt(pow((x - A.x), 2) + pow((y - A.y), 2)); //Distance from point to P1
double distance2 = sqrt(pow((x - B.x), 2) + pow((y - B.y), 2)); //Distance from Point to P2
double distance3 = sqrt(pow((B.x - A.x), 2) + pow((B.y - A.y), 2)); //Distance from P1 to P2
if (distance1+distance2==distance3)
{
c++;
}
}
else
{
CFigure* basepointer = FigList[i];
Point p1 = static_cast<CTriangle*>(basepointer)->getp1();
Point p2 = static_cast<CTriangle*>(basepointer)->getp2();
Point p3 = static_cast<CTriangle*>(basepointer)->getp3();
float alpha = (((float)p2.y - (float)p3.y)*((float)x - (float)p3.x) + ((float)p3.x - (float)p2.x)*((float)y - (float)p3.y)) /
(((float)p2.y - (float)p3.y)*((float)p1.x - (float)p3.x) + ((float)p3.x - (float)p2.x)*((float)p1.y - (float)p3.y));
float beta = (((float)p3.y - (float)p1.y)*((float)x - (float)p3.x) + ((float)p1.x - (float)p3.x)*((float)y - (float)p3.y)) /
(((float)p2.y - (float)p3.y)*((float)p1.x - (float)p3.x) + ((float)p3.x - (float)p2.x)*((float)p1.y - (float)p3.y));
float gamma = 1.0f - alpha - beta;
if (alpha>0 && beta>0 && gamma >0)
{
c++;
}
}
}
///Add your code here to search for a figure given a point x,y
if (c==0)
{
return NULL;
}
}
as you can see, I haven't decided on what to return yet, but my question is using dynamic cast the optimum solution here?
-CLine,CTriangle,CRectangle and CCircle are all derived classes from CFigure
Upvotes: 0
Views: 93
Reputation: 48665
You can use virtual functions to move the processing into each derived type rather than testing the types to decide how to process them.
Instead of doing this:
struct B {};
struct D1: B {};
struct D2: B {};
// ...
void func(B* b)
{
int c = 0;
if(dynamic_cast<D1*>(b))
{
// do D1 stuff
c = ...
}
else if(dynamic_cast<D2*>(b))
{
// do D2 stuff
c = ...
}
}
You should aim to have each sub-type know how to calculate itself:
struct B { virtual int calc() = 0; }; // virtual function calls derived type
struct D1: B { int calc() override { int c = 0; /* D1 calculation */ return c; } };
struct D2: B { int calc() override { int c = 0; /* D2 calculation */ return c; } };
// ...
void func(B* b)
{
int c = b->calc(); // virtual means the correct type's function is used
}
Upvotes: 0
Reputation: 33982
In class CFigure
add
virtual bool isclicked(int x, int y) = 0;
This is a pure virtual function. All subclasses of CFigure
must implement it. The subclass's implementation checks whether or not the click was inside its bounds and returns true or false accordingly.
The reduces ApplicationManager::GetFigure
to something like
CFigure *ApplicationManager::GetFigure(int x, int y) const
{
for (size_t i = 0; i < FigCount; i++)
{
if (FigList[i]->isclicked(x,y))
{
return FigList[i];
}
}
return nullptr;
}
Through the magic of virtual functions and polymorphism, the program will figure out which subclass's isclicked
function needs to be called with no further effort on your part.
Upvotes: 1