Custom list.sort comparisons in C++ - c++

I have an std::list that I'm trying to sort based on some calculations. Point2D is a struct with only int no, double x, and double y;
Here's the method that contains my list.sort code:
std::vector<Point2D> GrahamScan::getSortedPointSet(std::vector<Point2D> points) {
Point2D lowest = getLowestPoint(points);
std::list<Point2D> list;
for (int i = 0; i < (int)points.size(); i++) {
list.push_back(points[i]);
}
list.sort(compare_points);
std::vector<Point2D> temp;
for (int i = 0; i < (int)list.size(); i++) {
temp.push_back(list.front());
list.pop_front();
}
return temp;
}
And here's the compare_points method I wrote:
bool GrahamScan::compare_points(const Point2D& a, const Point2D& b) {
if (a.x == b.x && a.y == b.y) {
return false;
}
double thetaA = atan2((long)a.y - lowest.y, (long)a.x - lowest.x);
double thetaB = atan2((long)b.y - lowest.y, (long)b.x - lowest.x);
if (thetaA < thetaB) {
return false;
}
else if (thetaA > thetaB) {
return true;
}
else {
double distanceA = sqrt((((long)lowest.x - a.x) * ((long)lowest.x - a.x)) +
(((long)lowest.y - a.y) * ((long)lowest.y - a.y)));
double distanceB = sqrt((((long)lowest.x - b.x) * ((long)lowest.x - b.x)) +
(((long)lowest.y - b.y) * ((long)lowest.y - b.y)));
if (distanceA < distanceB) {
return false;
}
else {
return true;
}
}
}
The error Visual Studio is spitting out at me is "GrahamScan::compare_points":non-standard syntax; use '&' to create a pointer to member"
I don't have much experience in C++, but I'm trying to convert some Java code that uses a TreeSet to C++ and this is my attempt.
Any assistance would be appreciated.

If you want to keep compare_points in GrahamScan namespace you need to make it static:
static bool GrahamScan::compare_points
The reason the compiler complains is that compare_points is a member function. It needs a GrahamScan object to be applied on. Behind the curtains the real function signature of compare_points is something like bool compare_points(GrahamScan *this, const Point2D& a, const Point2D& b). So either make it static or don't define it as a member function.
Once you make compare_points static, your lowest variable will no longer be accessible to it. Easier way to work around that is to make lowest also static:
class GrahamScan
{
// declaration is inside class
static Point2D lowest;
}
// definition is outside class
Point2D GrahamScan::lowest;
and use it like this:
std::vector<Point2D> GrahamScan::getSortedPointSet(std::vector<Point2D> points)
{
GrahamScan::lowest = getLowestPoint(points);
//...
}

Related

Unexpected output zero

I'm new to C++ and currently practicing on a Singly Linked List. Somehow the output of the code below is always zero. I think the problem is the nextPoint Method but however I try to change the reference/dereference, it doesn't work.
Where is the problem? Thank you in advance.
// Singly Linked List
#include <math.h>
#include <iostream>
class Point {
public:
double x, y;
Point* next;
// constructor
Point (double x, double y) {
this->x = x;
this->y = y;
this->next = NULL;
}
void nextPoint(Point nexti) {
this->next = &nexti;
}
double dist(Point &a, Point &b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx - dy*dy);
}
double length() {
Point *iter = this;
double len = 0.0;
while (iter->next != NULL) {
len += dist(*iter, *iter->next);
iter = iter->next;
}
return len;
}
};
int main() {
Point p1(1,1);
Point p2(2,2);
Point p3(5,5);
p1.nextPoint(p2);
p2.nextPoint(p3);
std::cout << p1.length() << std::endl;
return 1;
}
Please turn on more compiler warnings and you'll probably get a warning that in nextPoint you are storing the address of a temporary variable (nexti) permanently (in this->next).
You must either pass the address of or a reference to the point to add.
void nextPoint(Point *nexti) {
this->next = nexti;
}
p1.nextPoint(&p2);
p2.nextPoint(&p3);
or
void nextPoint(Point &nexti) {
this->next = &nexti;
}
p1.nextPoint(p2);
p2.nextPoint(p3);
Side note: please replace NULL with nullptr.
There are two problems with your code:
nextPoint takes its parameter by value, which means you're storing the address of that by-value parameter which becomes invalid as soon as the execution of nextPoint ends. Change it to accept Point &nexti.
Your distance computation function is wrong. You should be adding the squares, not subtracting them: return sqrt(dx*dx + dy*dy);
Unrelated to your question, but there are several ways in which you could improve your code:
Use the mem-initialiser list in the constructor to initialise members instead of assigning to them. This is a good habit to get into, as it will come useful once you start dealing with things where initialisation and assignment are substantially different (references, classes, ...).
Point (double x, double y) : x(x), y(y), next(nullptr)
{}
Use nullptr instead of NULL, since the latter is not type-safe.
length should be marked const, because it does not modify the object on which it's called. Note that iter has likewise been changed to const Point *:
double length() const {
const Point *iter = this;
double len = 0.0;
while (iter->next != NULL) {
len += dist(*iter, *iter->next);
iter = iter->next;
}
return len;
}
dist does not use this at all, and so it could (and should) be made a static member function. Also, it should take its parameters by const &, because it doesn't modify them:
static double dist(const Point &a, const Point &b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx - dy*dy);
}

Is there any better alternative to this situation [downcasting]

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
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.
You can use virtual functions to move the processing into each derived type rather than testing the types to decide how to process them.
See Virtual Functions
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
}

Returning a class object based on two variables C++

I need help with a problem pertaining to classes. I know how to solve it but I am wondering if there is a better solution than my current idea.
Each Class Tile Object and Class Player Object has an x and y position. I would like to know if there is a way to expedite things. My current idea is if-else statements like this:
if(x==1) {
if(y==1) {
return tileone1;
} else if(y==2) {
return tileone2;
} else if(y==3) {
return tileone3;
} else if(y==4) {
return tileone4;
} else if(y==5) {
return tileone5;
} //......
} else if(x==2) {
if(y==1) {
return tiletwo1;
} else if(y==2) {
return tiletwo2;
} else if(y==3) {
return tiletwo3;
} else if(y==4) {
return tiletwo4;
} else if(y==5) {
return tiletwo5;
} //......
} //......
The problem is it would take way too long to write this for every tile.
I need a function that will return a Tile object based on the x and y input of the Object Player. Any other solution would be great as well.
Tile getTileBasedOnCoords(int x, int y){
}
There are multiple ways to achieve this. The easiest seems to be (given the question) is by putting all Tile objects into the array, and returning the one with corresponding index.
Use a map with custom keys providing x and y values. This way you have direct access to the tile without the need to compare each tile with the player position (see getSectorByCoordinate() in the following code taken from a project of mine).
struct CSectorCoordinate
{
private:
int mX;
int mY;
public:
CSectorCoordinate();
CSectorCoordinate(int aX, int aY);
bool operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const;
int getX();
int getY();
};
...
bool CSectorCoordinate::operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const
{
// note: the following conditions ensure a strict weak ordering (see documentation of std::map)
if (a.mX < b.mX)
return true;
if (b.mX < a.mX)
return false;
return a.mY < b.mY;
}
...
typedef std::map<CSectorCoordinate, Configuration::CSectorEntity *, CSectorCoordinate> CSectorCoordinateMap;
CSectorCoordinateMap mSectorCoordinateMap;
...
bool CSectorEntityConfigurationBunch::getSectorByCoordinate(int aX, int aY, Configuration::CSectorEntity * & prSector)
{
CSectorCoordinateMap::const_iterator i(mSectorCoordinateMap.find(CSectorCoordinate(aX, aY)));
if (i != mSectorCoordinateMap.end())
prSector = i->second;
else
prSector = 0;
return prSector;
}

Wrong version of overridden [] operator called in class

I have a simple two-dimensional line class which holds two vectors of doubles. I have added getValue and setValue functions, but would prefer the public interface to have the square bracket operator available alongside these functions. The following code shows the implementation and use:
#include <vector>
#include <algorithm>
#include <cassert>
class Simple2DLine
{
public:
Simple2DLine();
// Simple read method with linear interpolation
double getValue(double x) const;
// Simple write method, adds a curve point, keeping the arrays sorted
void setValue(double x, double y);
double& operator [](double x);
const double operator [](double x) const;
private:
std::vector<double> m_X;
std::vector<double> m_Y;
int getNearestIndex(double x) const;
};
Simple2DLine::Simple2DLine()
{
}
void Simple2DLine::setValue(double x, double y)
{
// Get the index of the point at or just before 'x'
int idx = getNearestIndex(x);
// Check if the exact point already exists.
if (idx >= 0)
{
if (m_X[idx] == x)
{
m_Y[idx] = y;
return;
}
else
{
// Insert adds the value just BEFORE idx, so increment it before inserting.
++idx;
m_X.insert(m_X.begin() + idx,x);
m_Y.insert(m_Y.begin() + idx,y);
return;
}
}
// Otherwise, just insert at the front.
m_X.insert(m_X.begin(),x);
m_Y.insert(m_Y.begin(),y);
}
double Simple2DLine::getValue(double x) const
{
// Make sure there are points - if not, return 0.
if (m_X.size() == 0)
{
return 0;
}
// Make sure it's not out of bounds.
if (x < m_X.front() || x > m_X.back())
{
return 0;
}
// Check if it's at or after the last point
if (x == m_X.back())
{
return m_X.back();
}
// Find the point just before the given point.
int idx = getNearestIndex(x);
// Check if we're on the exact point
if (m_X[idx] == x)
{
return m_X[idx];
}
else
{
// Find the distance from the nearest point and linearly interpolate.
double dist = x - m_X[idx];
return m_Y[idx] + dist * (m_Y[idx + 1] - m_Y[idx]) / (m_X[idx + 1] - m_X[idx]);
}
}
double& Simple2DLine::operator [](double x)
{
// Create a space for the new value
setValue(x,0.0);
int idx = getNearestIndex(x);
return m_Y[idx];
}
const double Simple2DLine::operator [](double x) const
{
return getValue(x);
}
// Returns the index of the point at or just before 'x'. Invalid values return -1.
int Simple2DLine::getNearestIndex(double x) const
{
if (m_X.empty())
{
return -1;
}
std::vector<double>::const_iterator xBegin(m_X.begin());
std::vector<double>::const_iterator xEnd(m_X.end());
// Get an iterator to the first value GREATER than our search value
std::vector<double>::const_iterator it = upper_bound(xBegin,xEnd,x);
// If the iterator is at the beginning, all values are greater
if (it == xBegin)
{
return -1;
}
// Otherwise, decrement the iterator by 1, and return its' distance from the start.
return (it - 1) - xBegin;
}
int main(int argc, char** argv)
{
Simple2DLine tda;
tda.setValue(0.0,10.0);
tda.setValue(1.0,15.0);
tda.setValue(2.0,20.0);
tda.setValue(3.0,25.0);
double tmp = tda.getValue(0.5);
assert(abs(tmp - 12.5) < 0.000001);
tmp = tda.getValue(1.5);
assert(abs(tmp - 17.5) < 0.000001);
tmp = tda.getValue(2.5);
assert(abs(tmp - 22.5) < 0.000001);
// Here, the wrong version of the overridden operator is being called.
tmp = tda[1.5];
tda[2.5] = 22.5;
}
When I access the line object in the following fashion, the correct version of the operator is called (non-const)
tda[2.5] = 22.5;
However, when I try to use the const version, as follows:
tmp = tda[1.5];
the non-const version is called. Is there an error in my implementation? Or is it not possible to access the class in this fashion?
The const version is called on const objects. So if you have an object declared like const Simple2DLine tda, const overloaded version of operator[] will be called.
Practically, you will see const objects as function parameters like:
void foo(const Simple2DLine& tda)
{
std::cout<< tda[0];
}
There you will notice const overloaded function being called.
Also your const overloaded operator[] can still return a reference.
Do you assume that automatically the const operator has to be called just because the expression containing it appears on the right side of an equation? This is not the way it works. The const version will be called if you have a const object.
You could e.g. try assigning the object to a const reference.
Simple2DLine const & tdaconst = tda;
tmp = tdaconst[1.5];
In the above code, the const version will be called.

Order: An Analysis on Point Sorting

So I've made for myself a point printing class, that is supposed to have the user enter in 2-tuples; that is, x and y, that then prints them back to the user in ^order,^ where order means p1=(x,y)
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
class Point2D {
public:
Point2D();
Point2D(double a, double b);
double getx();
double gety();
void setx(double a);
void sety(double b);
virtual void print();
virtual void print(int a);
double angle();
private:
double x;
double y;
};
bool operator<( Point2D a , Point2D b );
int main() {
double my_x=-999;
double my_y=-999;
string my_color;
double my_weight;
vector<Point2D*> points;
cout << "Welcome to Point Printer! Please insert the x-and y-coordinates for your points and I will print them in sorted order! Just one rule, the point (0,0) is reserved as the terminating point, so when you are done enter (0,0).\n";
while(true)
{
cout << "x = ";
cin>>my_x;
cout << "y = ";
cin>>my_y;
if((my_x == 0)&&(my_y==0))
{
break;
}
points.push_back(new Point2D(my_x, my_y));
}
sort(points.begin(), points.end());
cout << "\n\n";
cout << "Your points are\n\n";
for(int i=0;i<points.size();i++)
{
cout<<i+1<<": ";
(*points[i]).print(); cout<<endl; // this is the printing gadget
}
for(int i=0; i<points.size(); i++)
{
delete points[i];
}
cout << endl << endl;
return 0;
}
double Point2D::angle()
{
double Angle = atan2(y,x);
if(Angle < 0)
{
return Angle + 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
}
return Angle;
}
bool operator< (Point2D a, Point2D b)
{
if (a.getx()*a.getx()+a.gety()*a.gety() < b.getx()*b.getx()+b.gety()*b.gety())
{
return true;
}
else if (a.getx()*a.getx()+a.gety()*a.gety() > b.getx()*b.getx()+b.gety()*b.gety())
{
return false;
}
if (a.getx()*a.getx()+a.gety()*a.gety() ==b.getx()*b.getx()+b.gety()*b.gety())
{
if (a.angle() < b.angle())
{
return true;
}
else if (a.angle() > b.angle())
{
return false;
}
}
return true;
}
Point2D::Point2D() { x = 0; y = 0; return;}
Point2D::Point2D(double a, double b) { x = a; y = b; return;}
double Point2D::getx() { return x;}
double Point2D::gety() { return y;}
void Point2D::setx(double a) { x = a; return; }
void Point2D::sety(double b) { y = b; return; }
void Point2D::print() {
cout<<"("<<x<<","<<y<<")";
return;
}
void Point2D::print(int a) {
print(); cout<<endl;
}
What I'm having trouble with is either one of the following:
sort
angle()
operator<(Point2D a, Point2D b)
Something different entirely...
In particular, the following points:
x = 1
y = 2
x = 2
y = 3
x = 1.1
y = 2.2
x = -10
y = 10
x = -5
y = -3
x = -5
y = 3
x = 5
y = -3
x = 5
y = 3
x = 0
y = 0
are not sorted in the correct order.
Any help would be much appreciated. Thank you.
The problem (or one of them) is the final statement in your comparison function.
return true;
Look at this block:
if (a.getx()*a.getx()+a.gety()*a.gety() ==b.getx()*b.getx()+b.gety()*b.gety())
{
if (a.angle() < b.angle())
{
return true;
}
else if (a.angle() > b.angle())
{
return false;
}
}
First of all, if we've gotten to this point, we've determined that the (x*x + y*y) calculations for both a and b are equal. Now let's assume that the angle is also equal. What happens? The first test fails because a.angle() is not less than b.angle(). Then the second test fails because a.angle() is not greater than b.angle(). Then you return true. In other words, you're saying that it is true that a is less than b, even though by all rights, they should be considered equal, and so you should return false. Instead of multiple tests on the angle, you can just return a.angle() < b.angle();, and that should do the trick. With some additional simplifications, your function should look something like this:
bool operator<(Point2d a, Point2d b)
{
double A = a.getx()*a.getx()+a.gety()*a.gety();
double B = b.getx()*b.getx()+b.gety()*b.gety();
if (A < B) return true;
if (A > B) return false;
return a.angle() < b.angle();
}
The problem is probably that you are storing and sorting pointers, not objects. The points will be compared not with your operator but their addresses. Try change points to vector<Point2d>
First of all just use (if your are just planning to sort 2D points) :
(Edit : See Benjamin Lindley comments below.)
bool operator < ( Point2D a, Point2D b)
{
return a.getx() < b.getx() ||
(a.getx()==b.getx() && a.gety()< b.gety() );
}
Another thing if use use std::cout in operator < ( Point2D a, Point2D b), you will notice it won't be called anytime.
The reason is this:
vector<Point2D*> points; // Vector of Point2D*
but bool operator< (Point2D a, Point2D b) is used for comparision.
Suggested Fixes:
vector<Point2D> points;
points.push_back(Point2D(my_x, my_y));
And accordingly, wherever applicable.
Also you can't define anything like
bool operator<(const Point2D* a, const Point2D* b)
Because of this:
C++03 standard, ยง13.5 [over.oper] p6:
An operator function shall either be a non-static member function or
be a non-member function and have at least one parameter whose type is
a class, a reference to a class, an enumeration, or a reference to an
enumeration.