iOS OpenGL ES 2.0 Rotate 1 Point Cartesian X Radians about Origin - ios

I need to rotate a single point expressed in cartesian XYZ coordinates about the Z axis. The following 2 attempts are not working properly - I believe the first one is more correct..
I tried to rotate the points using the math on this website: http://farside.ph.utexas.edu/teaching/336k/newton/node153.html
// Rotate the XYZ coordinate for the pin image
if ( [satName isEqualToString:#"pin"] ) {
double x = xyz.x;
double y = xyz.y;
double radians = self.timeSinceOpenGlStarted;
x = x * cos(radians) + y * sin(radians);
y = -x * sin(radians) + y * cos(radians);
xyz.x = x;
xyz.z = y;
}
I also tried this function by extracting the points after GLKMatrix4Rotate:
// This function rotates XYZ a certain of radians about the origin and gives back XYZ
- (GLKVector4)rotateXYZCoordinates:(XYZ*)coords {
// Get the current modelview matrix
GLKMatrix4 currMat = self.effect.transform.modelviewMatrix;
// Print the coords before
NSLog(#"Before: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation Before: %f %f %f",currMat.m00,currMat.m10,currMat.m20);
// Construct the rows in the new matrix
float d = sqrt( pow(currMat.m00,2) + pow(currMat.m10,2) + pow(currMat.m20,2) );
GLKVector4 columnToInsert0 = GLKVector4Make(d, 0, 0, coords->x);
GLKVector4 columnToInsert1 = GLKVector4Make(0, d, 0, coords->y);
GLKVector4 columnToInsert2 = GLKVector4Make(0, 0, d, coords->z);
GLKVector4 columnToInsert3 = GLKVector4Make(0, 0, 0, 1);
// Build the new Matrix
GLKMatrix4 noTranslationInfo = GLKMatrix4SetRow(currMat, 0, columnToInsert0);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 1, columnToInsert1);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 2, columnToInsert2);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 3, columnToInsert3);
// Throw the world translation coordinates in the matrix
noTranslationInfo.m30 = ( noTranslationInfo.m30 );
noTranslationInfo.m31 = ( noTranslationInfo.m31 );
noTranslationInfo.m32 = ( noTranslationInfo.m32 );
// Now rotate the matrix so many angles
noTranslationInfo = GLKMatrix4Rotate(noTranslationInfo, self.timeSinceOpenGlStarted, 0, 0, 1);
// Latch the output
coords->x = noTranslationInfo.m30;
coords->y = noTranslationInfo.m31;
coords->z = noTranslationInfo.m32;
// Print the coords After
NSLog(#"AFter: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation After: %f %f %f",noTranslationInfo.m00,noTranslationInfo.m10,noTranslationInfo.m20);
}
I have a globe spinning along the Z axis and a billboarded sprite specified at a specific spherical coordinate ( representing a lat/lon location ) and need the ability to have the point rotate along with the earth or not.
What am I doing wrong? How do I calculate a new X and Y coordinate ( Z is constant ) to rotate an XYZ point around the Z axis when I know the number of radians I want to rotate? Thanks!
UPDATE: Now I've tried this:
// Rotate the XYZ coordinate for the pin image
/* http://www.blitzbasic.com/Community/posts.php?topic=70536
;rotate offset around Z axis
newx# = x# * Cos#(zr#) - y# * Sin#(zr#)
newy# = x# * Sin#(zr#) + y# * Cos#(zr#)
x# = newx#
y# = newy#
;rotate offset around X axis
newy# = y# * Cos#(xr#) - z# * Sin#(xr#)
newz# = y# * Sin#(xr#) + z# * Cos#(xr#)
y# = newy#
z# = newz#
;rotate offset around Y axis
newx# = z# * Sin#(-yr#) + x# * Cos#(-yr#)
newz# = z# * Cos#(-yr#) - x# * Sin#(-yr#)
x# = newx#
z# = newz#
*/
if ( [satName isEqualToString:#"pin"] && self.shouldAnimate == YES ) {
//NSLog(#"ONE %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
double x = xyz.x;
double y = xyz.y;
double z = xyz.z;
NSLog(#"%f",self.timeSinceOpenGlStarted); // Values like: 32521.473728
double zr = self.timeSinceOpenGlStarted;
double yr = 0.0f;
double xr = 0.0f;
// Rotations must be in this order: Z then X then Y
// Rotate around Z
x = x * cos(zr) - y * sin(zr);
y = x * sin(zr) + y * cos(zr);
// Rotate around X
y = y * cos(xr) - z * sin(xr);
z = y * sin(xr) + z * cos(xr);
// Rotate around Y
x = z * sin(-yr) + x * cos(-yr);
z = z * cos(-yr) + x * sin(-yr);
// Get the coordinates back
xyz.x = x;
xyz.y = y;
xyz.z = z;
//NSLog(#"TWO %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
}
The problem is that my image dances around the lat/lon it should be at - it almost does a figure 8.

I either don't understand what you want to achieve or these methods of yours are a bit strange. If you need to rotate a single point around centre (0,0,0) around Z axis (on the XY plane) then you should use something like this:
float x, y;
float currentAngle;
float radius = sqrt(x*x + y*y);
x = radius*cos(currentAngle);
y = radius*sin(currentAngle);
To make it even easier you can simply use radius (which should be constant in your case) and the angle in radians. In this case you only need last 2 lines of this snippet.

It looks like you are adding each frame to your angle. You can compute an "delta angle" just the angle to rotate from the previous frame, or to use the angle as it is now but apply the rotation to the initial orientation, not to last frame's result.

Related

Drawing Circle/SemiCircle in Metal

I am new to metal. I want to draw a semi circle. Any ideas or suggestions to draw a semi circle. I tried using tesselation
float u = patch_coord.x;
float v = patch_coord.y;
float w = patch_coord.z;
float x = u * patchIn.control_points[0].position.x + v * patchIn.control_points[1].position.x + w * patchIn.control_points[2].position.x;
float y = u * patchIn.control_points[0].position.y + v * patchIn.control_points[1].position.y + w * patchIn.control_points[2].position.y;
float2 tangent = normalize(float2(x, y)) / 25;
When I normalize always it is in the middle of the screen. I want to draw circle in my finger touch.

Finding a desired point based on an objects velocity and rotation

I'm looking to find the point that is 200 pixels in front of an enemy object. My method to try calculate this point is this:
//all sprites start facing down, so to begin with the point 200 pixels infront of the sprite is its current pos -200 on the y axis.
CGPoint predictedPoint = CGPointMake(self.position.x, self.position.y - 200);
//get the direction of this vector from the current position.
predictedPoint = [Utilities MinusVector:predictedPoint Vector2:self.position];
predictedPoint = [Utilities CGPointNormalize:predictedPoint];
//multiply it by 200 to get 200 pixels ahead.
predictedPoint = [Utilities MultiplyVector:predictedPoint Scalar:200];
//work out which way to rotate the enemy based on its velocity. (this code works as the enemies face the way they move!)
CGPoint facingVector = [Utilities MinusVector:self.position Vector2:CGPointMake(self.position.x + self.velocity.x, self.position.y + self.velocity.y)];
float theta = (atan2f(facingVector.y, facingVector.x) - SK_DEGREES_TO_RADIANS(90.0f));
//rotate
float cs = cosf(theta);
float sn = sinf(theta);
float px = predictedPoint.x * cs - predictedPoint.y * sn;
float py = predictedPoint.x * sn + predictedPoint.y * cs;
CGPoint thePoint = CGPointMake(px, py);
NSLog(#"Player x: %f. thePoint x: %f. Player y: %f. thePoint y: %f.", self.position.x, px, self.position.y, py);
So the calculation should be
green.center.x = triangle.center.x + 200 * cos( theta );
green.center.y = triangle.center.y + 200 * sin( theta );
where theta is the current rotation angle of the triangle. This assumes that theta == 0 has the triangle pointing to the right. If the 0 angle has the sprite pointing down, then I think you need to subtract M_PI_2, e.g.
green.center.x = triangle.center.x + 200 * cos( theta - M_PI_2 );
green.center.y = triangle.center.y + 200 * sin( theta - M_PI_2 );

Center of rotated cv::Rect

I have an image, and I place a rectangle on the image. Then I rotate the image. How do I get the center of the rectangle on the rotated image?
Or can I rotate a rectangle somehow to put on rotated image? I think in this case rotation must be done along same point with point used to rotate image.
This is the image with a rectangle placed on it.
This is the rotated image.
Here is the code I use to rotate my image:
cv::Mat frame, frameRotated;
frame = cv::imread("lena.png");
cv::Rect rect(225,250,150,150);
cv::rectangle(frame, rect, cv::Scalar(0,0,255),2);
int theta = 30;
double radians = theta * PI / 180.0;
double sin = abs(std::sin(radians));
double cos = abs(std::cos(radians));
int newWidth = (int) (frame.cols * cos + frame.rows * sin);
int newHeight = (int) (frame.cols * sin + frame.rows * cos);
cv::Mat targetMat(cv::Size(newWidth, newHeight), frame.type());
int offsetX = (newWidth - frame.cols) / 2;
int offsetY = (newHeight - frame.rows) / 2;
frame.copyTo(targetMat.rowRange(offsetY, offsetY + frame.rows).colRange(offsetX, offsetX + frame.cols));
cv::Point2f src_center(targetMat.cols/2.0F, targetMat.rows/2.0F);
cv::Mat rot_mat = cv::getRotationMatrix2D(src_center, theta, 1.0);
cv::warpAffine(targetMat, frameRotated, rot_mat, targetMat.size());
imshow("frame", frame);
imshow("rotated frame", frameRotated);
EDIT
Suppose I have a point in the rotated image, how do I get corresponding point in the original image using rotation matrix?
You only need to use rot_mat to transform the original center of the rect. I tested the below and it works:
cv::Rect r(250, 350, 20, 30);
cv::Point2d c(r.x + r.width / 2, r.y + r.height / 2);
// c is center of rect
// get c's location in targetMat when frame is copied
c.x += offsetX;
c.y += offsetY;
int theta = 30;
double radians = theta * M_PI / 180.0;
cv::Point2d src_center(targetMat.cols/2.0F, targetMat.rows/2.0F);
cv::Mat rot_mat = cv::getRotationMatrix2D(src_center, theta, 1.0);
// now transform point using rot_mat
double *x = rot_mat.ptr<double>(0);
double *y = rot_mat.ptr<double>(1);
Point2d dst(x[0] * c.x + x[1] * c.y + x[2],
y[0] * c.x + y[1] * c.y + y[2]);
// dst is center of transformed rect
EDIT
To transform a point from the rotated image you just need to reverse the process:
// undo translation
Point2d dst1(dst.x - x[2], dst.y - y[2]);
// undo rotation
Point2d dst2(x[0] * dst1.x - x[1] * dst1.y, -y[0] * dst1.x + y[1] * dst1.y);
// undo shift
Point2d in_unrotated_image(dst2.x - offsetX, dst2.y - offsetY);
You can translate any point in your source Mat to rotated Mat by multiplying with the Rotation matrix.
If you need to translate X,Y and given T=1, you can do this by Mat multiplication
| cosθ sinθ Tx | | X | | _X |
| | * | Y | = | |
| -sinθ cosθ Ty | | 1 | | _Y |
where Tx and Ty is the translation along the x and y see OpenCV Doc.
Suppose you need to find the centre (cent_x,cent_y) of source Mat in rotated Mat
Mat rot_mat = getRotationMatrix2D(src_center, theta, 1.0); //Find the rotation matrix
Mat co_Ordinate = (Mat_<double>(3,1) << cent_x,cent_y,1); //Create 3x1 matrix with input co-ordinates.
Mat rst=rot_mat*co_Ordinate; // Multiply rotation matrix with input co-ordinate matrix
trans_x=(int)rst.at<double>(0,0); //First row of result will be x
trans_y=(int)rst.at<double>(1,0); //Second row of result will be y.
Hopes these helpful....
I've solved the problem in second question.
I used the same code provided in the accepted answer and create rotation matrix with minus theta.

Tile to CGPoint conversion with Retina display

I have a project that uses a tilemap. I have a separate tilemap for low-res (29x29 Tilesize) and high-res (58x58). I have these methods to calculate tileCoord to position and back again.
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
int x = (tileCoord.x * _tileMap.tileSize.width) + _tileMap.tileSize.width/2;
int y = (_tileMap.mapSize.height * _tileMap.tileSize.height) - (tileCoord.y * _tileMap.tileSize.height) - _tileMap.tileSize.height/2;
return ccp(x, y);
}
I got this from RayWenderLich and I do honeslty not understand how it works, and why it has to be so complicated. But this doesn't work when I use retina tilemaps, only on 480x320. Can someone clever come up with a way to make this work for HD? Does not have to work on low-res either, I do not plan on supporting sub-iOS 7.
I want the output to be in the low-res coordinate scale tho, as you might know, cocos2d does the resizing to HD for you. (By multiplying by two)
i think this will work
- (CGPoint)tileCoordForPosition:(CGPoint)position {
    int x = position.x/29;
    int y = ((11*29)-position.y) / 29;
    
    return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
    double x = tileCoord.x * 29 + 14.5;
    double y = (11*29) - (tileCoord.y * 29) - 14.5;
    return ccp(x, y);
}
Here you're trying to compute your map X coordinate:
int x = position.x / _tileMap.tileSize.width;
The problem here is that (as of v0.99.5-rc0, cocos2d generally uses points for positions, but CCTMXTiledMap always uses pixels for tileSize. On a low-res device, 1 point = 1 pixel, but on a Retina device, 1 point = 2 pixels. Thus on a Retina device, you need to multiply by 2.
You can use the CC_CONTENT_SCALE_FACTOR() macro to fix this:
int x = CC_CONTENT_SCALE_FACTOR() * position.x / _tileMap.tileSize.width;
Here you're trying to compute yoru map Y coordinate:
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
The extra math here is trying to account for the difference between Cocos2D's normal coordinate system and your map's flipped coordinate system. In standard Cartesian coordinates, the origin is at the lower left and Y coordinates increase as you move up. In a flipped coordinate system, the origin is at the upper left and Y coordinates increase as you move down. Thus you must subtract your position's Y coordinate from the height of the map (in scene units, which are points) to flip it to map coordinates.
The problem again is that _tileMap.tileSize is in pixels, not points. You can again fix that by using CC_CONTENT_SCALE_FACTOR():
CGFloat tileHeight = _tileMap.tileSize.height / CC_CONTENT_SCALE_FACTOR();
int y = ((_tileMap.mapSize.height * tileHeight) - position.y) / tileHeight;

Image conversion from Cartesian coordinate to polar coordinate

I was wondering if someone helps me understand how to convert the top image to the bottom image.
The images are available in the following link.The top image is in Cartesian coordinate. The bottom image is the converted image in polar coordinate
This is a basic rectangular to polar coordinate transform. To do the conversion, scan across the output image and treat x and y as if they were r and theta. Then use them as r and theta to look up the corresponding pixel in the input image. So something like this:
int x, y;
for (y = 0; y < outputHeight; y++)
{
Pixel* outputPixel = outputRowStart (y); // <- get a pointer to the start of the output row
for (x = 0; x < outputWidth; x++)
{
float r = y;
float theta = 2.0 * M_PI * x / outputWidth;
float newX = r * cos (theta);
float newY = r * sin (theta);
*outputPixel = getInputPixel ( newX, newY ); // <- Should probably do at least bilinear resampling in this function
outputPixel++;
}
}
Note that you may want to handle wrapping depending on what you're trying to achieve. The theta value wraps at 2pi.

Resources