I need to implement a 2d shape rotate function - c++

this is the formular but i dont know how to implement it. can someone please help
rectangle::rectangle() //rectangle constructor
{
bl.real() = 0; //bottom
bl.imag() = 0; //left
tr.real() = 1; //top
tr.imag() = 1; //right
}
complex<double> rectangle::get_bl() const
{
return bl;
}
complex<double> rectangle::get_tr() const
{
return tr;
}
void rectangle::rotate(double angle)
{
//not sure how to do it tr = tr.real() * cos(angle) + tr.imag() *cos(angle);
}
main
rectangle r;
r.rotate(90);
expected output (not 100% sure)
0 0 -1 1

Move your shape to (0, 0) temporarily (formula assumes you are rotating about origin, so move the bottom-left corner to (0, 0)).
Apply formula.
Move it back.
if (tr.real() < bl.real()) {
float tempX = tr.real() - bl.real();
float tempY = tr.imag() - bl.imag();
} else {
float tempX = bl.real() - tr.real();
float tempY = bl.imag() - tr.imag();
}
tr.real() = tempX * cos(theta) - tempY * sin(theta)
tr.imag() = tempx * sin(theta) + tempY * cos(theta)

The formula is basically saying:
new_x = shape.point[i].x*cos(angle) - shape.point[i].y*sin(angle)
new_y = shape.point[i].x*sin(angle) + shape.point[i].y*cos(angle)
shape.point[i].x = new_x
shape.point[i].y = new_y
angle is in radians, to convert from degrees to radians use
degree*pi/180 where pi is the constant 3.14...
you will need to do this for each point on the shape to fully rotate the shape by the desired degree.
This formula also assumes that the points are centered around (0,0), i.e. the center of the shape is (0,0) and all points are relative to that center.
One tip, if applicable, try and store shapes as points, going clockwise from the 0th point. for instance, this rectangle will be:
point[0] = {-1, 1}
point[1] = { 1, 1}
point[2] = { 1,-1}
point[3] = {-1,-1}
To convert from tl, br to points you will need to do something similar to:
point[0] = {tl.x, tl.y}
point[1] = {br.x, tl.y}
point[2] = {br.x, br.y}
point[3] = {tl.x, br.y}

Related

Ray casting in rotating fan configuration produces point cloud with curvature, how to eliminate curvature?

I'm attempting to perform an intersection test using ray casting (not sure if correct term so please forgive me if not) and am outputting the intersections as a point cloud, and the point cloud shows curvature (on the Z-axis only, the point cloud is completely flat on the Y axis, and the horizontal axis in this image is the X axis):
I borrowed concepts from the Scratchapixel site, specifically http://scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection.
Essentially, I am generating 16 rays, all with the same origin vector. The direction vectors start at +15 degrees on the YZ plane, and continue in increments of -2 degrees down to -15. I have an axis aligned bounding box that I am testing intersection with. I use a rotation transform to rotate the 16 rays CCW around the Z axis. I am performing the intersection test for all 16 rays each 0.1 degrees, and if it returns true, I add the point to the point cloud.
Here's my intersection code:
bool test_intersect(Box b, Ray r, Vec3f& intersect_point)
{
float txmin = 0.0f, txmax = 0.0f, tymin = 0.0f, tymax = 0.0f, tzmin = 0.0f, tzmax = 0.0f;
float t_min = 0.0f, t_max = 0.0f, t = 0.0f;
// Determine inverse direction of ray to alleviate 0 = -0 issues
Vec3f inverse_direction(1 / r.direction.x, 1 / r.direction.y, 1 / r.direction.z);
// Solving box_min/box_max0 = O + Dt
txmin = (b.box_min.x - r.origin.x) * inverse_direction.x;
txmax = (b.box_max.x - r.origin.x) * inverse_direction.x;
tymin = (b.box_min.y - r.origin.y) * inverse_direction.y;
tymax = (b.box_max.y - r.origin.y) * inverse_direction.y;
tzmin = (b.box_min.z - r.origin.z) * inverse_direction.z;
tzmax = (b.box_max.z - r.origin.z) * inverse_direction.z;
// Depending on direction of ray tmin may > tmax, so we may need to swap
if (txmin > txmax) std::swap(txmin, txmax);
if (tymin > tymax) std::swap(tymin, tymax);
if (tzmin > tzmax) std::swap(tzmin, tzmax);
t_min = txmin;
t_max = txmax;
// If t-value of a min is greater than t-value of max,
// we missed the object in that plane.
if ((t_min > tymax) || (tymin > t_max))
return false;
if (tymin > t_min)
t_min = tymin;
if (tymax < t_max)
t_max = tymax;
if ((t_min > tzmax) || (tzmin > t_max))
return false;
if (tzmin > t_min)
t_min = tzmin;
if (tzmax < t_max)
t_max = tzmax;
if (t_min > 0)
t = t_min;
else
if (t_max > 0)
t = t_max;
else
return false;
intersect_point.x = r.origin.x + r.direction.x * t;
intersect_point.y = r.origin.y + r.direction.y * t;
intersect_point.z = r.origin.z + r.direction.z * t;
return true;
}
And my rotation:
// Rotation around z axis, for rotating array and checking beam intersections
void transform_rotate_z(Vec3f& in_vector, float angle)
{
float radians = angle * (M_PI / 180);
float result_x = cos(radians) * in_vector.x + -sin(radians) * in_vector.y;
float result_y = sin(radians) * in_vector.x + cos(radians) * in_vector.y;
in_vector.x = result_x;
in_vector.y = result_y;
}
I have racked my brain for quite a while but I can't seem to determine how I can prevent this curvature, I'm sure I'm overlooking something simple. I'd be grateful for any help you can provide.

How draw axis of ellipse

I am using fitellipse of Opencv and C++, and I'm getting these values:
/// Find the rotated rectangles and ellipses for each contour
vector<RotatedRect> minRect( contours.size() );
vector<RotatedRect> minEllipse( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
minRect[i] = minAreaRect( Mat(contours[i]) );
if( contours[i].size() > 5 )
minEllipse[i] = fitEllipse( Mat(contours[i]) );
// ...
}
float xc = minEllipse[element].center.x;
float yc = minEllipse[element].center.y;
float a = minEllipse[element].size.width / 2;
float b = minEllipse[element].size.height / 2;
float theta = minEllipse[element].angle;
But with these values how can I draw the axis of an ellipse, for example of the following ellipse?
NOTE: Element is an ellipse stored in minEllipse.
You can use minEllipse[element].points to get the four corners of the rotated bounding rectangle, like described here.
Then you only need to calculate the average of the two points on each side of the rectangle to get the endpoints for the axes...
Point2f vertices[4];
minEllipse[element].points(vertices);
line(image, (vertices[0] + vertices[1])/2, (vertices[2] + vertices[3])/2, Scalar(0,255,0));
line(image, (vertices[1] + vertices[2])/2, (vertices[3] + vertices[0])/2, Scalar(0,255,0));
You are probably looking for those formulas:
ct = cos(theta)
st = sin(theta)
LongAxix0.x = xc - a*ct
LongAxis0.y = yc - a*st
LongAxis1.x = xc + a*ct
LongAxix1.y = yc + a*st
ShortAxix0.x = xc - b*st
ShortAxix0.y = yc + b*ct
ShortAxis1.x = xc + b*st
ShortAxix2.y = yc - b*ct
But with these values how can I draw the axis of an ellipse?
The axis of the ellipse are passing through its centre:
float xc = minEllipse[element].center.x;
float yc = minEllipse[element].center.y;
the start and end points of the axis could be at an offset from the centre defined by the ellipse's width and height, i.e.:
// horizontal axis start/ end point
// coordinates
int HxStart = xc - size.width / 2;
int HyStart = yc;
int HxEnd = xc + size.width / 2;
int HyEnd = yc;
// points
Point Hstart(HxStart, HyStart);
Point Hend(HxEnd, HyEnd);
// horizontal axis
Line horizontalAxis(Hstart, Hend);
// vertical axis start/ end point
int VxStart = xc;
int VyStart = yc - size.height / 2;
int VxEnd = xc;
int VyEnd = yc + size.height / 2;
// ----//----
Now, you can rotate the axis (the above for points) by the provided angle theta, around the centre of the ellipse.
Having the above and knowing how to construct a line you can build the two axis at any given angle theta.

Rotating around a sphere using OpenGL and gluLookAt

Alright, so I'm trying to click and drag to rotate around an object using C++ and OpenGL. The way I have it is to use gluLookAt centered at the origin and I'm getting coordinates for the eye by using parametric equations for a sphere (eyex = 2* cos(theta) * sin(phi); eyey = 2* sin(theta) * sin(phi); eyez = 2* cos(phi);). This works mostly, as I can click and rotate horizontally, but when I try to rotate vertically it makes tight circles instead of rotating vertically. I'm trying to get the up vector by using the position of the camera and a vecter at a 90 degree angle along the x-z plane and taking the cross product of that.
The code I have is as follows:
double dotProduct(double v1[], double v2[]) {
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void mouseDown(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
xpos = x;
ypos = y;
}
}
void mouseMovement(int x, int y) {
diffx = x - xpos;
diffy = y - ypos;
xpos = x;
ypos = y;
}
void camera (void) {
theta += 2*PI * (-diffy/glutGet(GLUT_SCREEN_HEIGHT));
phi += PI * (-diffx/glutGet(GLUT_WINDOW_WIDTH));
eyex = 2* cos(theta) * sin(phi);
eyey = 2* sin(theta) * sin(phi);
eyez = 2* cos(phi);
double rightv[3], rightt[3], eyes[3];
rightv[0] = 2* cos(theta + 2/PI) * sin(phi);
rightv[1] = 0;
rightv[2] = 2* cos(phi);
rightt[0] = rightv[0];
rightt[1] = rightv[1];
rightt[2] = rightv[2];
rightv[0] = rightv[0] / sqrt(dotProduct(rightt, rightt));
rightv[1] = rightv[1] / sqrt(dotProduct(rightt, rightt));
rightv[2] = rightv[2] / sqrt(dotProduct(rightt, rightt));
eyes[0] = eyex;
eyes[1] = eyey;
eyes[2] = eyez;
upx = (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[2] + (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[1];
upy = (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[0] + (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[2];
upz = (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[1] + (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[0];
diffx = 0;
diffy = 0;
}
I am somewhat basing things off of this but it doesn't work, so I tried my way instead.
This isn't exactly a solution for the way you are doing it but I did something similar the other day. I did it by using DX's D3DXMatrixRotationAxis and D3DXVec3TransformCoord The math behind the D3DXMatrixRotationAxis method can be found at the bottom of the following page: D3DXMatrixRotationAxis Math use this if you are unable to use DX. This will allow you to rotate around any axis you pass in. In my object code I keep track of a direction and up vector and I simply rotate each of these around the axis of movement(in your case the yaw and pitch).
To implement the fixed distance camera like this I would simply do the dot product of the current camera location and the origin location (if this never changes then you can simply do it once.) and then move the camera to the origin rotate it the amount you need then move it back with its new direction and up values.

opengl trackball

I am trying to rotate opengl scene using track ball. The problem i am having is i am getting rotations opposite to direction of my swipe on screen. Here is the snippet of code.
prevPoint.y = viewPortHeight - prevPoint.y;
currentPoint.y = viewPortHeight - currentPoint.y;
prevPoint.x = prevPoint.x - centerx;
prevPoint.y = prevPoint.y - centery;
currentPoint.x = currentPoint.x - centerx;
currentPoint.y = currentPoint.y - centery;
double angle=0;
if (prevPoint.x == currentPoint.x && prevPoint.y == currentPoint.y) {
return;
}
double d, z, radius = viewPortHeight * 0.5;
if(viewPortWidth > viewPortHeight) {
radius = viewPortHeight * 0.5f;
} else {
radius = viewPortWidth * 0.5f;
}
d = (prevPoint.x * prevPoint.x + prevPoint.y * prevPoint.y);
if (d <= radius * radius * 0.5 ) { /* Inside sphere */
z = sqrt(radius*radius - d);
} else { /* On hyperbola */
z = (radius * radius * 0.5) / sqrt(d);
}
Vector refVector1(prevPoint.x,prevPoint.y,z);
refVector1.normalize();
d = (currentPoint.x * currentPoint.x + currentPoint.y * currentPoint.y);
if (d <= radius * radius * 0.5 ) { /* Inside sphere */
z = sqrt(radius*radius - d);
} else { /* On hyperbola */
z = (radius * radius * 0.5) / sqrt(d);
}
Vector refVector2(currentPoint.x,currentPoint.y,z);
refVector2.normalize();
Vector axisOfRotation = refVector1.cross(refVector2);
axisOfRotation.normalize();
angle = acos(refVector1*refVector2);
I recommend artificially setting prevPoint and currentPoint to (0,0) (0,1) and then stepping through the code (with a debugger or with your eyes) to see if each part makes sense to you, and the angle of rotation and axis at the end of the block are what you expect.
If they are what you expect, then I'm guessing the error is in the logic that occurs after that. i.e. you then take the angle and axis and convert them to a matrix which gets multiplied to move the model. A number of convention choices happen in this pipeline --which if swapped can lead to the type of bug you're having:
Whether the formula assumes the angle is winding left or right handedly around the axis.
Whether the transformation is meant to rotate an object in the world or meant to rotate the camera.
Whether the matrix is meant to operate by multiplication on the left or right.
Whether rows or columns of matrices are contiguous in memory.

Bullet algorithm having trouble with rotation on the X

Here is what I'm trying to do. I'm trying to make a bullet out of the center of the screen. I have an x and y rotation angle. The problem is the Y (which is modified by rotation on the x) is really not working as intended. Here is what I have.
float yrotrad, xrotrad;
yrotrad = (Camera.roty / 180.0f * 3.141592654f);
xrotrad = (Camera.rotx / 180.0f * 3.141592654f);
Vertex3f Pos;
// get camera position
pls.x = Camera.x;
pls.y = Camera.y;
pls.z = Camera.z;
for(float i = 0; i < 60; i++)
{
//add the rotation vector
pls.x += float(sin(yrotrad)) ;
pls.z -= float(cos(yrotrad)) ;
pls.y += float(sin(twopi - xrotrad));
//translate camera coords to cube coords
Pos.x = ceil(pls.x / 3);
Pos.y = ceil((pls.y) / 3);
Pos.z = ceil(pls.z / 3);
if(!CubeIsEmpty(Pos.x,Pos.y,Pos.z)) //remove first cube that made contact
{
delete GetCube(Pos.x,Pos.y,Pos.z);
SetCube(0,Pos.x,Pos.y,Pos.z);
return;
}
}
This is almost identical to how I move the player, I add the directional vector to the camera then find which cube the player is on. If I remove the pls.y += float(sin(twopi - xrotrad)); then I clearly see that on the X and Z, everything is pointing as it should. When I add pls.y += float(sin(twopi - xrotrad)); then it almost works, but not quite, what I observed from rendering out spheres of the trajector is that the furthur up or down I look, the more offset it becomes rather than stay alligned to the camera's center. What am I doing wrong?
Thanks
What basically happens is very difficult to explain, I'd expect the bullet at time 0 to always be at the center of the screen, but it behaves oddly. If i'm looking straight at the horizon to +- 20 degrees upward its fine but then it starts not following any more.
I set up my matrix like this:
void CCubeGame::SetCameraMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(Camera.rotx,1,0,0);
glRotatef(Camera.roty,0,1,0);
glRotatef(Camera.rotz,0,0,1);
glTranslatef(-Camera.x , -Camera.y,-Camera.z );
}
and change the angle like this:
void CCubeGame::MouseMove(int x, int y)
{
if(!isTrapped)
return;
int diffx = x-lastMouse.x;
int diffy = y-lastMouse.y;
lastMouse.x = x;
lastMouse.y = y;
Camera.rotx += (float) diffy * 0.2;
Camera.roty += (float) diffx * 0.2;
if(Camera.rotx > 90)
{
Camera.rotx = 90;
}
if(Camera.rotx < -90)
{
Camera.rotx = -90;
}
if(isTrapped)
if (fabs(ScreenDimensions.x/2 - x) > 1 || fabs(ScreenDimensions.y/2 - y) > 1) {
resetPointer();
}
}
You need to scale X and Z by cos(xradrot). (In other words, multiply by cos(xradrot)).
Imagine you're pointing straight down the Z axis but looking straight up. You don't want the bullet to shoot down the Z axis at all, this is why you need to scale it. (It's basically the same thing that you're doing between X and Z, but now doing it on the XZ vector and Y.)
pls.x += float(sin(yrotrad)*cos(xrotrad)) ;
pls.z -= float(cos(yrotrad)*cos(xrotrad)) ;
pls.y += float(sin(twopi - xrotrad));