Retrieving values from map <<object>, int> exhibits strange behavior - c++

I am reproducing a problem I have with maps in a project, or which I implemented the following debugging code. I am having trouble retrieving the integer values in a map from Point2 objects as keys.
I have implemented the overloading of the Point2 objects as shown in the code. Point2 objects are ordered according to the value of _label.
The map _mapExtendedPointToIntersectionLabel gets its elements inserted successfully, but lines 116,120,124 and 128 behave strangely.They should just assign the value of the corresponding POint2 object to the corresponding variables.
-line 116 does an insertion into the map, as shown in the figure and label1 is set to 0 instead of getting its value 27;
-the other 3 lines just set the variables label2, label3 and label4 to 0 instead of to the values 17,47 and 37;
What is going on? If I am doing something wrong, how do I fix it to get the desired behavior?
class Point2
{
private:
double _coordinates[2];
int _label = -2;
public:
Point2(const double x = 0.0, const double y = 0.0){_coordinates[0]=x;_coordinates[1]=y;}
int getFirstCoordinate() const{ return _coordinates[0];}
int getSecondCoordinate() const{ return _coordinates[1];}
int getPointLabel() const{ return _label;}
void setPointLabel(const int label){_label =label;}
friend bool operator< (const Point2& p1, const Point2& p2 ){
return p1._label < p2._label;
}
Point2& operator =(const Point2 &point)
{
_coordinates[0] = point.getFirstCoordinate();
_coordinates[1] = point.getSecondCoordinate();
_label = point.getPointLabel();
return *this;
}
Point2(const Point2 &p1){
_coordinates[0]=p1._coordinates[0];
_coordinates[1]=p1._coordinates[1];
_label = p1._label;
}
};
int main(){
Point2 _intersectionVertices[4];
_intersectionVertices[0]= Point2(10,20);
_intersectionVertices[1]= Point2(11,21);
_intersectionVertices[2]= Point2(12,21);
_intersectionVertices[3]= Point2(13,31);
Point2 p1 = Point2(10,20);
Point2 p2 = Point2(11,21);
Point2 p3 = Point2(12,31);
Point2 p4 = Point2(13,41);
p1.setPointLabel(1);
p2.setPointLabel(2);
p3.setPointLabel(3);
p4.setPointLabel(4);
int intersectionId ;
map<Point2, int>_mapExtendedPointToIntersectionLabel;
_mapExtendedPointToIntersectionLabel.insert(pair<Point2, int>(p1,27));
_mapExtendedPointToIntersectionLabel.insert(pair<Point2, int>(p2,17));
_mapExtendedPointToIntersectionLabel.insert(pair<Point2, int>(p3,47));
_mapExtendedPointToIntersectionLabel.insert(pair<Point2, int>(p4,37));
intersectionId = 0;
int label1 = _mapExtendedPointToIntersectionLabel[_intersectionVertices[intersectionId]]; //line 116 //I placed a debug point here
cout <<"Label1 is"<<label1<<endl;
intersectionId = 1;
int label2 = _mapExtendedPointToIntersectionLabel[_intersectionVertices[intersectionId]];//line 120
cout <<"Label2 is"<<label2<<endl;
intersectionId = 2;
int label3 = _mapExtendedPointToIntersectionLabel[_intersectionVertices[intersectionId]];//line 124
cout <<"Label3 is"<<label3<<endl;
intersectionId = 3;
int label4 = _mapExtendedPointToIntersectionLabel[_intersectionVertices[intersectionId]];//line 128
cout <<"Label4 is"<<label4<<endl;
cout<<"the end"<<endl;
return 0;
}
Before line 116:
After line 116:

friend bool operator< (const Point2& p1, const Point2& p2 )
{
return p1._label < p2._label;
}
The defined strict weak ordering of this custom class, that's used as a key, in the map, compares each class instance's _label value in order to determine thir strict weak ordering.
The shown code initializes p1 through p4's _labels to unique values, so they are correctly compared for uniqueness.
But for the map lookup is concerned, it uses the instances in the _intersectionVertices array, which all have their _labels at their default values of -2.
As far as the map is concerned, none of those values, from the _intersectionVertices array, are in the map. Because to determine that, only their _labels get compared, for the reasons explained above.

Related

Sorting a vector of custom class doesn't iterate over the vector correctly

I am trying to implement a painters sort algorithm for a rendering assignment. The premise of the code is that I need to find the average depth of a polygon, and the list of polygons via the depth assigned to them by the for loop.
this is the polygons declaration, as well as a collection of the vertices of the polygon post transformation which are used for the calculation of the depth of the polygon
std::vector<Polygon3D> _polygons;
std::vector<Vertex> _transvertices;
This is the method called by the model class to sort the _polygons vector using std::sort
void Model::Sort()
{
for (int i = 0; i <= GetPolygonCount(); i++)
{
_polygons[i].SetDepth((_transvertices[_polygons[i].GetIndex(0)].Get(2) + _transvertices[_polygons[i].GetIndex(1)].Get(2) + _transvertices[_polygons[i].GetIndex(2)].Get(2)) / 3);
}
sort(_polygons.begin(), _polygons.end(), sortByDepth);
}
This code then links to this binary predicate
bool sortByDepth(const Polygon3D &lhs, const Polygon3D &rhs)
{
float m = lhs.GetDepth(); //For value testing
float n = rhs.GetDepth(); //For value testing
return lhs.GetDepth() > rhs.GetDepth();
}
The issue is, once the sort algorithm starts, the value of lhs and rhs never change - lhs always has a depth of 0 (and looking further into its assignment, it seems to be creating an entirely new polygon?) and rhs always has a value of 30.53 (the depth of the first polygon in the _polygons vertex
I'm concerned that the issue might be with not having a form of iterator linked to the Polygon3D class, but I wouldn't know where to start with making an iterator for the class.
Any help would be appreciated, I've looked through far too many similar questions, but none of them seem to be quite right for my particular problem.
EDIT:
Post got taken down because I didn't provide enough code apparently. I tried to reproduce the problem in a different project but for some reason it iterates just fine there.
This is the "shortest possible reproduction" I tried, but for some reason this doesn't seem to have the same issue as the original.
#include <vector>
#include <algorithm>
class Polygon3D
{
public:
Polygon3D(); // Example data for testing purposes
float GetDepth() const;
void SetDepth(float depth);
private:
float _depthAverage;
};
class Model
{
public:
Model();
size_t GetPolygonCount() const;
void Sort();
private:
std::vector<Polygon3D> _polygons;
std::vector<int> _vertices;
std::vector<int> _transvertices;
};
Polygon3D::Polygon3D()
{
//_depthAverage = float(rand() % 100);
}
float Polygon3D::GetDepth() const
{
return _depthAverage;
}
void Polygon3D::SetDepth(float depth)
{
_depthAverage = depth;
}
Model::Model()
{
for (int i = 0; i < 10; i++)
{
_polygons.push_back(Polygon3D());
}
this->Sort();
}
size_t Model::GetPolygonCount() const
{
return _polygons.size() - 1;
}
bool sortByDepth(const Polygon3D& lhs, const Polygon3D& rhs)
{
float m = lhs.GetDepth();
float n = rhs.GetDepth();
return lhs.GetDepth() > rhs.GetDepth();
}
void Model::Sort()
{
for (int i = 0; i <= GetPolygonCount(); i++)
{
_polygons[i].SetDepth(float(rand() % 100) / 3);
}
sort(_polygons.begin(), _polygons.end(), sortByDepth);
}
int main()
{
Model m = Model();
}
Edit 2:
I played around with just using an auto type variable to manually iterate over _polygons, and that seems to work. I dont understand why std::sort doesnt
auto begin = _polygons.begin();
while(true)
{
begin++;
}
The answer turned out to be something incredibly stupid on my own part. The issue was the copy constructor used within the Polygon3D class - I had forgotten to copy over the depth value in the copy constructor, which meant lhs did not get a depth value.

How to avoid creating of empty object?

I am making my homework and I have 2 functions unionRect and intersectRect.I am creating a set of my first class Rectangle from a file. I have to return the union and intersect rectangle of that oColl.I am having a problem with returning the values because the object returns two 0 values.
I have tried to return different things but I couldn't do it.
This is from the first class Rectangle
Rectangle unionRect(const Rectangle& rec) const {
int ux1, ux2, uy1, uy2;
ux1 = min(ix1, rec.ix1);
uy1 = min(iy1, rec.iy1);
ux2 = max(ix2, rec.ix2);
uy2 = max(iy2, rec.iy2);
Rectangle a(ux1, ux2, uy1, uy2);
return a;
}
This is second class RectangleCollection function to read from file
RectangleCollection(const string& strFileName) {
ifstream ifile(strFileName.data());
copy(istream_iterator<Rectangle>(ifile), istream_iterator<Rectangle>(), inserter(oColl,oColl.begin()));
};
this is my RectangleCollection class function for union Rect
Rectangle calcUnionColl() {
set<Rectangle>::iterator it;
Rectangle a;
for (it = oColl.begin(); it != oColl.end(); ++it) {
a = unionRect(*it);
}
return a;
}
and the .txt file is
5 5 10 10
6 6 12 12
but when i call calcUnionColl it returns me
x1:0 x2:6 y1:0 y2:12
I expect the output to be x1:5 x2:6 y1:5 y2:12.
Thank you in advance!
You are not union'ing all of the Rectangles together that are in the collection. You are union'ing each individual Rectangle only with the one Rectangle that calcUnionColl() is called on, and then you return the result of just the last union that was performed.
Try something more like this instead:
class Rectangle {
public:
...
Rectangle unionRect(const Rectangle& rec) const;
...
}
Rectangle Rectangle::unionRect(const Rectangle& rec) const {
int ux1, ux2, uy1, uy2;
ux1 = std::min(ix1, rec.ix1);
uy1 = std::min(iy1, rec.iy1);
ux2 = std::max(ix2, rec.ix2);
uy2 = std::max(iy2, rec.iy2);
return Rectangle(ux1, ux2, uy1, uy2);
}
...
class RectangleCollection {
public:
...
Rectangle calcUnionColl() const;
...
}
Rectangle RectangleCollection::calcUnionColl() const {
Rectangle a;
if (!oColl.empty()) {
std::set<Rectangle>::iterator it = oColl.begin();
a = *it++;
while (it != oColl.end()) {
a = a.unionRect(*it++);
}
}
return a;
}
The answer from Remy Lebeau has a minor issue. If oColl is empty, calcUnionColl will return the the default-constructed value of a. So if the default-constructed value of a is x1:0, x2:0, y1:0, y2:0 then if calcUnionColl returns that value, it is impossible to know if that is the actual union of the values in oColl, or if
oColl was empty.
A common trick when finding the the maximum value of multiple ints is to initialize the running maximum with INT_MIN. And in the same way, when finding a minimum value, we initialize the the running minimum with INT_MAX.
Finding the union of rectagles is nothing more than finding the min/max value of the rectangles corner coordinates, so we can use the above trick.
For instance if a = {x1:INT_MAX, x2:INT_MIN, y1:INT_MAX, y2:INT_MIN}, then when calculating the union of a and any rectangle b, we will have:
b.x1 <= a.x1 // a.x1 == INT_MAX
b.y1 <= a.y1 // a.y1 == INT_MAX
b.x2 >= a.x1 // a.x1 == INT_MIN
b.y2 >= a.y2 // a.y2 == INT_MIN
So the union of a and b in this case will be b
Making use of this in calcUnionColl():
// I assume the data-type for your rectangle coordinates is `int`.
// If you use another datatype, change this accoringly.
Rectangle RectangleCollection::calcUnionColl() const {
int i_min = std::numeric_limit<int>::min(); // c++ way of getting INT_MIN
int i_max = std::numeric_limit<int>::max(); // c++ way of getting INT_MAX
set<Rectangle>::iterator it;
Rectangle a(i_max, i_min, i_max, i_min);
for (it = oColl.begin(); it != oColl.end(); ++it) {
a = a.unionRect(*it);
}
return a;
}
Now, if oColl is empty, calcUnionColl() will return x1:INT_MAX, x2:INT_MIN, y1:INT_MAX, y2:INT_MIN. This should be an invalid value for a rectangle since x1>x2 and y1>y2, and should be easy to test for.
Sometimes you don't even have to test for it, since it often is an invalid value "that makes sense" for further calculations.

Find pointer of object in vector C++

I have a class which is called Position:
class Position
{
public:
... //Constructor, Destructor, ...
private:
signed int x_;
signed int y_;
}
Then I have a vector which stores pointers of Positions:
std::vector<Position*> positions
How can I check if a Position is contained in the vector? For example, I have an object of a Position:
Position* p_ = new Position(0, 0);
And I want to check if the vector contains a Position with the same coordinates?
Which operator do I have to overload?
Thanks,
Barbara
auto it = find_if(positions.begin(), positions.end(),
[=](position* p)
{
return p->x() == p_->x() && p->y() == p_->y();
});
if(it != positions.end())
{
//object found
}
However, unless you have a real reason to store pointers in the vector (e.g. you're going to use polymorphism), storing objects directly is much simpler.
vector<position> v;
v.push_back(Position(1, 2));
...
Position p_(1, 4);
auto it = find_if(v.begin(), v.end(),
[=](position p)
{
return p.x() == p_.x() && p.y() == p_.y();
});
if(it != v.end())
{
//position found
}
In the latter case it is possible to further simplify the code by overloading operator == for position.
bool operator == (position p1, position p2)
{
return p1.x == p2.x && p1.y == p2.y; //assuming operator == is declared friend
}
Then you can
auto it = find(v.begin(), v.end(), p_);
And I want to check if the vector contains a Position with the same coordinates? Which operator do I have to overload?
If you had a vector of positions (instead of vector of pointers to positions) the operator you'd have to overload would be:
bool Position::operator==(const Position& p);
With this code, you could write (assuming you are using std::vector<Position> positions;, and not std::vector<Position*> positions;):
using std::find; using std::begin; using std::end;
const Position p{}; // element that is sought after
bool exists = (end(positions) != find(begin(positions), end(positions), p));
[comment:] Yeah I am also quite unsure about this. I asked one of my teammates why he does this [i.e. store by pointers] and he said it would be more efficient and faster and it should not be changed - EVER.
It is probably not more efficient, nor faster than storing by values. If you are not in a position to change the vector though, you will have to add the operator declared above, and also a predicate that compares a Position instance to the values in a Position pointer, and using that with std::find:
const Position p{}; // element that is sought after
auto matches_position = [&p](Position const* const x)
{
return x != nullptr // can positions in the vector be null?
&& p == *x;
};
bool exists = (end(positions) != find(begin(positions), end(positions),
matches_position));
== Coping strategy ==
I would go for the first version (no pointers in the vector), by doing the following:
create a new (minimalistic) project, that fills two separate vectors, with a bunch of randomized positions (fixed number of positions, between 2000 and 10000 instances or so); the vectors should contain positions by pointer and by value respectively, with the same values in each position (a position should be in both vectors, at the same index)
perform the search for the same values in both vectors.
repeat the searches multiple times (to average and minimize timing errors)
take results to your colleague(s).
There are two outcomes from this: either your colleague is right (which seems pretty unlikely, but hey! who knows?) or he is wrong, and his code that "should never be changed" - well ... it should be changed.
Add this to class Position
Public:
bool isSamePosition(position * p){
return p->x == this->x && p->y ==this->y;
}
Then compare with all in the vector
bool unique = true;
for (int i = 0; i < positions.length(); ++i){
if (new_position->isSamePosition(positions[i])
unique = false;
}
if (unique==true)
//do something like push_back vector
;

sorting points: concave polygon

I have a set of points that I'm trying to sort in ccw order or cw order from their angle. I want the points to be sorted in a way that they could form a polygon with no splits in its region or intersections. This is difficult because in most cases, it would be a concave polygon.
point centroid;
int main( int argc, char** argv )
{
// I read a set of points into a struct point array: points[n]
// Find centroid
double sx = 0; double sy = 0;
for (int i = 0; i < n; i++)
{
sx += points[i].x;
sy += points[i].y;
}
centroid.x = sx/n;
centroid.y = sy/n;
// sort points using in polar order using centroid as reference
std::qsort(&points, n, sizeof(point), polarOrder);
}
// -1 ccw, 1 cw, 0 collinear
int orientation(point a, point b, point c)
{
double area2 = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
if (area2 < 0) return -1;
else if (area2 > 0) return +1;
else return 0;
}
// compare other points relative to polar angle they make with this point
// (where the polar angle is between 0 and 2pi)
int polarOrder(const void *vp1, const void *vp2)
{
point *p1 = (point *)vp1;
point *p2 = (point *)vp2;
// translation
double dx1 = p1->x - centroid.x;
double dy1 = p1->y - centroid.y;
double dx2 = p2->x - centroid.x;
double dy2 = p2->y - centroid.y;
if (dy1 >= 0 && dy2 < 0) { return -1; } // p1 above and p2 below
else if (dy2 >= 0 && dy1 < 0) { return 1; } // p1 below and p2 above
else if (dy1 == 0 && dy2 ==0) { // 3-collinear and horizontal
if (dx1 >= 0 && dx2 < 0) { return -1; }
else if (dx2 >= 0 && dx1 < 0) { return 1; }
else { return 0; }
}
else return -orientation(centroid,*p1,*p2); // both above or below
}
It looks like the points are sorted accurately(pink) until they "cave" in, in which case the algorithm skips over these points then continues.. Can anyone point me into the right direction to sort the points so that they form the polygon I'm looking for?
Raw Point Plot - Blue, Pink Points - Sorted
Point List: http://pastebin.com/N0Wdn2sm (You can ignore the 3rd component, since all these points lie on the same plane.)
The code below (sorry it's C rather than C++) sorts correctly as you wish with atan2.
The problem with your code may be that it attempts to use the included angle between the two vectors being compared. This is doomed to fail. The array is not circular. It has a first and a final element. With respect to the centroid, sorting an array requires a total polar order: a range of angles such that each point corresponds to a unique angle regardless of the other point. The angles are the total polar order, and comparing them as scalars provides the sort comparison function.
In this manner, the algorithm you proposed is guaranteed to produce a star-shaped polyline. It may oscillate wildly between different radii (...which your data do! Is this what you meant by "caved in"? If so, it's a feature of your algorithm and data, not an implementation error), and points corresponding to exactly the same angle might produce edges that coincide (lie directly on top of each other), but the edges won't cross.
I believe that your choice of centroid as the polar origin is sufficient to guarantee that connecting the ends of the polyline generated as above will produce a full star-shaped polygon, however, I don't have a proof.
Result plotted with Excel
Note you can guess from the nearly radial edges where the centroid is! This is the "star shape" I referred to above.
To illustrate this is really a star-shaped polygon, here is a zoom in to the confusing lower left corner:
If you want a polygon that is "nicer" in some sense, you will need a fancier (probably much fancier) algorithm, e.g. the Delaunay triangulation-based ones others have referred to.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct point {
double x, y;
};
void print(FILE *f, struct point *p) {
fprintf(f, "%f,%f\n", p->x, p->y);
}
// Return polar angle of p with respect to origin o
double to_angle(const struct point *p, const struct point *o) {
return atan2(p->y - o->y, p->x - o->x);
}
void find_centroid(struct point *c, struct point *pts, int n_pts) {
double x = 0, y = 0;
for (int i = 0; i < n_pts; i++) {
x += pts[i].x;
y += pts[i].y;
}
c->x = x / n_pts;
c->y = y / n_pts;
}
static struct point centroid[1];
int by_polar_angle(const void *va, const void *vb) {
double theta_a = to_angle(va, centroid);
double theta_b = to_angle(vb, centroid);
return theta_a < theta_b ? -1 : theta_a > theta_b ? 1 : 0;
}
void sort_by_polar_angle(struct point *pts, int n_pts) {
find_centroid(centroid, pts, n_pts);
qsort(pts, n_pts, sizeof pts[0], by_polar_angle);
}
int main(void) {
FILE *f = fopen("data.txt", "r");
if (!f) return 1;
struct point pts[10000];
int n_pts, n_read;
for (n_pts = 0;
(n_read = fscanf(f, "%lf%lf%*f", &pts[n_pts].x, &pts[n_pts].y)) != EOF;
++n_pts)
if (n_read != 2) return 2;
fclose(f);
sort_by_polar_angle(pts, n_pts);
for (int i = 0; i < n_pts; i++)
print(stdout, pts + i);
return 0;
}
Well, first and foremost, I see centroid declared as a local variable in main. Yet inside polarOrder you are also accessing some centroid variable.
Judging by the code you posted, that second centroid is a file-scope variable that you never initialized to any specific value. Hence the meaningless results from your comparison function.
The second strange detail in your code is that you do return -orientation(centroid,*p1,*p2) if both points are above or below. Since orientation returns -1 for CCW and +1 for CW, it should be just return orientation(centroid,*p1,*p2). Why did you feel the need to negate the result of orientation?
Your original points don't appear form a convex polygon, so simply ordering them by angle around a fixed centroid will not necessarily result in a clean polygon. This is a non-trivial problem, you may want to research Delaunay triangulation and/or gift wrapping algorithms, although both would have to be modified because your polygon is concave. The answer here is an interesting example of a modified gift wrapping algorithm for concave polygons. There is also a C++ library called PCL that may do what you need.
But...if you really do want to do a polar sort, your sorting functions seem more complex than necessary. I would sort using atan2 first, then optimize it later once you get the result you want if necessary. Here is an example using lambda functions:
#include <algorithm>
#include <math.h>
#include <vector>
int main()
{
struct point
{
double x;
double y;
};
std::vector< point > points;
point centroid;
// fill in your data...
auto sort_predicate = [&centroid] (const point& a, const point& b) -> bool {
return atan2 (a.x - centroid.x, a.y - centroid.y) <
atan2 (b.x - centroid.x, b.y - centroid.y);
};
std::sort (points.begin(), points.end(), sort_predicate);
}

Get a full double value

I add one double value from a file to a variable and push it into a vector, with format "338620.3478" , then after that I get the value from the vector, it just gets "338620", as it could not get all the double value.
So how can I get a full double value like the original format?
The Code:
struct Point {
double x, y;
bool operator <(const Point &p) const {
return x < p.x || (x == p.x && y < p.y);
}
};
ifstream iFile("griddata.dat"); //read a file (grid)
string line;
Point Grid; /
while(getline(iFile,line))
{
unsigned pos = line.find(",");//the symbol is used to separate X and Y
std::string strs = line.substr(0,pos); // get X
std::string strs2 = line.substr(pos+1); // get Y
Grid.x = atof(strs.c_str()); // get the first cooordinate X
Grid.y = atof(strs2.c_str()); // get the second cooordinate Y
// A list of coordinates of grid is stored into the vector gridPoints
gridPoints.push_back(Grid); // adding the points of grid to vector
}
int j;
for(j=0;j<gridPoints.size();j++)
{
//here i cannot get the full double value for gridPoints[j].x;
//....it just gets "338620"
}
The format of file (griddata.dat):
338620.3478,6196150.566
Thank you!
Assuming that your Point class is in the windows framework, I'm pretty sure it's members are int types.
Either way, your values are being cast to a type that isn't floating point and is being truncated.
I think your problem is retrieving the values (maybe with cout?? -->then you can use: cout.precision(15))
see: How do I print a double value with full precision using cout?