I have the following functor for redefining the less operator of the sort method for the vector type:
typedef vector< vector<int> > MxInt2d;
typedef vector< vector<double> > MxDouble2d;
class QSweep{
public:
....
static MxDouble2d myPoints_;
MxDouble2d myEdges_;
class order{
public:
bool operator() (const vector<int>& edge1, const vector<int>& edge2){
//std::cout<<"inside sort"<<endl;
//3 sort criteria
return (myPoints_[edge1[0]][0]<myPoints_[edge2[0]][0])||
(myPoints_[edge1[0]][0]==myPoints_[edge2[0]][0]&&
myPoints_[edge1[0]][1]<myPoints_[edge2[0]][1])
||
(myPoints_[edge1[0]][0]==myPoints_[edge2[0]][0]&&
myPoints_[edge1[0]][1]==myPoints_[edge2[0]][1]&&
getSlope(myPoints_[edge1[0]][0],myPoints_[edge1[0][1],
myPoints_[edge1[1]][0],myPoints_[edge1[1]][0])
<
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][0]));
}
};
static double getSlope(double a, double b, double c, double d);
};
where getSlope is a function defined in the following way:
double QSweep::getSlope(double a, double b, double c, double d){
double slope=0.0;
//std::cout<<"slope criteria"<<endl;
double denum=c-a;
if (denum==0){
std::cout<<"zero denominator"<<endl;
}
else{
slope=(d-b)/denum;
}
return slope;
}
Each point is given by an index, an x, and a y coordinate; Each edge is given by source-edge[0] and destination-edge[1],where edge[0],edge[1] are indexes of the points).
I want to arrange the edge:
- by the x coordinate of their edge[0] coordinate (iff the x's of 2 edges are different)
- by the y coordinate of their edge[0] coordinate (iff the x's of 2 edges are equal)
- by their corresponding slopes (iff the x's of edges and the y's of edges are equal).
I declared the getSLope function static, but when I sort the edges with
sort(myEdges_.begin(),myEdges_.end(),order());
the last condition is not fullfilled.
if I have two edges with the same x's and y's for edgep[0] but with different slopes, e.g. slope(edge1)=1 ,slope(edge2)=1/2 than I would want to get
[edge2, edge1]; instead I get [edge1,edge2].
So my getSlope criteria is not computed.
is it because I declared getSlope static? what should I change so that the criteria is fulfilled?
thank you in advance for your suggestions,
madalina
crikey! It looks quite complex, firstly have you tried with a less complex set of values to compute - ie I see you have cout statements, I trust that they work correctly when you run it?
If so, can iut be that your inputs to getSlope are wrong - shouldn't
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][0])
be
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][1])
Maybe it happened because expression result could be calculated without it.
E.g.:
false && someFunction(); - function will not be called
true || someFunction(); - function will not be called
This is nice rule, it allow us write next:
if ( ptr && ptr->someMethod() )
// call method will not be called for NULL pointers
Related
#include <utility>
#include <algorithm>
using namespace std;
class Point
{
public:
int x, y, z;
Point(int ix, int iy, int iz) : x(ix), y(iy), z(iz) {}
};
int main() {
vector <Point> v = { {1, 1, 0}, {1, 2, 0}, {2, 2, 0}, {2, 1, 0} };
auto min_max = std::minmax_element(begin(v), end(v));
return 0;
}
In this program I get an error at the line where minmax_element is called in MSVS2019.
Also it would be very helpful if anyone can suggest a compare function for Point data type.
You need to implement an operator< for Point. The easiest way is to use std::tie(), which returns a std::tuple that has its own operator<, eg:
class Point
{
public:
int x, y, z;
Point(int ix, int iy, int iz) : x(ix), y(iy), z(iz) {}
bool operator<(const Point &rhs) const { return std::tie(x,y,z) < std::tie(rhs.x,rhs.y,rhs.z); }
};
In this program I get an error at the line where minmax_element is called in MSVS2019.
You already realized that this is because you haven't provided a way of comparing your Point.
The documentation lists the requirement that the argument must be LessThanComparable, ie, having a suitable operator <.
it would be very helpful if anyone can suggest a compare function for Point data type.
I can provide a million, because there is no singular natural well-defined ordering on ℤ³. You have to decide for yourself what ordering makes sense for you.
lexical (x, then y, then z) ordering as suggested in the other answer:
puts the leftmost point first, and then the higher of two points with the same x, and finally the deeper (or whatever you want to call z) of two points with the same x and y
this is well-defined in the sense that a < a is false, and
!(a < b || b < a) always means a == b
but it's not guaranteed to give you the lower-left and upper-right vertices
magnitude (ie, distance from the origin, or (xx + yy + z*z)
puts points closer to the origin first, but every point on a sphere (centred on the origin) with the same radius compares equal
lexical with different ordering ... distance from a different point ... etc.
basically I was looking for getting the left-bottom and right-top point of a polygon
Is the polygon in a flat z-plane? If so, you don't need to look at z at all. If not, you need to decide whether you want the left-bottom-front and right-top-back or what.
Let's assume 2D for simplicity - if the lower-left edge is (0,1) - (1,0), which of those corners is the left-bottom? Is it more important to be the leftmost, or the lower-most?
Nobody can answer this for you, because it isn't well-defined. You just have to make a decision about how you want your program to behave.
I read a very large number of point coordinates x, y and z and store them in a vector of Point structures to do further processing.
struct Point{
double x,y,z;
Point (double x0, double y0, double z0): x(x0), y(y0), z(z0) {}
}
vector<Point> pv;
pv.push_back (Point(x,y,z));
I also have a hash function that maps all the points with the same coordinates together with their vector index to an unordered_multimap for some other processing.
the problem is there are many duplicate points that I read from the file and I have to get rid of those elements. I have seen solutions on how to remove duplicate elements from a vector of primitive types but that does not apply to my case. In addition many of the proposed methods, requires sorting that is not applicable to a Point structure.
Define the less operator and then apply the same method as for primitive type
How to define the operator is:
struct Point{
(...)
const bool operator < ( const Point &r ) const{
return (x<r.x) || (x==r.x && y<r.y) || (x==r.x && y==r.y && z<r.z);
}
};
You can use the so-called erase-remove "idiom":
#include <algorithm>
...
pv.erase(std::remove(pv.begin(), pv.end(), pointToRemove), pv.end());
where operator== has been defined for Point:
bool operator==(Point a, Point b) {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
Suppose I have a std::vector<Point> where Point is struct Point { double x; double y;}
I'd like to partition such a vector into groups (buckets), where all Points in same bucket have same Euclidean norm between each other (e.g dist(PointA,PointB) == X, where X is constant). I've decided to use std::map for such task with custom sorting operator:
struct ClosePoints
{
bool operator()(Point const& A, Point const& B) const
{
bool same = dist(A,B) < x;
//If not close enough use lexical sort
return same ? false : std::tie(A.x, A.y) < std::tie(B.x,);
}
}
Partitioning code:
std::map<Point, std::list<Point>, ClosePoints> map;
for(const auto& p : pointsVector)
map[p].push_back(p);
After some testing and printing the buckets I've noticed that some points that do obey given Euclidean norm limit X ended in different buckets.
I can't figure out why is it so ?
The issue is that comparison operator that you defined does not provide equivalence relationship. For instance, you can have a point B that close to A and C but points A and C could be far from each other. Thus, if you compare B with A and C, you will put them in the same basket as B. However, if you compere A and C first, results will be unpredictable.
I am working with computer graphics.
I would like to represent a line with two end points, and, then I would like my Line2d class to have a method that returns a Vector2d object.
Suppose, I have the following classes:
struct Point2d
{
int x;
int y;
};
Then, I can easily represent a line segment using two points:
class LineSegment2d
{
private:
Point2d start;
Point2d end;
public:
...
...
};
According to the definition, a vector is composed of a magnitude and a direction.
class Vector2d
{
private:
Point2d p;
public:
double Magnitude(void);
Point Component(void);
Vector2d Normal();
Vector2d & Add(Vector & rhs);
Vector2d & Subtract(Vector & rhs);
Vector2d & Multiply(int scalar);
int DotProduct(Vector2d rhs);
Vector2d & CrossProduct(Vector2d rhs);
};
One object of Point2d is sufficient to represent a vector. For example, magnitude of a vector = sqrt(p.x*p.x + p.y*p.y);. And, p.x and p.y collectively represent the direction.
On the other hand, we know that the vector equation of a line passing through (x0,y0,z0) is, r =r0 + tv
Where,
r is the vector for the subject line.
r0 is a position vector that points to the direction of the point (x0, y0, z0). Since, r0 is a position vector, obviously, the origin of r0 would be (0,0,0).
t is any real numbered value, where, −∞<t<∞ –.
v is a vector which is parallel to our subject straight line.
Vector equation of a line segment between the points P(1, 3, 2) and Q(-4, 3, 0):
According to the above formula, the vector equation of the line PQ could be either
r =<1,3,2> + tv
or,
r =<-4,3,0> + tv
The vector that connects the two points P and Q is,
PQ = <(-4-1), (3-3), (0-2)>
= <-5, 0, -2>
And, this vector is parallel to our subject line for sure.
So, we can write,
r =<1, 3, 2> + t <-5, 0, -2>
=<1, 3, 2>+<-5t, 0, -2t>
= <(1-5t), (3+0), (2-2t)>
=<1-5t, 3, 2-2t>
According to the vector equation of a line segment, I think, my Vector class should look like the following:
class LineVector2d
{
private:
Vector2d v;
double t;
public:
..........
};
Is this the correct representation?
If that so, how can I calculate/set/find the value of t?
There are many forms of line representation.
If you mean line (not segment), then, probably, you'll find convenient to use class/structure, containing BasePoint and UnitDirectionVector.
For line segments, choose between (Point pt0, Point pt1) form, and, (Point pt, Vector v = pt1 - pt0) form.
The second one is more suitable for parametric approach like,
X = P0.X + t * D.X etc.
I think there's some confusion because of the following
According to the definition, a vector is composed of a magnitude and a direction.
There is more than one way of representing a vector. I think in your question you mean that a vector can be represented by a magnitude (scalar) and a unit vector indicating a direction. A vector can just be an ordered triplet (for three dimensions) that indicate the magnitude (sqrt(x^2 + y^2 + z^2)) and the direction from the origin.
I think the answer to your question is, you don't need to calculate t. Correct me if I'm mistaken, but I think you're interpreting t as the magnitude? You can calculate that from v with sqrt(x^2 + y^2 + z^2), but v can hold both a magnitude and direction as an ordered triplet by itself.
Edit:
template <typename T>
struct Point2d
{
T x;
T y;
Point2d operator + (const Point2d<T>& rhs) const
{
return Point2d<T>{x + rhs.x, y + rhs.y};
}
Point2d operator - (const Point2d<T>& rhs) const
{
return Point2d<T>{x - rhs.x, y - rhs.y};
}
// ...
Point2d operator * (const T value) const
{
return Point2d<T>{x*value, y*value};
}
Point2d operator / (const T value) const
{
return Point2d<T>{x/value, y/value};
}
// ...
};
template <typename T>
class Vector2d
{
private:
Point2d<T> p;
public:
Vector2d(const Point2d<T>& point) : p{point} {}
/*double Magnitude();
Point2d<T> Component();
Vector2d Normal();
int DotProduct(Vector2d rhs);
Vector2d& CrossProduct(Vector2d rhs);*/
Vector2d operator + (const Vector2d<T>& rhs) const
{
return p + rhs.p;
}
Vector2d operator - (const Vector2d<T>& rhs) const
{
return p - rhs.p;
}
// ...
Vector2d operator * (const T value) const
{
return p*value;
}
Vector2d operator / (const T value) const
{
return p/value;
}
// ...
};
template <typename T>
class LineVector2d
{
private:
Point2d<T> p;
Vector2d<T> v;
public:
LineVector2d() = default;
LineVector2d(const Point2d<T>& point, const Vector2d<T>& direction) : p{point}, v{direction} {}
/// Returns the point on the line for the time/value `t`
Point2d<T> valueAt(T t)
{
return p + v*t;
}
};
If you want to convert a line segment to a vector, you have to be aware that there is no "universal semantic" for the conversion, it is up to you to define what the conversion means. That said, I assume you want a vector with the same (Euclidean) norm as the length of the line segment and pointing in the same direction, i.e. something like this:
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end) - Vector2d(start);
}
};
In other words, offset the line segment to the origin point of the coordinate system. The end point can then be converted to a vector.
EDIT: After understanding a bit more about why you want this, you might be looking for another representation
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end);
}
};
This will get you one vector for each line segment: the end point. If your polygons consist of connected line segments, this will give you all the vertices in the polygon.
Use the representation of line segments you have in the question.
I'll write LS(a,b) for the line segment with start point a, and, end point b.
Now given two such segments LS(a,b), and, LS(c,d) that intersect (in your context one from the clipping polygon and one from the polygon being clipped; I am presuming you know how to determine this).
What you seem to want answered is if this intersection has LS(c,d) going to the inside of the polygon while crossing the edge LS(a,b).
For this, it is sufficient to determine the angle between the directions of the line segments. This is the same as the angle between the vectors v = b-a and w = d-c.
Also, you don't even need the angle, all you need is to see if the angle is positive or negative; so look at the vector w-v. If LS(c,d) crosses LS(a,b) to the inside, this vector will be in the lower half plane. If LS(c,d) crosses LS(a,b) to the outside, this vector will be in the upper half plane.
Determining upper verses lower half plane means looking at the second coordinate of end-start.
Apologies for the wall of text, but mathjax doesn't seem active on this site. Also no code, but I believe that (if I didn't make any mistakes) all the operations I mentioned are easy to translate into code.
If you want to be very mathematical, maybe this can help: https://en.wikipedia.org/wiki/Homogeneous_coordinates
In 2d that means a position is (x,y,1) and a direction (dx,dy,0). The reason for this is projection, which is rare in 2d but common in 3d.
So to try to answer: Just use 4 component vectors all the time. Positions have a w=1, directions a w=0.
Just try it with a line based of two points A and B, both have w=1. The vector from A to B is B-A, which ends up with w=0.
Also what you use in your code does matter very little unless you end up optimizing a special case. Just go for the smallest data structure. Start and end should be fine.
Maybe think about indexed: A flat array of all vertices and every line is just two indices into the vertex array.
Your representation of class LineSegment2d is fine. But the representation of class Vector2d is incorrect. This is because you are considering only those vectors that pass through the origin. A vector on a 2d plane can be represented with 3 components in the same way it done in 3d space. The 3 components of a vector are namely: Direction, Magnitude and A point through which it passes. If we define x, y and z axes for a 3d space then, for a point in the x-y plane z component is equal to 0. Also, direction in 3d space is defined in the form of direction cosines(ie. the cosine of the angle between the vector and an axis). Hence cosine of angle between vector and z-axis is equal to zero(because the angle = 90 degrees) for a vector in x-y plane.
Suppose we want two constructors for a class representing complex numbers:
Complex (double re, double img) // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates
but the parameters (number and type) are the same: what is the more elegant way
to identify what is intended? Adding a third parameter to one of the constructors?
It is better to add static methods with appropriate names and let them to create the objects.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
You can't have two constructors (or any functions) with the same signatures. The best solution is probably to create classes for your coordinate types and overload on those. For example:
struct CartCoord {
CartCoord( double re, double img ) : mRe(re), mImg(img) {}
double mRe, mImg;
};
struct PolarCoord {
PolarCoord( double a, double v ) : mA(a), mV(v) {}
double mA, mV;
};
Then your constructors become:
Complex( const CartCoord & c );
Complex( const PolarCoord & c);
In use:
Complex c( CartCoord( 1, 2 ) );
You can also use them with overloaded operators of the Complex class. For example, assuming you have a binary + operator for the class define as:
Complex operator+( const Complex &, const Complex & );
then:
Complex a( CartCoord( 0, 0 ) );
Complex b = a + PolarCoord( 1, 1 );
As we have a conversion constructor from PolarCoord to Complex, this will be used in the + expression. This is more natural (IMHO) than calling static functions to create the temporary..
This is an example of Koenig's dictum (or at least a version of it) - whenever faced with a difficult problem, introduce a new level of classes to solve it.
Use the named constructor idiom described here at the Parashift C++ FAQ.
You can't - if the method signatures are the same, you're stuffed.
Of course, you could always create a subclass for each type of coordinate system, but that's far from ideal - especially if you later find a good reason to want to subclass Complex for other reasons...
Instead of having two constructors, you need to have only one, but add a third parameter, for example:
Complex (double re, double img, enum type) {
if(type == polar) {
..treat as polar coordinates..
} else {
..treat as cartesian coordinates..
}
}
'enum type' can have a default type as well so you don't have to supply what type of coordinates you intend to use every time, the default should off course be what's most used.
Complex (double re, double img, enum type = polar);
Since no one mentioned it, you can use tags:
class Complex{
struct CartCoord{};
struct PolarCoord{};
Complex( CartCoord, double re, double img);
Complex( PolarCoord, double a, double v);
};
int main(){
auto c1 = Complex(Complex::CartCoord{}, 5, 6);
auto c2 = Complex(Complex::PolarCoord{}, 5, 6);
}
I don't know if it is good practice in C++ but I would name these two methods differently, at least for a maintainability point of view.
I would probably create more classes, but then I am an adept of Boost Strong Typedef library.
For me it does not make sense to use double to represent both coordinates, module and angles.
So I would have:
class CoordinateX {};
class CoordinateY {};
class Modulus {};
class Angle {};
class Complex
{
public:
Complex(CoordinateX, CoordinateY);
Complex(Modulus, Angle);
};
And there it's perfectly clear, and there is no ambiguity. Also you add some compile-time check of "units" in a loose sense. It rarely makes sense (if ever) to add an X-coordinate and an Y-coordinate, or worse a distance and an angle.
For me the more elegant way would be to create a class representing cartesian coordinates and another representing polar coordinates, then give object of the relevant class to the constructors.
That way you would have two constructor using different parameters.
I use this simple alternative way while practicing C++, I don't know if it is what you want.
class Vector{
public:
float x, y;
Vector();
Vector(float , float, bool);
float get_distance(Vector v); // find distance from another vector
float get_magnitude(); // find distance from origin point
Vector add(Vector v);
Vector subtract(Vector v);
Vector multiply(Vector v); // multiply by vector
Vector multiply(float scalar); // multiply by scalar
float get_angle();
};
Vector::Vector(float a, float b, bool is_cartesian = true){
if(is_cartesian){
x = a;
y = b;
}
else{
x = a * cos( b );
y = a * sin( b );
}
}