Alors je viens de finir un programme sans prétention qui ,je l'espère,vous impressionnera:
Il sait:
<ul>
<li>Trouver le nombre de quadrilatère / les donner</li>
<li>Trouver un cas spécial (6 points,39 quadrilatères)</li>
<li>Faire de rapides stats (maximum/minimum de quadrilatères pour n points en ayant faire k essais</li>
<li>Afficher les quadrilatères trouvés
<ul>
<li> Déplacer les points (clic gauche->drag)</li>
<li> Ajouter de nouveaux points (clic droit)</li>
<li> Refaire une nouvelle liste de points (espace)</li>
<li> Changer le nombre de points (flèche droite et gauche)</li>
</ul></li>
</ul>
Pour le lancer il vous faudra python (2.x) et pygame (paquet python-pygame)
Source / Exemple :
############################################### quad.py ###################################
#!/usr/bin/env python
from random import randint
import operator
import view
def Cnp(n,p, l=None, res=None):
"""Return combinaisons of k lenght of [1,2,3,...,n] set"""
if l is None: l=[]
if res is None: res=[]
if p==0:
res.append(l)
return
if n==0: return
l1=list(l)
l1.append(n)
Cnp(n-1, p-1, l1, res)
Cnp(n-1, p, l, res)
return res
def Anp(n, p, l=None, res=None):
"""Return arrangements of k lenght of [1,2,3,...,n] set"""
if l is None: l=[]
if res is None: res=[]
if p==0:
res.append(l)
return
for k in range(1,n+1):
if k not in l:
l1=list(l)
l1.append(k)
Anp(n, p-1, l1,res)
return res
def get_arrangements(list,p):
"""Return all p-arrangement in the list
ex = get_arrangements('ABC',3) == ('ABC','ACB','BAC','BCA','CAB','CBA')
"""
if len(list) < p:
return []
return [[list[i-1] for i in el] for el in Anp(len(list),p)]
def get_combinaisons(list,p):
"""Return all p-subset in the list"""
if len(list) < p:
return []
return [[list[i-1] for i in el] for el in Cnp(len(list),p)]
def is_colinear(u,v):
(u1,u2),(v1,v2) = u,v
return u1*v2 == u2*v1
def is_points_colinear(p1,p2,p3,p4):
u = map(operator.sub,p2,p1)#just u[0] = p2[0] - p1[0],u[1] = ...
v = map(operator.sub,p4,p3)
return is_colinear(u,v)
def is_aligned(p1,p2,p3):
return is_points_colinear(p1,p2,p2,p3)
def is_aligned_with_one_in(p1,points):
"""Return True if p1 is aligned with one point in points"""
for p2,p3 in get_arrangements(points,2):
if is_aligned(p1,p2,p3):
return True
return False
def get_lines_pintersection(p1,p2,p3,p4):
"""Return point of intersection between L1(p1,p2) and L2(p3,p4)"""
if is_points_colinear(p1,p2,p3,p4) : return None
(x1,y1),(x2,y2),(x3,y3),(x4,y4) = p1,p2,p3,p4
i , j = (x1*y2-y1*x2),(x3*y4-y3*x4)
q = float((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4))
x = (i*(x3-x4)-(x1-x2)*j) / q
y = (i*(y3-y4)-(y1-y2)*j) / q
return (x,y)
def get_lines_vintersection(u,v):
return get_lines_pintersection(u[0],u[1],v[0],v[1])
def get_random_point(w,h):
"""Return a random point with 0 <= x <= w and 0 <= x <= h"""
return (randint(0,w),randint(0,h))
def get_random_points(n,w,h):
"""Return n random points non-aligned"""
points = []
for i in xrange(n):
p = get_random_point(w,h)
while p in points or is_aligned_with_one_in(p,points):
p = get_random_point(w,h)
points.append(p)
return points
def is_in_seg_but_not_in_line(p,seg):
"""Return if p is in the segment (seg) but not in the line (formed by the seg two points)"""
#Just verify if p is in seg bounding box
xmin = min(seg[0][0],seg[1][0])
ymin = min(seg[0][1],seg[1][1])
xmax = max(seg[0][0],seg[1][0])
ymax = max(seg[0][1],seg[1][1])
x,y = p
return x >= xmin and x <= xmax and ymin <= y and ymax >= y
def is_cross_quad(quad):
"""Return True if quad is crossed
ex:for a square ABCD,ACBD is crossed
"""
segs = []
for i in range(4):
segs.append((quad[i % 4],quad[(i+1) % 4]))
i1 = get_lines_vintersection(segs[0],segs[2])
i2 = get_lines_vintersection(segs[1],segs[3])
if (i1 != None and is_in_seg_but_not_in_line(i1,segs[0]) and is_in_seg_but_not_in_line(i1,segs[2]))\
or (i2 != None and is_in_seg_but_not_in_line(i2,segs[1]) and is_in_seg_but_not_in_line(i2,segs[3])) :
return True
return False
def in_triangle(p,tri):
"""Return True if p is in tri"""
(x1,y1),(x2,y2),(x3,y3) = tri
xx,yy = p
a0 = abs((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))
a1 = abs((x1-xx)*(y2-yy)-(x2-xx)*(y1-yy))
a2 = abs((x2-xx)*(y3-yy)-(x3-xx)*(y2-yy))
a3 = abs((x3-xx)*(y1-yy)-(x1-xx)*(y3-yy))
return abs(a1+a2+a3-a0) <= 1.0/256
def get_interior_point(q):
"""Return point inside the 3 others in this quad
or None of q is convex
"""
for i,p in enumerate(q):
tri = q[:i]+q[i+1:]
if in_triangle(p,tri):
return p
def count_quads(points):
"""Count quads more efficiently"""
c = 0
for comb in get_combinaisons(points,4):
ip = get_interior_point(comb)
if ip == None: #convex
c += 1 #1 choice
else: #concave
c += 3 #3 choice
return c
def get_quads(points):
"""Return all possible quads (non-crossed,BCDA == ABCD) for given points"""
quads = []
for comb in get_combinaisons(points,4):
ip = get_interior_point(comb)
if ip == None: #convex
for arr in get_arrangements(comb[1:],3):
q = (comb[0],) + tuple(arr)
#print q
if not is_cross_quad(q):
quads.append(q)
break
else: #concave
pos = comb.index(ip)
quads.append([comb[(pos+i)%4] for i in (0,1,2,3)])
quads.append([comb[(pos+i)%4] for i in (0,1,3,2)])
quads.append([comb[(pos+i)%4] for i in (0,3,1,2)])
return quads
def update(n = 15):
"""Return (points,quads) with points = random points and quads = all possible quads"""
points = get_random_points(n,view.WIDTH,view.HEIGHT)
quads = get_quads(points)
return (points,quads)
def quads_numbered(quads,points):
"""Return ((1,3,4,2),(2,4,5,3),...) quads for given (((0.55,0.21),(541,322),(51,444),(12,32)),...) quads
useful for debugging (see if quads are valid)
"""
l = []
for q in quads:
qn = []
for p in q:
qn.append(points.index(p))
l.append(qn)
return l
def print_stat(n,k):
"""Print max and min in k loops"""
list = []
print 'Stat:k=',k
print
ans = ()
counter = 0
for i in xrange(k):
c = count_quads(get_random_points(n,1000,1000))
list.append(c)
new = [max(list),min(list)]
if new != ans:
ans = new
print counter,new
list = [max(list),min(list)]
counter += 1
print
print "max:",max(list)
print "min:",min(list)
def show_special_case(n,case):
points,quads = update(n)
while len(quads) != case:
points,lines,quads = update(n)
view.show(points,quads)
def main():
points,quads = update()
view.show(points,quads)
#print_stat(7,100)
#show_special_case(7,79)
if __name__ == "__main__":
main()
############################################### view.py ###################################
#!/usr/bin/env python
import pygame ,os
import quad
from pygame.locals import *
WIDTH,HEIGHT = 800,600
def draw_text(surf,text,pos=(0,0),size = 40,color=(100,100,100)):
font = pygame.font.Font(pygame.font.get_default_font(),size)
text = font.render(text,True,color)
surf.blit(text,pos)
def draw_points(screen,points):
radius = 5
font = pygame.font.Font(pygame.font.get_default_font(),radius*4)
for i,point in enumerate(points):
pygame.draw.circle(screen, (0,0,0), point, radius)
text = font.render(str(i),True,(100,100,100))
screen.blit(text,point)
def draw_quads(screen,quads):
for q in quads:
pygame.draw.polygon(screen, (255,87,0), q, 1)
def show(points,quads):
os.environ['SDL_VIDEO_CENTERED'] = '1'
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Points viewer")
pygame.font.init()
selected = None
points = [list(p) for p in points] #tuple to list
stopLoop = False
while not stopLoop:
for event in pygame.event.get():
update = False
if event.type == QUIT: stopLoop = True
elif event.type == KEYDOWN:
if event.key in (K_ESCAPE,K_RETURN):stopLoop = True
if event.key == K_RIGHT:
update = True
points.append(list(quad.get_random_point(WIDTH,HEIGHT)))
if event.key == K_LEFT:
update = True
points = points[:-1]
elif event.key in (K_u,K_SPACE):
update = True
points = get_random_points(points)
points = [list(p) for p in points]
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for p in points:
if abs(p[0] - event.pos[0]) < 10 and abs(p[1] - event.pos[1]) < 10 :
selected = p
elif event.button == 3:
x,y = pygame.mouse.get_pos()
points.append([x,y])
update = True
elif event.type == MOUSEBUTTONUP and event.button == 1:
if selected is not None:
update = True
selected = None
if update:
draw_text(screen,"please wait...",(0,HEIGHT-40))
pygame.display.flip()
n = len(points)
quads = quad.get_quads(points)
screen.fill((255,255,255))
if selected is not None:
selected[0],selected[1] = pygame.mouse.get_pos()
pygame.draw.circle(screen, (255,200,200), selected, 10)
draw_quads(screen,quads)
draw_points(screen,points)
draw_text(screen,str(len(points))+" points,"+str(len(quads))+" quads")
pygame.display.flip()
if __name__ == "__main__":
quad.main()
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.