Create arrow class - c++

I am trying to create an arrow class that takes two Points. This is what I have:
struct Arrow : Lines { // an Arrow is a Line that has an arrow at the end
Arrow(Point p1, Point p2) // construct an Arrow from two points
:p1(p1), p2(p2) {}
void draw_lines() const;
Point p1;
Point p2;
};
This is what I have of the draw_lines() const function:
void Arrow::draw_lines() const
{
Lines arrow;
arrow.add(p1, p2);
arrow.draw_lines();
}
It works by typing Arrow a(Point(x,y), Point(x1,y1));. It is then supposed to calculate the arrow using (x,y), which becomes p1, and (x1,y1), which becomes p2, as guides to the direction and (x1,y1) as the arrow base point. I would like the arrow to look like this, only solid: --->. How can I calculate the angle that the arrow points? The lines of the arrow head need to be as two x,y coordinates, such as (p2.x, p2.y, (x coordinate of back point of arrow relative to p2), (y coordinate of back point of arrow relative to p2). The .x and .y notation returns the x and y coordinates of Point p.
Thank you for any help.

Here's what it looks like using atan2.
const double pi = 3.1415926535897931;
const int r = 5;
const double join_angle = pi / 6.0; // 30 degrees
const double stem_angle = atan2(p2.y-p1.y, p2.x-p1.x);
Lines arrow;
arrow.add(p1, p2);
arrow.add(p2, Point(p2.x - r*cos(stem_angle+join_angle), p2.y - r*sin(stem_angle+join_angle)));
arrow.add(p2, Point(p2.x - r*cos(stem_angle-join_angle), p2.y - r*sin(stem_angle-join_angle)));
This is exactly the approach you described in your comment:
Ideally, I would like to enter a const int to be added or subtracted to the angle of the slope to create the angle of the arrowhead lines, and another for the length, and it takes care of the nitty gritty point coordinates itself.
Except that double is much better than int for storing the join_angle in radians.

You don't need trigonometric functions like atan. Just normalize the vector from p1 to p2 (you need sqrt for that), get the orthogonal vector to that (easy in 2D) and get the missing two points by adding multiples (factors determine length and width of the arrow head) of these two unit vectors to the end point.

Related

Project an object with rotation around another object in C++/OpenGL

I'm Using OpenGL/C++ to create a game.
One aspect of this game that I'm working on is having a character that shoots a projectile the way said character is facing. To do this I have a 'player' and a 'projectile'.
I pass to the projectile the characters x and y co-ordinates, the angle the player is facing. From this I want to shoot the projectile in that direction.
In my draw I am currently using glTranslate with the characters x and y and rotating the projectile on the way the character is facing. This moves my projectile to the way the player is facing.
glTranslatef(this->m_X, this->m_Y, 0);
glRotatef(angle, 0, 0, 1);
This is where i'm stuck, I can move the projectile position by incrementing/decrementing the X and Y values in the translate. But what I'm trying to ask is how can I move the projectile along the line the player is facing.
Thanks for the help!
You can use polar vectors for these calculations.
http://mathworld.wolfram.com/PolarVector.html
A polar vector will allow you to make several calculations that would normally be complicated and convoluted in a simple way. Using their applied mathematics your request won't be an issue.
Here's an implementation of mine of polar vectors.
The header file:
#include <cmath>
//Using SFML Vector2 class, making a similar class is easy.
//Check this URL: http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Vector2.php
class PolarVector
{
public:
float r;
float t; ///Angle stored in degrees.
PolarVector();
PolarVector(float radius, float angle);
PolarVector(const sf::Vector2f V2); ///Conversion constructor.
sf::Vector2f TurnToRectangular() const;
};
PolarVector TurnToPolar(const sf::Vector2f point);
float getConvertedRadius(const sf::Vector2f point);
float getConvertedAngle(sf::Vector2f point);
bool operator ==(const PolarVector& left, const PolarVector& right);
bool operator !=(const PolarVector& left, const PolarVector& right);
And the source file:
#include "PolarVector.hpp"
PolarVector::PolarVector()
:r(0.f)
,t(0.f)
{}
PolarVector::PolarVector(float radius, float angle)
:r(radius)
,t(angle)
{}
PolarVector::PolarVector(const sf::Vector2f V2)
:r(getConvertedRadius(V2))
,t(getConvertedAngle(V2))
{}
sf::Vector2f PolarVector::TurnToRectangular() const
{ return sf::Vector2f(static_cast<float>(r* std::cos(t)), static_cast<float>(r* std::sin(t))); }
PolarVector TurnToPolar(const sf::Vector2f point)
{
PolarVector PV;
PV.r = getConvertedAngle(point);
PV.t = getConvertedRadius(point);
return PV;
}
float getConvertedRadius(const sf::Vector2f point)
{ return std::sqrt((point.x * point.x) + (point.y * point.y) ); }
float getConvertedAngle(const sf::Vector2f point)
{ return std::atan2(point.y, point.x); }
bool operator ==(const PolarVector& left, const PolarVector& right)
{
float diffR = left.r - right.r;
float diffA = left.t - right.t;
return ((diffR <= EPSILON) && (diffA <= EPSILON));
}
bool operator !=(const PolarVector& left, const PolarVector& right)
{
float diffR = left.r - right.r;
float diffA = left.t - right.t;
return !((diffR <= EPSILON) && (diffA <= EPSILON));
}
The reason why I suggest this is because you can do the following.
Let's say you have a 2 dimensional vector:
sf::Vector2f character(0.f, 0.f); //Origin point. First parameter is X, second is Y
float angleCharFacesAt = 0.698132; //40 degrees in radians. C++ Trigonometry uses Radians. std::cos, std::sin and std::atan2 are used internally.
For the first object or character. You want the other object to have the same angle, but a different position.
Let's say the other object has a position above it:
sf::Vector2f object(0.f, 10.f); //Above the origin point.
float angleObjectFacesAt = 0.f; //0 degrees.
So all you need to do is rotate it using a polar vector:
PolarVector PV = TurnToPolar(object); //Use this for calculations.
PV.t += angleCharFacesAt; //t is the angle parameter of the polar vector.
object = PV.TurnToRectangular(object);
By doing this you will get the rotated position of the object.
The distance between one object and the other will always be the r (Radius) value of the polar vector. So you could make the distance longer or shorter by doing this:
PolarVector PV = TurnToPolar(object); //Use this for calculations.
PV.r += 10; //Increase the radius to increase the distance between the objects.
object = PV.TurnToRectangular(object);
You should try to understand the rotation matrix and polar math to be able to achieve more things with this, but with this code it is possible. You should also put all this code in a class, but first play with it until you understand it well.
Sorry for the lengthy answer, but this is a topic that isn't very easy to explain without delving into linear algebra. The classes are for actual code manageability (I use these in my own game), but you can reproduce the same effects with the calculations only.
I personally prefer Polar Vectors over using the rotation matrix due to their usefulness in more than just rotating an object. But here's a link to understanding the rotation matrix better: https://en.wikipedia.org/wiki/Rotation_matrix
After you've done the transformation with the polar vector, you can just glTranslate to the final position given by the polar vector. You have to make sure that you rotate around the origin you are using. Otherwise rotation might not occur as you desire to use it.

How to connect OpenCV contours horizontally?

I'm using findContours in Opencv 2.9 (C++). What I obtain is a vector> contours, which describes my contours. Lets say I've got a rectangle with its contour stored in the vector. What I would like to do next is, to connect the left and right side of the contour at any point with a line. E.g. 10 pixels below the upper left corner to the 10 pixels below upper right corner of the rectangle. The line should end where the contour does. Is there a better approach then just going scanline wise through that lane and checking every pixel if pointPolygonTest is true?
Thanks in advance!
Suppose you have corners (top-left, top-right, bottom-right and bottom-left points) then you can easily calculate intersections between two lines each defined with two points.
For example, line(P1, P4) intersects with line(R1,R2) and the intersection point is I:
Here is a snippet code for calculating intersection point if the lines do intersect:
// Finds the intersection of two lines, or returns false.
// The lines are defined by (o1, p1) and (o2, p2).
bool intersection(cv::Point2f o1, cv::Point2f p1, cv::Point2f o2, cv::Point2f p2, cv::Point2f &r)
{
cv::Point2f x = o2 - o1;
cv::Point2f d1 = p1 - o1;
cv::Point2f d2 = p2 - o2;
float cross = d1.x*d2.y - d1.y*d2.x;
if (std::abs(cross) < /*EPS*/1e-8)
return false;
double t1 = (x.x * d2.y - x.y * d2.x)/cross;
r = o1 + d1 * t1;
return true;
}

Compute mesh vertices from a Plane

I would like to draw my Plane with OpenGL to debug my program but I don't know how I can do that (I'm not very good in math).
I've got a Plane with 2 attributs:
A constant
A normal
Here is what i've got:
////////////////////////////////////////////////////////////
Plane::Plane( const glm::vec3& a, const glm::vec3& b, const glm::vec3& c )
{
glm::vec3 edge1 = b - a;
glm::vec3 edge2 = c - a;
this->normal = glm::cross(edge1, edge2);
this->constant = -glm::dot( this->normal, a );
this->normalize();
}
////////////////////////////////////////////////////////////
Plane::Plane( const glm::vec4& values )
{
this->normal = glm::vec3( values.x, values.y, values.z );
this->constant = values.w;
}
////////////////////////////////////////////////////////////
Plane::Plane( const glm::vec3& normal, const float constant ) :
constant (constant),
normal (normal)
{
}
////////////////////////////////////////////////////////////
Plane::Plane( const glm::vec3& normal, const glm::vec3& point )
{
this->normal = normal;
this->constant = -glm::dot(normal, point);
this->normalize();
}
I would like to draw it to see if everything is ok. How I can do that?
(I need to compute vertices and indices to draw it)
When you want to draw, you need to find two vectors that are perpendecular to normal and a point on the plane. That's not so hard. First, let's get a vector that is not normal. Call it some_vect. For example:
if normal == [0, 0, 1]
some_vect = [0, 1, 0]
else
some_vect = [0, 0, 1]
Then, calculating vect1 = cross(normal, some_vect) would give you a vector perpendecular to normal. Calculating vect2 = cross(normal, vect1) would give you another vector that is perpendecular to normal.
Having two perpendecular vectors vect1 and vect2 and one point on the plane, drawing the plane becomes trivial. For example the sqaure with the following four points (remember to normalize the vectors):
point + vect1 * SIZE
point + vect2 * SIZE
point - vect1 * SIZE
point - vect2 * SIZE
where point is a point on the plane. If your constant is distance from the origin, then one point would be constant * normal.
The difficulty with drawing a plane is that it's an infinite surface; i.e. by definition it has no edges or vertices. If you want to show the plane in a typical polygonal fashion then you'll have to crop it to a particular area, such as a square.
A fairly easy approach is this:
Pick an arbitrary unit vector which is perpendicular to the normal. Store it as v1.
Use the cross product of v1 and the plane normal to get v2.
Negate v1 to get v3.
Negate v2 to get v4.
The points v1-4 now express the four corners of a square which has the same orientation as your plane. All you need to do is multiply them up to whatever size you want, and draw it relative to any point on your plane.

Rotating a 2D polygon shape algorithm

I have searched stackoverflow and find this question useful and learned about the 2D shape rotation.
I have the coordinates in such format
int x1=-30, x2=-15, x3=20, x4=30;
int my1=-30,y2=-15,y3=0,y4=15,y5=20,y6=30;
and have some center and pivot points like this
int xc=320, yc=240;//Center of the figure
int xp=0, yp=0;//Pivot point for this figure
I used this function to draw the shape
void draw_chair()
{
int loc_xc = xc+xp;
int loc_yc = yc+yp;
line(x2+loc_xc,my1+loc_yc,x2+loc_xc,y5+loc_yc);
line(x3+loc_xc,my1+loc_yc,x3+loc_xc,y5+loc_yc);
line(x2+loc_xc,my1+loc_yc,x3+loc_xc,my1+loc_yc);
line(x2+loc_xc,y2+loc_yc,x3+loc_xc,y2+loc_yc);
line(x2+loc_xc,y3+loc_yc,x3+loc_xc,y3+loc_yc);
line(x1+loc_xc,y4+loc_yc,x4+loc_xc,y4+loc_yc);
line(x2+loc_xc,y3+loc_yc,x1+loc_xc,y4+loc_yc);
line(x3+loc_xc,y3+loc_yc,x4+loc_xc,y4+loc_yc);
line(x1+loc_xc,y4+loc_yc,x1+loc_xc,y6+loc_yc);
line(x4+loc_xc,y4+loc_yc,x4+loc_xc,y6+loc_yc);
}
The problem is that, Now I am confused at how to compute the rotated x and y values
I tried google and found this piece of code to rotate
int tempx=x1;
x1=tempx*cos(angle)-my1*sin(angle);
my1=tempx*sin(angle)+my1*cos(angle);
tempx=x2;
x2=tempx*cos(angle)-y2*sin(angle);
y2=tempx*sin(angle)+y2*cos(angle);
tempx=x3;
x3=tempx*cos(angle)-y3*sin(angle);
y3=tempx*sin(angle)+y3*cos(angle);
tempx=x4;
x4=tempx*cos(angle)-y4*sin(angle);
y4=tempx*sin(angle)+y4*cos(angle);
I tried this but it did not rotated shape properly but instead this code converts shape into some other strange shape. Also I have 4 x points and 6 y points, then how to compute new value for each point?
Any Idea? or hint?
Thanks
You cannot technically rotate a coordinate, as it is just a point with no notion of direction.
The code you found is used to rotate vectors, which is indeed what you'll need, but first you would need to convert your coordinates into vectors. You can think of vectors as being the invisible line that connects the center of the figure to your points, so it consists of two points, which in your case you can assume one to be (0,0) since you later increment them with the center of the figure, and the other corresponds to your pairs such as (x2,my1), (x2,y5)... as used in your line drawing function.
Your code should actually become something like this:
PS: unless you pass in only the perfect angles, you cannot expect the figure to always work with integer coordinates. You would need them to be doubles)
int point1x, point1y;
point1x = (int) round(x2*cos(angle)-m1y*sin(angle));
point1y = (int) round(x2*sin(angle)+m1y*cos(angle));
int point2x, point2y;
point2x = (int) round(x2*cos(angle)-y5*sin(angle));
point2y = (int) round(x2*sin(angle)+y5*cos(angle));
...
line(point1x+loc_xc, point1y+loc_yc, point2x+loc_xc, point2y+loc_yc);
and so on.
Also, make sure your angle value is in radians, as both sin() and cos() functions assume that. If you are passing down degrees, convert them to radians first with the following formula:
double pi = acos(-1);
double rotation_angle = (double) angle / 180.0 * pi;
and use rotation_angle instead of angle in the code above.

Ray tracing vectors

So I decided to write a ray tracer the other day, but I got stuck because I forgot all my vector math.
I've got a point behind the screen (the eye/camera, 400,300,-1000) and then a point on the screen (a plane, from 0,0,0 to 800,600,0), which I'm getting just by using the x and y values of the current pixel I'm looking for (using SFML for rendering, so it's something like 267,409,0)
Problem is, I have no idea how to cast the ray correctly. I'm using this for testing sphere intersection(C++):
bool SphereCheck(Ray& ray, Sphere& sphere, float& t)
{ //operator * between 2 vec3s is a dot product
Vec3 dist = ray.start - sphere.pos; //both vec3s
float B = -1 * (ray.dir * dist);
float D = B*B - dist * dist + sphere.radius * sphere.radius; //radius is float
if(D < 0.0f)
return false;
float t0 = B - sqrtf(D);
float t1 = B + sqrtf(D);
bool ret = false;
if((t0 > 0.1f) && (t0 < t))
{
t = t0;
ret = true;
}
if((t1 > 0.1f) && (t1 < t))
{
t = t1;
ret = true;
}
return ret;
}
So I get that the start of the ray would be the eye position, but what is the direction?
Or, failing that, is there a better way of doing this? I've heard of some people using the ray start as (x, y, -1000) and the direction as (0,0,1) but I don't know how that would work.
On a side note, how would you do transformations? I'm assuming that to change the camera angle you just adjust the x and y of the camera (or the screen if you need a drastic change)
The parameter "ray" in the function,
bool SphereCheck(Ray& ray, Sphere& sphere, float& t)
{
...
}
should already contain the direction information and with this direction you need to check if the ray intersects the sphere or not. (The incoming "ray" parameter is the vector between the camera point and the pixel the ray is sent.)
Therefore the local "dist" variable seems obsolete.
One thing I can see is that when you create your rays you are not using the center of each pixel in the screen as the point for building the direction vector. You do not want to use just the (x, y) coordinates on the grid for building those vectors.
I've taken a look at your sample code and the calculation is indeed incorrect. This is what you want.
http://www.csee.umbc.edu/~olano/435f02/ray-sphere.html (I took this course in college, this guy knows his stuff)
Essentially it means you have this ray, which has an origin and direction. You have a sphere with a point and a radius. You use the ray equation and plug it into the sphere equation and solve for t. That t is the distance between the ray origin and the intersection point on the spheres surface. I do not think your code does this.
So I get that the start of the ray would be the eye position, but what is the direction?
You have camera defined by vectors front, up, and right (perpendicular to each other and normalized) and "position" (eye position).
You also have width and height of viewport (pixels), vertical field of view (vfov) and horizontal field of view (hfov) in degrees or radians.
There are also 2D x and y coordinates of pixel. X axis (2D) points to the right, Y axis (2D) points down.
For a flat screen ray can be calculated like this:
startVector = eyePos;
endVector = startVector
+ front
+ right * tan(hfov/2) * (((x + 0.5)/width)*2.0 - 1.0)
+ up * tan(vfov/2) * (1.0 - ((y + 0.5f)/height)*2.0);
rayStart = startVector;
rayDir = normalize(endVector - startVector);
That assumes that screen plane is flat. For extreme field of view angles (fov >= 180 degreess) you might want to make screen plane spherical, and use different formulas.
how would you do transformations
Matrices.