For each pair of adjacent vertices A,B:
construct a vector from A to B, call it p
now construct a vector from A to your test point X call it q
the dot product formula for a pair of vectors is p.q = |p||q|cosC
where C is the angle between the vectors.
so if p.q/|p||q| == 1 then the points AX and AB are co-linear. Working on a computer, you will want 1 - p.q/|p||q| < some_small_value depending on how accurate you want to be.
also need to check that |q| < |p| (ie X is closer to A than B)
if 4&5 are true your point is on the border.
Edit
The other way I think I've seen this done is to take your test point X, and construct a line through X perpendicular to the line between A and B. Find where this line and the line A->B cross. Work out the distance from X to this crossing point, if that is sufficiently small you consider the point as being on the line.
Edit -- fun little exercise!
Posted some code that was wrong earlier due to me misremembering some maths.
Had a play in Pythonista on the train home and came up with this which seems to basically work. Have left the maths proof out as editing posts on iPad is painful!
Not much testing done, no testing for division by zero etc, caveat user.
# we determine the point of intersection X between
# the line between A and B and a line through T
# that is perpendicular to the line AB (can't draw perpendicular
# in ascii, you'll have to imagine that angle between AB and XT is 90
# degrees.
#
# B
# /
#. X
# / \
# / T
# A
# once we know X we can work out the closest the line AB
# comes to T, if that distance is 0 (or small enough)
# we can consider T to be on the line
import math
# work out where the line through test point t
# that is perpendicular to ab crosses ab
#
# inputs must be 2-tuples or 2-element lists of floats (x,y)
# returns (x,y) of point of intersection
def intersection_of_perpendicular(a,b,t):
if a[0] == b[0]:
return (a[0],t[1])
if a[1] == b[1]:
return (t[0],a[1])
m = (a[1] - b[1])/(a[0] - b[0]) #slope of ab
x_inter = (t[1] - a[1] + m*a[0] + (1/m)*t[0])*m/(m**2 + 1)
y_inter = m*(x_inter - a[0]) + a[1]
y_inter2 = -(1/m)*(x_inter - t[0]) + t[1]
#print '...computed ',m,(x_inter, y_inter), y_inter2
return (x_inter, y_inter)
# basic Pythagorean formula for distance between two points
def distance(a,b):
return math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 )
# check if a point is within the box defined by a,b at
# diagonally opposite corners
def point_in_box(a,b,t):
xmin = min(a[0],b[0])
xmax = max(a[0],b[0])
ymin = min(a[1],b[1])
ymax = max(a[1],b[1])
x_in_bounds = True
if xmax != xmin:
x_in_bounds = xmin <= t[0] <= xmax
y_in_bounds = True
if ymax != ymin:
y_in_bounds = ymin <= t[1] <= ymax
return x_in_bounds and y_in_bounds
# determine if point t is within 'tolerance' distance
# of the line between a and b
# returns Boolean
def is_on_line_between(a,b,t,tolerance=0.01):
intersect = intersection_of_perpendicular(a,b,t)
dist = distance(intersect, t)
in_bounds = point_in_box(a,b,t)
return in_bounds and (dist < tolerance)
a = (0,0)
b = (2,2)
t = (0,2)
p = intersection_of_perpendicular(a,b,t)
bounded = point_in_box(a,b,t)
print 'd ',distance(p,t), ' p ',p, bounded
a = (0,2)
b = (2,2)
t = (1,3)
p = intersection_of_perpendicular(a,b,t)
bounded = point_in_box(a,b,t)
print 'd ',distance(p,t),' p ',p, bounded
a = (0.0,2.0)
b = (2.0,7.0)
t = (1.7,6.5)
p = intersection_of_perpendicular(a,b,t)
bounded = point_in_box(a,b,t)
on = is_on_line_between(a,b,t,0.2)
print 'd ',distance(p,t),' p ',p, bounded,on