Está en la página 1de 14

Ruiz Coronel Erick David

2143067521
Fecha:22/03/2022

GEOMETRÍA COMPUTACIONAL

Tarea No. 1

Algoritmo de Graham
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022

El método de Graham (Graham scan) es un método de cálculo computacional de la


envolvente convexa de un conjunto finito de puntos en el plano, de complejidad O(nlogn).
El algoritmo calcula todos los vértices de la envolvente convexa ordenados a lo largo de la
frontera. Puede ser fácilmente modificado para calcular los puntos que, sin ser vértices,
pertenecen a dicha envolvente.

DESCRIPCIÓN DEL ALGORITMO

1. Hallar un punto q interior al cierre convexo

2. Ordenar los N puntos angularmente en sentido positivo alrededor


de él.
Llamaremos p(n) al punto situado en la posición n

3. (Scan) Recorrer la lista ordenada de puntos hasta que se llegue al


punto de partida

Examinar tripletas de puntos consecutivos [p(i-1),p(i),p(i+1)]

a. Si la tripleta es un giro a la izquierda se avanza un vértice


y se comprueba [p(i),p(i+1),p(i+2)]

b. Si la tripleta no es un giro a la izquierda, entonces p(i) no


es un vértice, ya que es interior a [q,p(i-1),p(i+1)].

i. Eliminar p(i)

ii. Comprobar la Tripleta [p(i-2),p(i-1),p(i+1)]

4. Los puntos que queden son los vértices de la envolvente


convexa.
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022

Código del programa:


from matplotlib import pyplot as plt
from random import randint
from math import atan2
box={'facecolor': '#FFFF99','boxstyle': 'round'}

def pausa(key):
if key == '':
print(" ")

def label():
plt.title('Envolvente Convexa - Erick Ruiz')
plt.xlabel('Eje - X')
plt.ylabel('Eje - Y')

def generarGraficaPasos(noConvexa0,noConvexa,step,coords,envolventeConvexa=None):
nC=0
xs,ys=zip(*coords)
plt.scatter(xs,ys,color="black")
puntosOrdenEnum=quicksort(coords)
if noConvexa0 != []:
for z in range(len(puntosOrdenEnum)):
for zz in range(len(noConvexa0)):
if puntosOrdenEnum[z]==noConvexa0[zz]:
zx=puntosOrdenEnum[z-1]
zy=puntosOrdenEnum[z+1]
zxy=noConvexa0[zz]
plt.plot((zy[0],zxy[0]),(zy[1],zxy[1]),color='black',linestyle='dashed',fillstyle='bottom')
plt.plot((zx[0],zxy[0]),(zx[1],zxy[1]),color='black',linestyle='dashed',fillstyle='bottom')
if envolventeConvexa!=None:
for i in range(1,len(envolventeConvexa)+1):
if i==len(envolventeConvexa): i=0
c0=envolventeConvexa[i-1]
c1=envolventeConvexa[i]
c00=envolventeConvexa[len(envolventeConvexa)-1]
c01=envolventeConvexa[len(envolventeConvexa)-2]
c02=envolventeConvexa[len(envolventeConvexa)-3]
plt.text(c00[0]+1.5,c00[1]-1,'f',bbox=box)
if i>0:
if i<len(envolventeConvexa)-1:
plt.plot((c0[0],c1[0]),(c0[1],c1[1]),color='green',fillstyle='top')
if i==2 and len(envolventeConvexa)<4:
if noConvexa==[]:
plt.plot((c00[0],c01[0]),(c00[1],c01[1]),color='blue',fillstyle='top')
plt.text(c01[0]+1.5,c01[1]-1,'m',bbox=box)
plt.text(c02[0]+1.5,c02[1]-1,'o',bbox=box)
if noConvexa!=[]:
cxx=noConvexa[0]
plt.plot((c02[0],c01[0]),(c02[1],c01[1]),color='green',fillstyle='top')
plt.plot((c01[0],cxx[0]),(c01[1],cxx[1]),color='blue',fillstyle='top')
plt.plot((cxx[0],c00[0]),(cxx[1],c00[1]),color='red',fillstyle='top')
nC=1
del noConvexa[0]
if i>2:
if noConvexa!=[]:
if nC != 1:
cxx=noConvexa[0]
plt.plot((c02[0],c01[0]),(c02[1],c01[1]),color='green',fillstyle='top')
plt.plot((c01[0],cxx[0]),(c01[1],cxx[1]),color='blue',fillstyle='top')
plt.plot((cxx[0],c00[0]),(cxx[1],c00[1]),color='red',fillstyle='top')
plt.text(cxx[0]+1.5,cxx[1]-1,'m',bbox=box)
plt.text(c01[0]+1.5,c01[1]-1,'o',bbox=box)
nC=1
del noConvexa[0]
if nC==0:
plt.plot((c0[0],c1[0]),(c0[1],c1[1]),color='green',fillstyle='top')
plt.plot((c00[0],c01[0]),(c00[1],c01[1]),color='red',fillstyle='top')
plt.plot((c01[0],c02[0]),(c01[1],c02[1]),color='blue',fillstyle='top')
plt.text(c01[0]+1.5,c01[1]-1,'m',bbox=box)
plt.text(c02[0]+1.5,c02[1]-1,'o',bbox=box)
label()
enumerarPts(puntosOrdenEnum)
plt.show()
enter = input("Pulsa ENTER para continuar: ")
pausa(enter)

def generarGrafica(noConvexa0,coords,envolventeConvexa=None):
xs,ys=zip(*coords)
plt.scatter(xs,ys,color="black")
puntosOrdenEnum=quicksort(coords)
if envolventeConvexa!=None:
for i in range(0,len(envolventeConvexa)):
if i==len(envolventeConvexa): i=0
c0=envolventeConvexa[i-1]
c1=envolventeConvexa[i]
c00=envolventeConvexa[0]
c01=envolventeConvexa[len(envolventeConvexa)-1]
c02=envolventeConvexa[len(envolventeConvexa)-2]
plt.text(c00[0]+1.5,c00[1]-1,'f',bbox=box)
plt.text(c01[0]+1.5,c01[1]-1,'m',bbox=box)
plt.text(c02[0]+1.5,c02[1]-1,'o',bbox=box)
plt.plot((c0[0],c1[0]),(c0[1],c1[1]),color='green',fillstyle='top')
if noConvexa0 != []:
for z in range(len(puntosOrdenEnum)):
for zz in range(len(noConvexa0)):
if puntosOrdenEnum[z]==noConvexa0[zz]:
zx=puntosOrdenEnum[z-1]
zy=puntosOrdenEnum[z+1]
zxy=noConvexa0[zz]
plt.plot((zx[0],zxy[0]),(zx[1],zxy[1]),color='black',linestyle='dashed',fillstyle='top')
plt.plot((zy[0],zxy[0]),(zy[1],zxy[1]),color='black',linestyle='dashed',fillstyle='top')
label()
enumerarPts(puntosOrdenEnum)
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
plt.show()
print ("\nEnvolvente convexa:",envolventeConvexa)
enter = input("Pulsa ENTER para finalizar: ")
pausa(enter)

def enumerarPts(coordenadas):
for enum0 in range(0,len(pts)):
if enum0==len(pts): enum0=-1
po0=coordenadas[enum0]
plt.text(po0[0]-0.4,po0[1]+1.5,enum0+1)

def anguloPolar(p0,p1=None):
if p1==None: p1=ancla
y_span=p0[1]-p1[1]
x_span=p0[0]-p1[0]
return atan2(y_span,x_span)

def distancia(p0,p1=None):
if p1==None: p1=ancla
y_span=p0[1]-p1[1]
x_span=p0[0]-p1[0]
return y_span**2 + x_span**2

def det(p1,p2,p3):
return (p2[0]-p1[0])*(p3[1]-p1[1]) \
-(p2[1]-p1[1])*(p3[0]-p1[0])

def quicksort(a):
if len(a)<=1: return a
menor,igual,mayor=[],[],[]
piv_ang=anguloPolar(a[randint(0,len(a)-1)])
for pt in a:
pt_ang=anguloPolar(pt)
if pt_ang<piv_ang: menor.append(pt)
elif pt_ang==piv_ang: igual.append(pt)
else: mayor.append(pt)
return quicksort(menor) \
+sorted(igual,key=distancia) \
+quicksort(mayor)

def graham(puntos,show_progress=False):
global ancla
paso=1
stp=0
min_idx=None
for i,(x,y) in enumerate(puntos):
if min_idx==None or y<puntos[min_idx][1]:
min_idx=i
if y==puntos[min_idx][1] and x<puntos[min_idx][0]:
min_idx=i
ancla=puntos[min_idx]
puntosOrden=quicksort(puntos)
del puntosOrden[puntosOrden.index(ancla)]
envolvente=[ancla,puntosOrden[0]]
noEnvolvente=[]
noEnvolvente0=[]
for s in puntosOrden[1:]:
while det(envolvente[-2],envolvente[-1],s)<=0:
noEnvolvente.append(envolvente[-1])
noEnvolvente0.append(envolvente[-1])
del envolvente[-1]
stp=stp+1
envolvente.append(s)
if show_progress:
print('\nPaso #: ',paso)
generarGraficaPasos(noEnvolvente0,noEnvolvente,stp,puntos,envolvente)
paso=paso+1
print('\nPaso #: ',paso)
generarGrafica(noEnvolvente0,puntos,envolvente)
return 0

pts=[[42, 20], [28, 35], [13, 13], [21, 1], [39, 27], [12, 29], [31, 31], [39, 34], [35, 9], [15, 28]]
print ("\nSe han generado los siguientes puntos:",pts,"\n")
envolvente=graham(pts,True)
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022
Ruiz Coronel Erick David
2143067521
Fecha:22/03/2022

Conclusiones:

El algoritmo de Graham es uno de los más conocidos en lo que respecta a los algoritmos
para encontrar la cerradura convexa de una nube de puntos. Fue desarrollado a finales de la
década de los 60, cuando en los laboratorios Bell se necesitaba calcular la cerradura
convexa de una cantidad enorme de puntos (10000 a más), y con uno de los algoritmos de
por entonces, de O(N^2) resultaba demasiado lento. Entonces Graham lo solucionó con el
presente algoritmo.

Bibliografía:

Colaboradores de Wikipedia. (2021, 7 mayo). Método de Graham. Wikipedia, la


enciclopedia libre.
https://es.wikipedia.org/wiki/M%C3%A9todo_de_Graham#:%7E:text=El%20m%C3%A9t
odo%20de%20Graham%20(Graham,public%C3%B3%20el%20algoritmo%20en%201972.

Brian Faure. (2017, 29 noviembre). Graham Scan: Background & Python Code. YouTube.

https://www.youtube.com/watch?v=vPDPE66nhlo&t=1s

También podría gustarte