Najprościej (ale nie najwydajniej) jest imho zrobić tak: sprawdzasz, czy linia poprowadzona pomiędzy dwoma dowolnymi różnymi nienastępującymi po sobie wierzchołkami koliduje z którąkolwiek z linii poprowadzonych pomiędzy dwoma następującymi po sobie wierzchołkami.
Ale kombinujesz. Nie dość że algorytm O(n^2), to jeszcze wcale nie najprostszy ;].
Najprościej, jak pisała @AgnieszkaUp, iść po kolei po punktach i sprawdzać czy 'zakręt' jaki tworzą trzy kolejne punkty jest 'w prawo' czy 'w lewo'. Tzn. jeśli narysujesz wielokąt wypukły na ziemi i będziesz chodził po jego krawędziach, to zawsze będziesz skręcał w jednym kierunku - nigdy tak że raz w lewo, raz w prawo.
Tutaj luźna implementacja tego pomysłu, przy czym zakłada że wielokąt jest wierzchołkami w kierunku przeciwnym do ruchu wskazówek zegara (nie testowana dokładnie, ale powinno działać):
def sub(a, b): # odejmowanie "wektorów"
return (a[0] - b[0], a[1] - b[1])
def cross(u, v): # cross product między wektorami
return u[0] * v[1] - u[1] * v[0]
def is_convex(poly):
p = poly + [poly[0], poly[1]] # żeby się warunkami brzegowymi nie przejmować
for i in xrange(len(poly)):
if cross(sub(p[i], p[i+1]), sub(p[i+1], p[i+2])) < 0:
return False
return True
(Cross product wektorów (a ściśle jego analogia w 2D) jest równy liczbowo |a|*|b|*sin(a, b), więc po jego znaku możemy zgadywać kierunek 'skrętu')
Trzy przykłady na których przetestowałem przed wysłaniem:
print is_convex([ (0, 0), (1, 0), (1, 1), (0, 1) ])
print is_convex([ (0, 0), (1, 0), (0.1, 0.1), (0, 1) ])
print is_convex([ (0.7, 0.7), (1, 0), (1, 1), (0, 1) ])