Precise selection


#1

This is not any challenge, but selection was annoying, so I tried it more mathematical. Most probably, I even saved repititions. I guess, there are some steps which I could have used predefined methods for, but like this it was more fun

I also added the maximum distance as parameter, to play around with it more flexible

-(Line *)lineAtPoint:(CGPoint)point maxDistance:(float)maxDistance
{
	int lowest = maxDistance;
	Line *closestLine = nil;
	
	//check the distance of the point from all complete lines
	for (Line *l in self.completeLines) {
		
		//s=intersection t=testpoint p1=liniestart p2=linieend
		
		float xp1 = [l start].x;
		float xp2 = [l end].x;
		float yp1 = [l start].y;
		float yp2 = [l end].y;
		float xt = point.x;
		float yt = point.y;
		
		//calculate the distance of the point from the line through those two points
		float m1 = (yp2-yp1)/(xp2-xp1);
		float t1 = yp1-(m1*xp1);
		
		float m2 = -(1/m1);
		float t2 = yt-(m2*xt);
		
		float xs = (t2-t1)/(m1-m2);
		float ys = (m1*xs)+t1;
		
		
		BOOL isVertical = ((xp1-xp2) == 0);
		BOOL isHorizontal = ((yp1 - yp2) == 0);
		
		if (isVertical) {
			ys = yt;
			xs = xp1-xt;
		} else if (isHorizontal) {
			xs = xt;
			ys = yp1-yt;
		}
		
		float d = sqrtf(((xs-xt)*(xs-xt))+((ys-yt)*(ys-yt)));
		
		//look whether the intersection point is between start and end, with one pixel tolerance
		CGRect lineBox = CGRectMake(MIN(xp1,xp2)-1, MIN(yp1,yp2)-1, (MAX(xp1,xp2)-MIN(xp1,xp2))+1, (MAX(yp1,yp2)-MIN(yp1,yp2))+1);
		
		BOOL isAwayFromLine = !CGRectContainsPoint(lineBox, CGPointMake(xs, ys));
		
		float minDistance = d;
		
		//if it is, take the distance from the closest end point
		
		//calculate the distance from the end points
		float distanceFromP1 = sqrtf(((xp1-xt)*(xp1-xt))+((yp1-yt)*(yp1-yt)));
		float distanceFromP2 = sqrtf(((xp2-xt)*(xp2-xt))+((yp2-yt)*(yp2-yt)));
		
		if (isAwayFromLine) {
			minDistance = MIN(distanceFromP1, distanceFromP2);
		}
		
		if (minDistance<lowest) {
			lowest = minDistance;
			closestLine = l;
			NSLog(@"setNewMin");
		}
	}
		
	return closestLine;
}

#2

small bugfix: vertical and horizontal lines still did not work. Insert after

CGFloat yp2 = [l end].y;
float xt = point.x;
float yt = point.y;

[code]//if the line is vertical or horizontal, make a small fix agains /0
BOOL isVertical = (xp1 == xp2);
BOOL isHorizontal = (yp1 ==yp2);

	if (isVertical) {
		xp2 = xp2+0.0001;
	} else if (isHorizontal) {
		yp2 = yp2+0.0001;
	}

[/code]

and remove the old

[code]BOOL isVertical = ((xp1-xp2) == 0);
BOOL isHorizontal = ((yp1 - yp2) == 0);

  if (isVertical) {
     ys = yt;
     xs = xp1-xt;
  } else if (isHorizontal) {
     xs = xt;
     ys = yp1-yt;
  }[/code]