Bezier path see if it crosses - objective-c

I have a code that lets the user draw a shape, I'm using UIBezierPath for this. But I need to see if the shape crosses itself, for example like this: http://upload.wikimedia.org/wikipedia/commons/0/0f/Complex_polygon.svg
Then it's not a a valid shape.
How can I find this?
Edit:
I still haven't solved this. I save all the points between the lines in the path in a array. And then I loop through the array and try to find if any lines intersects. But it does not work, sometimes it says that there is an intersection when it isn't.
I think that the problem is somewhere in this method.
-(BOOL)pathIntersects:(double *)x:(double *)y {
int count = pathPoints.count;
CGPoint p1, p2, p3, p4;
for (int a=0; a<count; a++) {
//Line 1
if (a+1<count) {
p1 = [[pathPoints objectAtIndex:a] CGPointValue];
p2 = [[pathPoints objectAtIndex:a+1] CGPointValue];
}else{
return NO;
}
for (int b=0; b<count; b++) {
//Line 2
if (b+1<count) {
p3 = [[pathPoints objectAtIndex:b] CGPointValue];
p4 = [[pathPoints objectAtIndex:b+1] CGPointValue];
}else{
return NO;
}
if (!CGPointEqualToPoint(p1, p3) && !CGPointEqualToPoint(p2, p3) && !CGPointEqualToPoint(p4, p1) && !CGPointEqualToPoint(p4, p2)
&& !CGPointEqualToPoint(p1, p2) && !CGPointEqualToPoint(p3, p4)) {
if (LineIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, x, y)) {
return YES;
}
}
}
}
return NO;
}
This is the code I found to see if two lines intersects, It's in C but I should work.
int LineIntersect(
double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4,
double *x, double *y)
{
double mua,mub;
double denom,numera,numerb;
denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1);
numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
/* Are the line coincident? */
if (ABS(numera) < 0.00001 && ABS(numerb) < 0.00001 && ABS(denom) < 0.00001) {
*x = (x1 + x2) / 2;
*y = (y1 + y2) / 2;
return(TRUE);
}
/* Are the line parallel */
if (ABS(denom) < 0.00001) {
*x = 0;
*y = 0;
return(FALSE);
}
/* Is the intersection along the the segments */
mua = numera / denom;
mub = numerb / denom;
if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
*x = 0;
*y = 0;
return(FALSE);
}
*x = x1 + mua * (x2 - x1);
*y = y1 + mua * (y2 - y1);
return(TRUE);
}

It depends on how complex the polygon drawn by the user can be and the number of points in the path. Ideally, there would be a point for all the vertices in the shape and nothing more. Get a CGPath from the UIBezierPath and use GCPathApply to hand the elements to a function, which adds each point to an array. Traverse the array with two for loops, one nested in the other, which checks each line segment against every line segment after it using a standard line-line intersection test. As soon as an intersection has been found, break from the loop. Or, if this were a convenience method, return a BOOL. That's the simplest way.
EDIT: Here's an example of a line-line intersection function which returns a BOOL telling you whether or not two segments cross. Pass in the two points that create the first segment followed by the two points that make the second segment. It was hastily modified from a piece of source code I found online quickly, but it works.
CGPoint lineSegmentsIntersect(CGPoint L1P1, CGPoint L1P2, CGPoint L2P1, CGPoint L2P2)
{
float x1 = L1P1.x, x2 = L1P2.x, x3 = L2P1.x, x4 = L2P2.x;
float y1 = L1P1.y, y2 = L1P2.y, y3 = L2P1.y, y4 = L2P2.y;
float bx = x2 - x1;
float by = y2 - y1;
float dx = x4 - x3;
float dy = y4 - y3;
float b_dot_d_perp = bx * dy - by * dx;
if(b_dot_d_perp == 0) {
return NO;
}
float cx = x3 - x1;
float cy = y3 - y1;
float t = (cx * dy - cy * dx) / b_dot_d_perp;
if(t < 0 || t > 1) {
return NO;
}
float u = (cx * by - cy * bx) / b_dot_d_perp;
if(u < 0 || u > 1) {
return NO;
}
return YES;
}
You can use it like this.
if (lineSegmentsIntersect(lineOnePointOne,lineOnePointTwo,lineTwoPointOne,lineTwoPointTwo)){
//segments intersect
} else {
//segments did not intersect
}
It's up to you to create the double loop to check the correct segments against one another.

Related

how to calculate the angle of a line form by two points from the north direction?

Does anyone have a script/code/function to calculate the angle from the north line (bearing) of a line formed by two points (x1,y1) and (x2,y2)?
Two points (x1,y1) and (x2,y2)
In javascript
function calcAngleDegrees(x1, y1,x2,y2) {
let x = x2 - x1 ;
let y = y2 - y1 ;
return Math.atan2(y, x) * 180 / Math.PI;
}
let angleDegree = calcAngleDegrees(0,0,5,-5); // -45
let bearingFromAngle = (450 - angleDegree ) % 360; // 135
float calc_azimuth(float x1, float y1, float x2, float y2)
{
//calculate deltas
float deltax = x2 - x1;
float deltay = y2 - y1;
//chech if the deltas are zeros, and if they are, then use a small number
if (deltax == 0.0)
deltax = 0.000001;
if (deltay == 0.0)
deltay = 0.000001;
//Calculate angle
float angle = abs(atan(deltay / deltax) * (180/3.14159));
//define and initialize azimuth
float azim = 0;
//first quadrant
if (x2 >= x1 && y2 > y1)
azim = 90.0 - angle;
//second quadrant
else if (x2 > x1 && y2 <= y1)
azim = angle + 90.0;
//third quadrant
else if (x2 <= x1 && y2 < y1)
azim = 270.0 - angle;
//fourth quadrant
else
azim = 270.0 + angle;
return azim;
}

Collision between a circle and a rectangle

I have a problem with collision detection of a circle and a rectangle. I have tried to solve the problem with the Pythagorean Theorem. But none of the queries works. The rectangle collides with the rectangular bounding box of the circle.
if (CGRectIntersectsRect(player.frame, visibleEnemy.frame)) {
if (([visibleEnemy spriteTyp] == jumper || [visibleEnemy spriteTyp] == wobble )) {
if ((visibleEnemy.center.x - player.frame.origin.x) * (visibleEnemy.center.x - player.frame.origin.x) +
(visibleEnemy.center.y - player.frame.origin.y) * (visibleEnemy.center.y - player.frame.origin.y) <=
(visibleEnemy.bounds.size.width/2 * visibleEnemy.bounds.size.width/2)) {
NSLog(#"Check 1");
normalAction = NO;
}
if ((visibleEnemy.center.x - (player.frame.origin.x + player.bounds.size.width)) *
(visibleEnemy.center.x - (player.frame.origin.x + player.bounds.size.width)) +
(visibleEnemy.center.y - player.frame.origin.y) * (visibleEnemy.center.y - player.frame.origin.y) <=
(visibleEnemy.bounds.size.width/2 * visibleEnemy.bounds.size.width/2)) {
NSLog(#"Check 2");
normalAction = NO;
}
else {
NSLog(#"Check 3");
normalAction = NO;
}
}
}
Here is how I did it in one of my small gaming projects. It gave me best results and it's simple. My code detects if there is a collision between circle and the line. So you can easily adopt it to circle - rectangle collision detection by checking all 4 edges of the rectangle.
Let's say that a ball has a ballRadius, and location (xBall, yBall). The line is defined with two points (xStart, yStart) and (xEnd, yEnd).
Implementation of a simple collision detection:
float ballRadius = ...;
float x1 = xStart - xBall;
float y1 = yStart - yBall;
float x2 = xEnd - xBall;
float y2 = yEnd - yBall;
float dx = x2 - x1;
float dy = y2 - y1;
float dr = sqrtf(powf(dx, 2) + powf(dy, 2));
float D = x1*y2 - x2*y1;
float delta = powf(ballRadius*0.9,2)*powf(dr,2) - powf(D,2);
if (delta >= 0)
{
// Collision detected
}
If delta is greater than zero there are two intersections between ball (circle) and line. If delta is equal to zero there is one intersection – perfect collision.
I hope it will help you.

Trouble Returning CGPoint

I got this method:
-(CGPoint) getPointOnaLine: (CGPoint) p1: (CGPoint) p2: (int) dt {
CGPoint tempPoint;
float myY = p1.y;
float len = getLineLength( p1, p2 );
float res = 1000;
// do not bother with calculation with small widths
if ( dt == 0 )
return p1;
if ( len < (2 / res ) )
return p2;
float increm = len / res;
// int min = 2;
float dY = p2.y - p1.y;
float dx = p2.x - p1.x;
if ( dx != 0 ) { // slope is infinite
float slope = dY / dx;
float b = p1.y - slope * p1.x;
if ( p1.x < p2.x ) {
for ( float i= p1.x; i<=p2.x; i=i+increm ) {
myY = (slope * i + b);
tempPoint = ccp(i,myY);
len = getLineLength( p1, tempPoint);
if ( len >= dt)
return tempPoint;
}
} else if ( p1.x > p2.x )
for ( float i= p2.x; i<=p1.x; i=i+increm) {
myY = (slope * i + b);
tempPoint = ccp(i,myY);
len = getLineLength( p2, tempPoint);
if ( len >= dt )
return tempPoint;
}
} else {
return p2;
}
return p1;
}
I use it in another method:
CGPoint b1, b2, pt;
b1 = getPointOnaLine(originalPoint, bezierPoint, (int)t*stepLine1);
b2 = getPointOnaLine(bezierPoint, targetPoint, (int)t*stepLine2);
bLen = getLineLength(b1,b2);
stepLine3 = bLen / frames;
pt = getPointOnaLine(b1,b2,(int)self.tCGPoint b1, b2, pt;
The compiler keep telling me "Incompatable types in assignment" where I declare b1, b2, and pt. The interface is:
-(CGPoint) getPointOnaLine: (CGPoint) p1: (CGPoint) pt2: (int) dt;
If I remove the assignment it just gives me an Implicit declaration warning. I'm really confused about why this won't compile.
Chris
You've defined a method (though with oddly unnamed parameters) but you're calling it as a function.
Try:
b1 = [self getPointOnaLine:originalPoint :bezierPoint :(int)t*stepLine1];
(Better still, declare it with parameter names to make reading easier for your future self.)
You are calling objective-c messages in the c-function style, instead use it as
b1 = [self getPointOnaLine:originalPoint :bezierPoint :(int)t*stepLine1];
b2 = [self getPointOnaLine:bezierPoint :targetPoint :(int)t*stepLine2];
if b1 and b2 are initialized in the same class, otherwise self is to be replaced by the object that has getPointOnaLine:bezierPoint method defined.

How to find a third point using two other points and their angle

I found an answer here, but can't understand how to transfer the math to Objective C
Find the third point
I have two points and I also have the angle relative to the axes. How do I find a third point which will form a straight line? The distance should be variable.
This is the code that I am using:
float distanceFromPx2toP3 = 1300.0;
float mag = sqrt(pow((px2.x - px1.x),2) + pow((px2.y - px1.y),2));
float P3x = px2.x + distanceFromPx2toP3 * (px2.x - px1.x) / mag;
float P3y = px2.y + distanceFromPx2toP3 * (px2.y - px1.y) / mag;
CGPoint P3 = CGPointMake(P3x, P3y);
Let's say I have two points pointA and pointB. The slope of the line formed by the two points m is:
static CGFloat calculateSlope(CGPoint pointA, CGPoint pointB) {
CGFloat m = (pointB.y - pointA.y) / (pointB.x - pointA.x);
return m;
}
A third point pointC a distance d from pointA on the line would be given by:
static CGPoint calculatePointOnLine(
CGPoint pointA, CGPoint pointB, CGFloat d, BOOL startAtB) {
CGFloat m = calculateSlope(pointA, pointB);
CGFloat dX = pointB.x - pointA.x;
CGFloat dY = pointB.y - pointA.y;
CGFloat signDX = dX / fabsf(dX);
CGFloat signDY = dY / fabsf(dY);
CGFloat dSquared = d * d;
CGFloat mSquared = m * m;
// We know pointC is distance d from pointA,
// and that pointA and pointC are on the
// same line
// dXSquared + dYSquared = dSquared
// m = dY / dX
// dY = m * dX
// dXSquared + mSquared * dXSquared = dSquared
// dXSquared * ( 1 + mSquared ) = dSquared
// dXSquared = dSquared / ( 1 + mSquared )
// Handle a vertical line, dX == 0, and a horizontal line, dY == 0
if (dX != 0 && dY != 0) {
// Account for the sign of dX
dX = signDX * sqrtf(dSquared / ( 1 + mSquared ));
// Account for the sign of dY
dY = signDY * m * dX;
}
// Handle a vertical line, dX == 0
if (dX == 0 && dY != 0) {
dY = signDY * d;
}
// Handle a horizontal line, dY == 0
if (dY == 0 && dX != 0) {
dX = signDX * d;
}
CGPoint startingPoint = pointA;
if (startAtB) {
startingPoint = pointB;
}
CGPoint pointC = CGMakePoint(startingPoint.x + dX,
startingPoint.y + dY);
return pointC;
}
pointC will now always lie a distance d along the line from pointA,
in the direction from pointA to pointB. Pass startAtB to have pointC
lie a distance d along the line from pointB, in the direction from
pointA to pointB.
Exchange the order of piintA and pointB in the call to calculatPointOnLine
to calculate a pointC which lies a distance d along the line from
PointB, in the direction from pointB to pointA.
You can use these two functions to calculate a third point on the line.
Thanks for accepting this answer if this helps you.

Angle between two lines is wrong

I want to get angles between two line.
So I used this code.
int posX = (ScreenWidth) >> 1;
int posY = (ScreenHeight) >> 1;
double radians, degrees;
radians = atan2f( y - posY , x - posX);
degrees = -CC_RADIANS_TO_DEGREES(radians);
NSLog(#"%f %f",degrees,radians);
But it doesn't work .
The Log is that: 146.309935 -2.553590
What's the matter?
I can't know the reason.
Please help me.
If you simply use
radians = atan2f( y - posY , x - posX);
you'll get the angle with the horizontal line y=posY (blue angle).
You'll need to add M_PI_2 to your radians value to get the correct result.
Here's a function I use. It works great for me...
float cartesianAngle(float x, float y) {
float a = atanf(y / (x ? x : 0.0000001));
if (x > 0 && y > 0) a += 0;
else if (x < 0 && y > 0) a += M_PI;
else if (x < 0 && y < 0) a += M_PI;
else if (x > 0 && y < 0) a += M_PI * 2;
return a;
}
EDIT: After some research I found out you can just use atan2(y,x). Most compiler libraries have this function. You can ignore my function above.
If you have 3 points and want to calculate an angle between them here is a quick and correct way of calculating the right angle value:
double AngleBetweenThreePoints(CGPoint pointA, CGPoint pointB, CGPoint pointC)
{
CGFloat a = pointB.x - pointA.x;
CGFloat b = pointB.y - pointA.y;
CGFloat c = pointB.x - pointC.x;
CGFloat d = pointB.y - pointC.y;
CGFloat atanA = atan2(a, b);
CGFloat atanB = atan2(c, d);
return atanB - atanA;
}
This will work for you if you specify point on one of the lines, intersection point and point on the other line.