Is there an easy way to do this.
I have a CGPoint pointA (10, 10) and another CGPoint pointB (15, 8). I need to get a CGPoint which is on the same line as the one connecting A and B and at a certain distance (say 2) before point A.
I tried looking around for any vector based struct. There is something called CGVector but that seems to be pretty useless here.
It can be done like this:
Assumption: The direction of line is from head:(point2) tail:(point1)
- (CGPoint)getPointFromLineConnecting:(CGPoint)point1 andPoint2:(CGPoint)point2 withDistanceFromPoint1:(CGFloat)dist {
// distance between connecting points
CGFloat distance = sqrtf(powf(point1.x-point2.x, 2) + powf(point1.y-point2.y, 2));
// unit vector point: v = (x1-x0)i/distance + (y1-y0)j/distance
CGPoint unitVectorPoint = CGPointMake((point2.x - point1.x)/distance, (point2.y - point1.y)/distance);
// resultant point at a distance d from p1
CGPoint resultPoint = CGPointMake((point1.x+dist*unitVectorPoint.x), (point1.y+dist*unitVectorPoint.y));
return resultPoint;
}
Related
I have an app with a color wheel and I'm trying to pick a random color within the color wheel. However, I'm having problems verifying that the random point falls within the color wheel.
Here's the code as it currently is:
CGPoint randomPoint = CGPointMake(arc4random() % (int)colorWheel.bounds.size.width, arc4random() % (int)colorWheel.bounds.size.height);
UIColor *randomColor = [self colorOfPoint:randomPoint];
CGPoint pointInView = [colorWheel convertPoint:randomPoint fromView:colorWheel.window];
if (CGRectContainsPoint(colorWheel.bounds, pointInView)) {
NSLog(#"%#", randomColor);
}
else {
NSLog(#"out of bounds");
}
A couple of other methods of verifying the point that I've tried with no luck:
if (CGRectContainsPoint(colorWheel.frame, randomPoint)) {
NSLog(#"%#", randomColor);
}
if ([colorWheel pointInside:[self.view convertPoint:randomPoint toView: colorWheel] withEvent: nil]) {
NSLog(#"%#", randomColor);
}
Sometimes it'll output "out of bounds", and sometimes it'll just output that the color is white (the background around the color wheel is currently white but there's no white in the color wheel image).
The color wheel image is a circle, so I'm not sure if that's throwing off the test, although it seems like white pops up way too frequently for it to just be a transparent square outline around the image giving a white color.
If you want to generate a random point in a circle, you would do better to pick your point in polar coordinates and then convert it to Cartesian.
The polar coordinate space uses two dimesions, radius and angle. Radius is just the distance from the center, and angle usually starts at "due east" for 0, and goes around counter-clockwise up to 2π (that's in radians, 360˚ of course in degrees).
Presumably your wheel is divided into simple wedges, so the radius actually doesn't matter; you just need to pick a random angle.
uint32_t angle = arc4random_uniform(360);
// Radius will just be halfway from the center to the edge.
// This assumes the circle is exactly enclosed, i.e., diameter == width
CGFloat radius = colorWheel.bounds.size.width / 4;
This function will give you a Cartesian point from your polar coordinates. Wikipedia explains the simple math if you're interested.
/** Convert the polar point (radius, theta) to a Cartesian (x,y). */
CGPoint poltocar(CGFloat radius, CGFloat theta)
{
return (CGPoint){radius * cos(theta), radius * sin(theta)};
}
The function uses radians for theta, because sin() and cos() do, so change the angle to radians, and then you can convert:
CGFloat theta = (angle * M_PI) / 180.0
CGPoint randomPoint = poltocar(radius, theta);
One last step: this circle has its origin at the same place as the view, that is, in the corner, so you need to translate the point to use the center as the origin.
CGPoint addPoints(CGPoint lhs, CGPoint rhs)
{
return (CGPoint){lhs.x + rhs.x, lhs.y, rhs.y};
}
CGPoint offset = (CGPoint){colorWheel.bounds.size.width / 2,
colorWheel.bounds.size.height / 2};
randomPoint = addPoints(randomPoint, offset);
And your new randomPoint will always be within the circle.
I agree with #JoshCaswell's approach, but FYI, the reason the OP code is not working is that the test for inside a circle is incorrect.
The coordinate conversion is unnecessary, and the test against a rectangle is sure to be wrong. Instead, work out how far the random point is from the center and compare that with the radius.
CGFloat centerX = colorWheel.bounds.size.width / 2.0;
CGFloat centerY = colorWheel.bounds.size.height / 2.0;
CGFloat distanceX = centerX - randomPoint.x;
CGFloat distanceY = centerY - randomPoint.y;
CGFloat distance = distanceX*distanceX + distanceY*distanceY;
CGFloat radius = colorWheel.bounds.size.width / 2.0; // just a guess
CGFloat r2 = radius*radius;
// this compares the square of the distance with r^2, to save a sqrt operation
BOOL isInCircle = distance < r2;
I am reading iOS Core Animation Advanced Techniques.
In this book there is an example code that gets control points from a CAMediaTimingFunction:
//create timing function
CAMediaTimingFunction *function = [CAMediaTimingFunction functionWithControlPoints:1 :0 :0.75 :1];
//get control points
CGPoint controlPoint1, controlPoint2;
[function getControlPointAtIndex:1 values:(float *)&controlPoint1];
[function getControlPointAtIndex:2 values:(float *)&controlPoint2];
The controlPoint value that I get seems to be wrong:
controlPoint1 CGPoint (x = 5.2635442471208903E-315, y = 4.9406564584124654E-324)
controlPoint2 CGPoint (x = 0.0078125018408172764, y = 2.8421186829703262E-314)
However, if I use an float array as type of the parameter values, I get the right values of controlPoint:
float c1p[2], c2p[2];
[function getControlPointAtIndex:1 values:c1p];
[function getControlPointAtIndex:2 values:c2p];
The values are:
controlPoint1 CGPoint (x = 1, y = 0)
controlPoint2 CGPoint (x = 0.75, y = 1)
The question is, how can I use CGPoint as the first code snippet shows? Why isn't it getting the right values?
Thanks.
If what you are showing is the book code, the book code is wrong. functionWithControlPoints: takes float values. CGPoint is made up of CGFloat values. They are not the same - as you have discovered. You can get these values using an array of float, as you are doing.
(I suppose the first code would work on a 32-bit device, where CGFloat and float are the same. But that is sort of an accident. To try to treat two floats as a CGPoint is just silly.)
CGPoint pointA = [self.appDelegate.points[0] CGPointValue];//first point
CGPoint pointB = [self.appDelegate.points[1] CGPointValue];// second point
CGPoint pointC = [self.appDelegate.points[2] CGPointValue];//third point
CGFloat slopeAB = (pointB.y - pointA.y)/(pointB.x - pointA.x);//slope ab
CGFloat slopeBC = (pointC.y - pointB.y)/(pointC.x - pointB.x);//slope bc
self.ang=(slopeAB-slopeBC)/(1+(slopeAB)*(slopeBC));//slope
CGFloat finalAngle = atanf(self.ang);// angle tan inverse slope
CGFloat angle = (finalAngle * (180.0/M_PI));
NSLog(#"The angle is: %.2f degrees",angle);
calculated the slope of each line
calculated angle by tan inverse
Use the atan2() function. From the manual page:
#include <math.h>
double
atan2(double y, double x);
The atan2() function computes the principal value of the arc tangent of
y/x, using the signs of both arguments to determine the quadrant of the
return value.
To do this for the three points you'll need to call atan2() twice: once to find the angle of AB, and once for the angle of BC. Take the difference between these two to find the angle between AB and BC:
double angle_ab = atan2(pointA.y - pointB.y, pointA.x - pointB.x);
double angle_cb = atan2(pointC.y - pointB.y, pointC.x - pointB.x);
double angle_abc = angle_ab - angle_cb;
Note that this is assuming that B is the "center" point of the angle you're interested in. Adjust appropriately if I've assumed wrongly.
I know how to draw simple lines using Core Graphics. I now need to draw a Dimension line for measurements. See the image below for an example of what I need to draw (in red). The top line would be easy, but drawing the perpendicular on a diagonal line will require some math that I'm having a difficult time figuring out right now.
Each main line will have (x,y) as a starting point and (x1,y1) as an ending point. I then need to draw the perpendicular lines that intersect at each of the points (x,y) and (x1,y1).
What is the math required to calculate the points for these perpendicular lines?
The following code computes a vector of length 1 that is perpendicular to
the line from p = (x, y) to p1 = (x1, y1):
CGPoint p = CGPointMake(x, y);
CGPoint p1 = CGPointMake(x1, y1);
// Vector from p to p1;
CGPoint diff = CGPointMake(p1.x - p.x, p1.y - p.y);
// Distance from p to p1:
CGFloat length = hypotf(diff.x, diff.y);
// Normalize difference vector to length 1:
diff.x /= length;
diff.y /= length;
// Compute perpendicular vector:
CGPoint perp = CGPointMake(-diff.y, diff.x);
Now you add and subtract a multiple of that perpendicular vector to the first point
to get the endpoints of the first marker line at p:
CGFloat markLength = 3.0; // Whatever you need ...
CGPoint a = CGPointMake(p.x + perp.x * markLength/2, p.y + perp.y * markLength/2);
CGPoint b = CGPointMake(p.x - perp.x * markLength/2, p.y - perp.y * markLength/2);
For the second marker line, just repeat the last calculation with p1 instead of p.
I calculate angle between two CGPoints :
//calculate radian and degree
CGPoint diff = ccpSub(center, location);//return ccp(v1.x - v2.x, v1.y - v2.y);
float rads = atan2f( diff.y, diff.x);
float degs = -CC_RADIANS_TO_DEGREES(rads);
NSLog(#"Rad %.2f Degs %.2f",rads,degs);
Now In another function where I have a pre known CGPoint and the degree of above function, I want to calculate closest point that satisfies the degree.
I was thinking about maybe below code would help me but in below code start point and rotation point is known, in my situation I only know start point.
-(void) rotateAroundPoint:(CGPoint)rotationPoint angle:(CGFloat)angle {
CGFloat x = cos(CC_DEGREES_TO_RADIANS(-angle)) * (self.position.x-rotationPoint.x) - sin(CC_DEGREES_TO_RADIANS(-angle)) * (self.position.y-rotationPoint.y) + rotationPoint.x;
CGFloat y = sin(CC_DEGREES_TO_RADIANS(-angle)) * (self.position.x-rotationPoint.x) + cos(CC_DEGREES_TO_RADIANS(-angle)) * (self.position.y-rotationPoint.y) + rotationPoint.y;
Lets say I have a point 800,600 and I have a degree of 70, how can I calculate closest point with that point and that degree?
EDIT:::
Normally in my game sprites are moved with a button therefore all rotation,movement,speed etc are handled when button pressed [sprite moveToPreGivenPostion:CGPoint]
But now a compass is added and when user choose an angle on the compass I need to move the sprite in the direction of degree on compass, since [sprite moveToPreGivenPostion:CGPoint] already handles rotation and other stuff I just want to determine that what CGPoint should I send to moveToPreGivenPostion function.
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.
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);