Finding point is close to line and between the endpoints of the line - objective-c

To find if the point is on a specified line containing two points i do the following checks:
-(Boolean)isOnLine:(Line*) line point:(CGPoint) point{
//If between two dots:
if (((line.first.x <= point.x && point.x <= line.last.x)||(line.first.x >= point.x && point.x >= line.last.x))&&((line.first.y<=point.y && point.y<= line.last.y)||(line.first.y>=point.y && point.y>=line.last.y)) ) {
//Calculate distance:
double dist = (((double)point.y - line.first.y)) / (0.00001+((double)(point.x - line.first.x)))- ((double)(line.last.y - line.first.y)) / (0.00001+((double)(line.last.x - line.first.x)));
NSLog(#"Dist to line: %f", fabs(dist));
return fabs(dist) <0.5;
}else
return NO;
}
}
Somehow, however, the function is not working with vertical lines. My guess is the if clause is invalid in some sense.

I haven't read your code carefully so I'm not entirely sure what you're doing, but fyi the easiest way to do this operation is find the distance of one end of the line to the point, find the distance of the other end of the line to the point, and then add those distances and compare to the length of the line.
Something like:
Boolean isOnLine(line, point) {
var dist1 = dist(line.first, point)
var dist2 = dist(line.last, point)
return abs(line.length - (dist1 + dist2)) < .5
}
For the dist() function I'm guessing CoreGraphics provides that, but if not it's just basic trigonometry.

Here's my implementation of jhockings' solution
return abs([line length] -
(sqrt((line.first.x - point.x)*(line.first.x - point.x)
+ (line.first.y - point.y)*(line.first.y - point.y))
+ sqrt((line.last.x - point.x)*(line.last.x - point.x)
+ (line.last.y - point.y)*(line.last.y - point.y)))) < .5;

Another(my) implementation of #jhocking solution:
- (BOOL)isPoint:(CGPoint)origin nearToLineSegmentPointA:(CGPoint)pointA pointB:(CGPoint)pointB withMarginOfError:(CGFloat)marginOfError {
CGFloat distanceAP = [self distanceBetweenPointA:origin pointB:pointA];
CGFloat distanceBP = [self distanceBetweenPointA:origin pointB:pointB];
CGFloat distanceAB = [self distanceBetweenPointA:pointA pointB:pointB];
if (fabsf(distanceAB - distanceAP - distanceBP) < marginOfError) {
return YES;
} else {
return NO;
}
}
- (CGFloat)distanceBetweenPointA:(CGPoint)pointA pointB:(CGPoint)pointB {
return sqrtf(powf((pointA.x - pointB.x), 2.f) + powf((pointA.y - pointB.y), 2.f));
}

The explanation of why it is not working is you are comparing the tangent of the angles of two triangles - you are not calculating distance at all despite the comments and variable name.
Now as the angle approaches 90 deg the magnitude of the tangent increases rapidly until it reaches infinity at 90 degrees itself. At 90 degrees the difference of the x coordinates is zero and you would end up with a divide-by-zero error where it not for adding in the 0.00001 constant to avoid it. While the relative difference between two tangents near 90 might be small the absolute difference can be huge even for very close angles, so your < 0.5 test fails.
So you need another approach. One is to calculate the distances from the point to the two end points, and the length of the line itself, and compare - if the sum of the two distances from the point is larger than the length of the line the three points form a triangle, if it isn't they are co-linear. (And if the sum is less you've slipped into an alternate dimension...).
You can calculate the length of the lines using Pythagorus: sqrt((x1 - x2)^2 + (y1 - y2)^2).

Related

How to Set Wheelnav.js Spin Direction Always the Shorted Distance?

How can wheelnav.js be setup to rotate both clockwise and counterclockwise, whichever is closest? Whenever it goes from 0 to the highest number, it flips around the long way, as seen when you go from 0 to 5 on this demo page after turning on rotation:
http://pmg.softwaretailoring.net/
It needs to always rotate in the closest direction and never flip around the long way.
I am also open to a solution using wheelizate tabs, which uses Wheelnav to accomplish this:
http://wtabs.softwaretailoring.net/
Thank you for your attention on this.
Found the solution by doing a Console.log(rotationAngle), and watching what the rotation value for each particular click. Then I found that I could take the numbers of the situations that went the wrong way, and subtract 360 from it to get it to rotate the opposite direction.
The patch involve adding this to Wheelnav.js line 411:  
if (rotationAngle == 288){
rotationAngle = -72;
}
if (rotationAngle == 216){
rotationAngle = -144;
}
You need to replace the next line (line 422 of Wheelnav.js):
navItem.currentRotateAngle -= rotationAngle;
with the following conditional expression:
if (rotationAngle >= 180) {
rotationAngle = 360 - rotationAngle;
navItem.currentRotateAngle += rotationAngle;
} else if (Math.abs(rotationAngle) > 180) {
rotationAngle = 360 + rotationAngle;
navItem.currentRotateAngle -= rotationAngle;
} else {
navItem.currentRotateAngle -= rotationAngle;
}

Distance between point and finite line in objective-c

I've looked up some formulas relating to finding the distance a point and a line. On this page, I used example 14
http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
I have a method that has turned into this:
+(bool) checkPointNearBetweenPointsWithPointA:(CGPoint)pointA withPointB:(CGPoint)pointB withPointC:(CGPoint)pointC withLimit:(float)limit {
float A = pointB.x - pointA.x;
float B = pointA.y - pointC.y;
float C = pointA.x - pointC.x;
float D = pointB.y - pointA.y;
float dividend = fabs( A * B ) - ( C * D );
float divisor = sqrt(pow(A,2) + pow(D,2));
float distanceBetweenPointAndLine = dividend / divisor;
if(distanceBetweenPointAndLine < limit){
NSLog(#"distanceBetweenPointAndLine = %f",distanceBetweenPointAndLine);
return YES;
}
return NO;
}
The problem is that it still returns YES if I'm passed point B, if the line segment is drawn like B----A. Other screwed up things happen to depending on which angle the line is drawn. Just wondering if I need to consider anything else if testing to see if a point is near a finite line. Most examples I see online deal with lines of infinite length.
try my code below. line is considered to exist between points A & B (regardless of how you draw it B->A or A->B ) and point C is the point in consideration to measure the distance.
+ (bool) checkPointNearBetweenPointsWithPointA:(CGPoint)pointA
withPointB:(CGPoint)pointB
withPointC:(CGPoint)pointC
withLimit:(float)limit
{
CGFloat slopeLine = atan((pointB.y-pointA.y)/(pointB.x-pointA.x) );
CGFloat slopePointToPointA = -1 *atan((pointC.y-pointA.y)/(pointC.x-pointA.x));
CGFloat innerAngle = slopeLine + slopePointToPointA;
CGFloat distanceAC = sqrtf(pow(pointC.y-pointA.y,2) + pow(pointC.x-pointA.x,2));
CGFloat distanceBetweenPointAndLine = fabs(distanceAC * sin(innerAngle));
NSLog(#"distanceBetweenPointAndLine = %f",distanceBetweenPointAndLine);
NSLog(#"is exceeding limit ? %#",distanceBetweenPointAndLine > limit ? #"YES":#"NO");
if(distanceBetweenPointAndLine < limit)
{
return YES;
}
return NO;
}

Determining explosion radius damage - Circle to Rectangle 2D

One of the Cocos2D games I am working on has circular explosion effects. These explosion effects need to deal a percentage of their set maximum damage to all game characters (represented by rectangular bounding boxes as the objects in question are tanks) within the explosion radius. So this boils down to circle to rectangle collision and how far away the circle's radius is from the closest rectangle edge. I took a stab at figuring this out last night, but I believe there may be a better way. In particular, I don't know the best way to determine what percentage of damage to apply based on the distance calculated.
Note : All tank objects have an anchor point of (0,0) so position is according to bottom left corner of bounding box. Explosion point is the center point of the circular explosion.
TankObject * tank = (TankObject*) gameSprite;
float distanceFromExplosionCenter;
// IMPORTANT :: All GameCharacter have an assumed (0,0) anchor
if (explosionPoint.x < tank.position.x) {
// Explosion to WEST of tank
if (explosionPoint.y <= tank.position.y) {
//Explosion SOUTHWEST
distanceFromExplosionCenter = ccpDistance(explosionPoint, tank.position);
} else if (explosionPoint.y >= (tank.position.y + tank.contentSize.height)) {
// Explosion NORTHWEST
distanceFromExplosionCenter = ccpDistance(explosionPoint,
ccp(tank.position.x, tank.position.y + tank.contentSize.height));
} else {
// Exp center's y is between bottom and top corner of rect
distanceFromExplosionCenter = tank.position.x - explosionPoint.x;
} // end if
} else if (explosionPoint.x > (tank.position.x + tank.contentSize.width)) {
// Explosion to EAST of tank
if (explosionPoint.y <= tank.position.y) {
//Explosion SOUTHEAST
distanceFromExplosionCenter = ccpDistance(explosionPoint,
ccp(tank.position.x + tank.contentSize.width,
tank.position.y));
} else if (explosionPoint.y >= (tank.position.y + tank.contentSize.height)) {
// Explosion NORTHEAST
distanceFromExplosionCenter = ccpDistance(explosionPoint,
ccp(tank.position.x + tank.contentSize.width,
tank.position.y + tank.contentSize.height));
} else {
// Exp center's y is between bottom and top corner of rect
distanceFromExplosionCenter = explosionPoint.x - (tank.position.x + tank.contentSize.width);
} // end if
} else {
// Tank is either north or south and is inbetween left and right corner of rect
if (explosionPoint.y < tank.position.y) {
// Explosion is South
distanceFromExplosionCenter = tank.position.y - explosionPoint.y;
} else {
// Explosion is North
distanceFromExplosionCenter = explosionPoint.y - (tank.position.y + tank.contentSize.height);
} // end if
} // end outer if
if (distanceFromExplosionCenter < explosionRadius) {
/*
Collision :: Smaller distance larger the damage
*/
int damageToApply;
if (self.directHit) {
damageToApply = self.explosionMaxDamage + self.directHitBonusDamage;
[tank takeDamageAndAdjustHealthBar:damageToApply];
CCLOG(#"Explsoion-> DIRECT HIT with total damage %d", damageToApply);
} else {
// TODO adjust this... turning out negative for some reason...
damageToApply = (1 - (distanceFromExplosionCenter/explosionRadius) * explosionMaxDamage);
[tank takeDamageAndAdjustHealthBar:damageToApply];
CCLOG(#"Explosion-> Non direct hit collision with tank");
CCLOG(#"Damage to apply is %d", damageToApply);
} // end if
} else {
CCLOG(#"Explosion-> Explosion distance is larger than explosion radius");
} // end if
} // end if
Questions:
1) Can this circle to rect collision algorithm be done better? Do I have too many checks?
2) How to calculate the percentage based damage? My current method generates negative numbers occasionally and I don't understand why (Maybe I need more sleep!). But, in my if statement, I ask if distance < explosion radius. When control goes through, distance/radius must be < 1 right? So 1 - that intermediate calculation should not be negative.
Appreciate any help/advice
EDIT
My occasional negative result was due to a misplaced parenthesis.
damageToApply = (1 - (distanceFromExplosionCenter/explosionRadius)) * explosionMaxDamage;
Still looking for input on how to calculate explosion radius damage.
You can check the distance of the objects using ccpDistance:
float distance = ccpDistance(sprite1.position, sprite2.position);
I think the ccpDistance will always return a positive value. But if its't, then get the absolute value: fabsf(distance)

Getting minimum number of MKMapRects from a MKPolygon

So I have a function that takes two MKMapRect's and the second intersects with the first one. So the function creates an MKPolygon that is the first rect without the intersecting parts:
-(void) polygons:(MKMapRect)fullRect exclude:(MKMapRect)excludeArea{
NSLog(#"Y is: %f height: %f",excludeArea.origin.y,excludeArea.size.height);
double top = excludeArea.origin.y - fullRect.origin.y;
double lft = excludeArea.origin.x - fullRect.origin.x;
double btm = (fullRect.origin.y + fullRect.size.height) - (excludeArea.origin.y + excludeArea.size.height);
double rgt = (fullRect.origin.x + fullRect.size.width) - (excludeArea.origin.x + excludeArea.size.width);
double ot = fullRect.origin.y, it = (ot + top);
double ol = fullRect.origin.x, il = (ol + lft);
double ob = (fullRect.origin.y + fullRect.size.height), ib = (ob - btm);
double or = (fullRect.origin.x + fullRect.size.width), ir = (or - rgt);
MKMapPoint points[11] = {{ol,it}, {ol,ot}, {or,ot}, {or,ob}, {ol,ob}, {ol,it}, {il,it}, {ir,it}, {ir,ib}, {il,ib}, {il,it}};
MKPolygon *polygon = [MKPolygon polygonWithPoints:points count:11];
}
And my question is now how do I get the minimum number of MKMapRects from this MKPolygon? I have done some googling as well as looking through the forum but havn't found anything.
EDIT:
So the goal is the following:
I have a MKMapRect rect1, then I have a list of rectangles, rectList, which is MKMapRects intersecting with rect1 and what I want to do is create a rectilinear MKPolygon of rect1, remove the surface of all MKMapRects in rectList from rect1 and then create the minimum number of MKMaprects from the created rectilinear MKPolygon.
Right now the problem is the following: I am able to create a polygon when removing one MKMapRect from rect1 but I dont know how to remove the following maprects from rect1 and I dont know how to extract the minimum set of MkMapRects from the polygon created.
Best regards
Peep
I'm not sure if this is what you're looking for or if I understand the question fully, but if all you need to know is the minimum number of rectangles in a polygon that's created by subtracting one rectangle from another you should be able to do it by checking the number of corner points in the second rectangle that are contained in the first rectangle. In pseudo code:
int minNumRects(MKRect r1, MKRect r2) {
int numPointsContained = 0;
for (Point p in r2) {
if (MKMapRectContainsPoint(r1, p)) {
numPointsContained++;
}
}
if (numPointsContained == 1) {
return 2;
} else if (numPointsContained == 2) {
return 3;
} else if (numPointsContained == 4) {
return 4;
} else {
return 0;
}
}
P.S. - This assumes that the rectangles are axis-aligned but as far as I know that's the case with MKRects

CGFloat substraction problem

_screen.brightness = _screen.brightness - 0.1;
This line of code gives me an unexpected result.
When I call the NSLog(#"%.2f", _screen.brightness - 0.1); command, then it prints the
-0.00 value. When I test to this if (_screen.brightness == 0), it gives me NO.
Why this happens? Is there any conversion problem?
Here's my accessor methods in the class of _screen's object:
- (CGFloat)brightness {
return 1 - _dimmingView.alpha;
}
- (void)setBrightness:(CGFloat)brightness {
if (brightness < self.minValue || brightness > self.maxValue) {
return;
}
_dimmingView.alpha = 1 - brightness;
}
Floating point arithmetic doesn't necessarily give you the precise answers you're looking for. Better men than I have explained it here: C# float bug? 0.1 - 0.1 = 1.490116E-08. For a different language but the point remains the same.