Related
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.
I am looking for a fast way to calculate the dot product of vectors with 3 or 4 components. I tried several things, but most examples online use an array of floats while our data structure is different.
We use structs which are 16 byte aligned. Code excerpt (simplified):
struct float3 {
float x, y, z, w; // 4th component unused here
}
struct float4 {
float x, y, z, w;
}
In previous tests (using SSE4 dot product intrinsic or FMA) I could not get a speedup, compared to using the following regular c++ code.
float dot(const float3 a, const float3 b) {
return a.x*b.x + a.y*b.y + a.z*b.z;
}
Tests were done with gcc and clang on Intel Ivy Bridge / Haswell. It seems that the time spend to load the data into the SIMD registers and pulling them out again kills alls the benefits.
I would appreciate some help and ideas, how the dot product can be efficiently calculated using our float3/4 data structures. SSE4, AVX or even AVX2 is fine.
Editor's note: for the 4-element case, see How to Calculate single-vector Dot Product using SSE intrinsic functions in C. That with masking is maybe good for the 3-element case, too.
Algebraically, efficient SIMD looks almost identical to scalar code. So the right way to do the dot product is to operate on four float vectors at once for SEE (eight with AVX).
Consider constructing your code like this
#include <x86intrin.h>
struct float4 {
__m128 xmm;
float4 () {};
float4 (__m128 const & x) { xmm = x; }
float4 & operator = (__m128 const & x) { xmm = x; return *this; }
float4 & load(float const * p) { xmm = _mm_loadu_ps(p); return *this; }
operator __m128() const { return xmm; }
};
static inline float4 operator + (float4 const & a, float4 const & b) {
return _mm_add_ps(a, b);
}
static inline float4 operator * (float4 const & a, float4 const & b) {
return _mm_mul_ps(a, b);
}
struct block3 {
float4 x, y, z;
};
struct block4 {
float4 x, y, z, w;
};
static inline float4 dot(block3 const & a, block3 const & b) {
return a.x*b.x + a.y*b.y + a.z*b.z;
}
static inline float4 dot(block4 const & a, block4 const & b) {
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
}
Notice that the last two functions look almost identical to your scalar dot function except that float becomes float4 and float4 becomes block3 or block4. This will do the dot product most efficiently.
To get the best out of AVX intrinsics, you have to think in a different dimension.
Instead of doing one dot product, do 8 dot products in a single go.
Look up the difference between SoA and AoS.
If your vectors are in SoA (structures of arrays) format, your data looks like this in memory:
// eight 3d vectors, called a.
float ax[8];
float ay[8];
float az[8];
// eight 3d vectors, called b.
float bx[8];
float by[8];
float bz[8];
Then to multiply all 8 a vectors with all 8 b vectors, you use three simd multiplications, one for each of x,y,z.
For dot, you still need to add afterwards, of course, which is a little trickier. But multiplication, subtraction, addition of vectors, using SoA is pretty easy, and really fast. When AVX-512 is available, you can do 16 3d vector multiplications in just 3 instructions.
I'm revamping an old application that use Numerical Recipes' dmatrix quite extensively. Since one of the reasons I'm working on the application is because its code is about to be opened, I want to replace all of the Numerical Recipes code with code that can be freely distributed.
dmatrix is a function that returns a matrix of doubles. The called supplies the lower and upper bound for each index, like so:
double **mat = dmatrix(1,3,1,3);
mat now has 3 rows, from 1 to 3, and 3 columns, from 1 to 3, so that mat[1][1] is the first element and mat[3][3] is the last.
I looked at various C++ matrix implementations, none of them allowed me to specify the lower bound of each dimension. Is there something I can use, or do I have to write yet another matrix class for this?
I believe that you can easily make a wrapper of some other matrix implementation to add the lower bound feature. Example (untested):
class Matrix {
OtherMatrix m;
int lowerX, lowerY;
public:
Matrix(int lx, int hx, int ly, int hy) :
m(hx-lx, hy-ly),
lowerX(lx), lowerY(ly) { }
MatrixCol operator[] (int x) {
return {this, x};
}
};
class MatrixCol {
friend class Matrix;
Matrix* mm;
int x;
public:
double& operator[] (int y) {
return mm->m[x - mm->lowerX, y - mm->lowerY];
}
};
This may require a little more robust implementation depending on your use case. But this is the basic idea, expand from it.
In my program -- which uses the Eigen library -- I need to operate on 2D vectors. In my inner loop I have the following function:
static inline double eval(double x, double y, double xi, double yi)
{
const double invlen2 = 1/(x*x + y*y);
const double invlen4 = invlen2*invlen2;
const double invlen6 = invlen4*invlen2;
const double x2 = x*x, y2 = y*y;
const double x3 = x2*x, y3 = y2*y;
const double xi2 = xi*xi, yi2 = yi*yi;
return x*invlen2 + invlen4*(x2*xi + 2*x*y*yi - xi*y2)
+ invlen6*(x3*xi2 + 3*x*y2*yi2 + 6*x2*y*xi*yi - 3*x*xi2*y2 - 2*y3*xi*yi - x3*yi2);
}
void f(Vector2d& out, const Vector2d& R, const Vector2d& r)
{
out.x() = eval(R.x(), R.y(), r.x(), r.y());
out.y() = eval(R.y(), R.x(), r.y(), r.x());
}
This expression, although messy, seems like a prime candidate for vectorisation as both the x() and y() computations follow identical paths. My question is how to do it with Eigen without needing to manually drop down to assembly.
This answer has nothing to do with Eigen, but since you mentioned manually dropping down to assembly, I'll add this.
You don't need to use assembly to vectorize code. There are compiler intrinsics that will let manually vectorize without assembly:
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_overview.htm#intref_overview
That said: It looks like Eigen already has internal support for vectorization, but it doesn't appear to be applicable in your example. So I can see why you want to do it manually.
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 );
}
}