Rotating a Cgpoint Around Another Cgpoint

Rotating a CGPoint around another CGPoint

This is really a maths question. In Swift, you want something like:

func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = target.x - origin.x
let dy = target.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * CGFloat(M_PI / 180.0) // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}

There are lots of ways to simplify this, and it's a perfect case for an extension to CGPoint, but I've left it verbose for clarity.

What is the best way to rotate a CGPoint on a grid?

You can also use that:

rotatedPoint = CGPointApplyAffineTransform(initialPoint, CGAffineTransformMakeRotation(angle));

EDIT: to perform rotation around custom point you must do like Adam described in his answer. Using CGAffineTransform it must look something like:

CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(customCenter.x, customCenter.y);
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(angle);

CGAffineTransform customRotation = CGAffineTransformConcat(CGAffineTransformConcat( CGAffineTransformInvert(translateTransform), rotationTransform), translateTransform);

rotatedPoint = CGPointApplyAffineTransform(initialPoint, customRotation);

Swift: make rotation of point in 2D

You are really describing two rotations with your example:

  1. The points are rotated by -90 degrees around the center of the 3x3 grid. When this happens, the topLeft point becomes bottomLeft, and topRight becomes topLeft.
  2. Then you rotate those points around the center of the square 90 degrees (ie. the other direction) to make them topLeft and topRight again.

Using this function from this answer:

func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = target.x - origin.x
let dy = target.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * .pi / 180 // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}

let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
let squareCenter = CGPoint(x: 2.5, y: 1.5)

// First rotate around the center of the 3 x 3 square
let centerOfRotation = CGPoint(x: 1.5, y: 1.5)

let tl1 = rotatePoint(target: topLeft, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 1)
let tr1 = rotatePoint(target: topRight, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 0)
let sc1 = rotatePoint(target: squareCenter, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1.5 y 0.5)

// Now rotate the 1x1 square the other way around new position of square center
let tl2 = rotatePoint(target: tl1, aroundOrigin: sc1, byDegrees: 90) // (x 1 y 0)
let tr2 = rotatePoint(target: tr1, aroundOrigin: sc1, byDegrees: 90) // (x 2 y 0)

Note: As @MBo noted in the comments, if your cell is always 1x1, it is sufficient to rotate the center of your cell and then just add and subtract the 0.5 offsets to find the four corners.

AffineTransform a CGPoint

Your code to calculate the transform is correct. All you need to do is apply the transform to the point.

CGRect bounds = self.bounds;
CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, center.x, center.y);
transform = CGAffineTransformRotate(transform, DEGREES_TO_RADIANS(degreesOfRotation));
transform = CGAffineTransformTranslate(transform, -center.x, -center.y);

CGPoint point = CGPointMake(bounds.size.width - 10, center.y); // some point
CGPoint point2 = CGPointApplyAffineTransform(point, transform); // some point rotated about the center of the view

CGPoint rotation changes distance from origin

CGAffineTransform is a handy tool when it comes to rotation, translation, and scaling. To make sure a point is rotated properly, you must translate it to the origin, rotate it, and then translate it back.

To complete your transformation, something like the following should do the trick:

CGPoint pointToRotate = CGPointMake(30, 30);
float angleInRadians = DEGREES_TO_RADIANS(90);
CGPoint distanceFromOrigin = CGPointMake(0 - pointToRotate.x, 0 - pointToRotate.y);

CGAffineTransform translateToOrigin = CGAffineTransformMakeTranslation(distanceFromOrigin.x, distanceFromOrigin.y);
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(angleInRadians);
CGAffineTransform translateBackFromOrigin = CGAffineTransformInvert(translateToOrigin);

CGAffineTransform totalTransform = CGAffineTransformConcat(translateToOrigin, rotationTransform);
totalTransform = CGAffineTransformConcat(totalTransform, translateBackFromOrigin);

pointToRotate = CGPointApplyAffineTransform(pointToRotate, totalTransform);

And here is the documentation on CGAffineTransform, if you'd like to review it further: http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html

Please let me know if you need anything else if this doesn't solve your problem!

How to determine closest CGPoint with an angle and another CGPoint

As @trumpetlicks said you cant find the closest point like that, but I guess I understood what you want and that function -(void) rotateAroundPoint:(CGPoint)rotationPoint angle:(CGFloat)angle you are trying to use is perfectly fine to achieve what you want.

Sample Image

all you need to do is choose float radius.

you know your current point and lets say your radius is 1, basically you can calculate your previous point without a degree, assuming 0 degrees is left of your point and lets say your point is 200,200 with 1 radius 0 degree your previous point automatically becomes 199,200.
So now you have a reference point so now calculate the point you want to move your sprite:

//choose a feasable radius
float radius = 0.5;
//position_ is your preknown position as you said
//find a the point to roate
//position_.x-radius is always 0 degrees of your current point
CGFloat x = cos(rads) * ((position_.x-radius)-position_.x) - sin(rads) * ((position_.y)-position_.y) + position_.x;
CGFloat y = sin(rads) * ((position_.x-radius)-position_.x) + cos(rads) * ((position_.y)-position_.y) + position_.y;

//get the new point
CGPoint newLocation = ccp(x, y);

Setting a rotation point for CGAffineTransformMakeRotation Swift

What you are looking for is the anchorPoint property of your views' layers. This property basically represents the handle that is be used while the view is being moved around.

It defaults to the center of your view so and that why you are always seeing your view rotating form the middle.

You can use this great method i've found here on SO to change the anchorPoint of you views to the top (use CGPointMake(0, 0.5f))

// Swift version
// Place this before you set the transform property
setAnchorPoint(CGPointMake(0, 0.5), view: imageOne)
setAnchorPoint(CGPointMake(0, 0.5), view: imageTwo)
setAnchorPoint(CGPointMake(0, 0.5), view: imageThree)

func setAnchorPoint(anchorPoint: CGPoint, view: UIView) {
var newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y)
var oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y)

newPoint = CGPointApplyAffineTransform(newPoint, view.transform)
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform)

var position : CGPoint = view.layer.position

position.x -= oldPoint.x
position.x += newPoint.x;

position.y -= oldPoint.y;
position.y += newPoint.y;

view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}

This is the objective c version of the same code

// Obj-c version
// Place this before you set the transform property
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageOne];
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageTwo];
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageThree];

-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x,
view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
view.bounds.size.height * view.layer.anchorPoint.y);

newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);

CGPoint position = view.layer.position;

position.x -= oldPoint.x;
position.x += newPoint.x;

position.y -= oldPoint.y;
position.y += newPoint.y;

view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}

I'd encourage you to try to understand yourself what this code is doing once you have seen what the anchorPoint property represents. (the method is by user: Anand K)



Related Topics



Leave a reply



Submit