# 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]``````