I’m getting close to solving this problem but there is one part that is giving me trouble. I am trying to mimic a ruler object that the user can rotate, scale, and place on a canvas, and then trace along the edge to make a mark on the canvas. The issue I am having is getting the next point on the line regardless of where the user’s finger goes. I can trace the normal from the point back to a small transparent view along the edge that I have, but because of aliasing (or something) the line twitches as it gets drawn at any angle other than pure straight ones (0, 90, 180, 270). I’ve also tried to write a function like CGRectContainsPoint, except it takes an arbitrarily rotated rectangle but I had no success.
Here is the code that calculates the point based on the user’s touch:
- (CGPoint)perpendicularPointFromPoint:(CGPoint)point
{
CGPoint testPoint1 = point;
CGPoint testPoint2 = testPoint1;
CGPoint pointToUse = CGPointZero;
//Get the right angle to the current rotation, and make
//a unit vector in that direction
CGFloat rightAngle = mCurRotation + M_PI_2;
CGFloat xInc = cosf(rightAngle);
CGFloat yInc = sinf(rightAngle);
//Check both "forward" and "backward"
int counter = 0;
while(pointToUse.x == 0)
{
testPoint1.x += xInc;
testPoint1.y += yInc;
testPoint2.x -= xInc;
testPoint2.y -= yInc;
//mLineOutline is a small view on top of the ruler (transparent)
if([self.superview hitTest:testPoint1 withEvent:nil] == mLineOutline)
{
pointToUse = testPoint1;
}
else if([self.superview hitTest:testPoint2 withEvent:nil] == mLineOutline)
{
pointToUse = testPoint2;
}
else if(counter++ > 1000) //Neither ray intersects the ruler
pointToUse.x = -1.f;
}
return CGPointMake(roundf(pointToUse.x), roundf(pointToUse.y));
}
However, because of whatever reason, the line jitters as I draw it (just a few pixels up and down but very noticeable). What can I do to combat this? Also, is there a less awkward way?
Josh Caswell’s comment gave me an idea. In this article, it indicates that coordinates in children are stored in local space. I knew this before, but it somehow slipped my mind that this would mean the view always faces up no matter how you rotate it. It is only rotated in terms of its coordinates in world space (or parent space).
So instead of getting the touch point on the superview and then calculating, I get the touch point on the subview instead. Change its y value to -2 or whatever I want (just above the ruler because it always faces up in local space) and then
[self convertPoint:point toView:self.superview];to let the view hierarchy take care of the hard part.