martes, 3 de marzo de 2015

Construcción de la Cornoide

(es) Construcción de la Cornoide

(eo) Konstruado de Kornokurbo

Construcción de la Cornoide

http://dx.doi.org/10.13140/RG.2.2.34092.90243

Descripción artística:

Instrucciones visuales para el trazo de la curva Cornoide, descubierta por el Doctor Alberto Sánchez, salvadoreño, en 1895.
La secuencia está en espiral: Comenzando en la esquina superior izquierda, luego a la derecha hasta la esquina superior derecha, luego hacia abajo hasta la esquina inferior derecha, luego a la izquierda y así sucesivamente.

Motivación:

Las instrucciones simples pero poco conocidas para la construcción de la Cornoide.

Descripción técnica:

El trazo de la curva Cornoide, en 16 pasos en espiral de afuera hacia adentro.
El procedimiento geométrico para construirla es el siguiente:
Sea C un punto de la circunferencia de diámetro director AB y sea C' el punto de intersección de la circunferencia con la paralela por el punto C al diámetro AB . Desde C se traza la recta tangente a la circunferencia y desde C' la recta perpendicular a la recta tangente. Sea D el punto intersección de ambas rectas. Cuando el punto C describe la circunferencia, el punto D describe la Cornoide.

Archivos

Código (Python):

#!/usr/bin/env python
# coding: utf-8

# Copyright 2015 Eduardo Adam Navas López
# Este programa es Software Libre liberado bajo la licencia GNU GPLv3 o su versión más reciente:
# http://www.gnu.org/licenses/gpl.html

"""Este programa genera la secuencia de pasos de la construcción de la Cornoide
"""

import pygame
import math
import escala

#prueba = False
prueba = True

if prueba:
 ANCHO = 1000
 ALTO  = 1000
else:
 ANCHO = 2000
 ALTO  = 2000

INF_IZQ = (-1.05,-1.05)
#INF_IZQ = (-1.45,-1.45)
SUP_DER = (1.45,1.45)

TAMMATRIZ = 4
NUMPASOS = 16
NUMPASOSCURVA = 160*NUMPASOS
TIEMPO_PAUSA = 600

#En pixeles:
GRUESO_CIRCULO = 4 ####2
GRUESO_CORNOIDE = 20 ####4
GRUESO_LINEA = 2
RADIO_PUNTO = 10 ####2

#En unidades virtuales:
RADIO_CIRCULO = 1.0
PROP_ANG = 0.1

ROJO   = (255,0,0)
VERDE  = (0,255,0)
AZUL   = (0,0,255)
BLANCO = (255,255,255)
NEGRO  = (0,0,0)

COLOR_CORNOIDE = (84,187,255)
COLOR_CIRCULO = NEGRO
COLOR_RADIO = (0,250,0)
COLOR_TANGENTE = (0,200,0)
COLOR_SECANTE = (0,150,0)
COLOR_FINAL = (0,100,0)
COLOR_ANGULO = (200,200,200)
COLOR_PUNTO = ROJO

matriz = [(0,0),(1,0),(2,0),(3,0),(3,1),(3,2),(3,3),(2,3),(1,3),(0,3),(0,2),(0,1),(1,1),(2,1),(2,2),(1,2),]

def cornoide(t, r=1.0):
 return r*math.cos(t)*math.cos(2*t), r*math.sin(t)*(2+math.cos(2*t))

def actualizar(lienzo,i):
 """Aquí hay que guardar las imágenes"""
 global imgfinal
 
 if prueba:
  pygame.display.flip()
  #Descomentar la siguiente línea para generar los archivos *.png individuales
  #pygame.image.save(lienzo, "img-{0:02}.png".format(i))
 else:
  if NUMPASOS==16:
   imgfinal.blit(lienzo, (ANCHO*matriz[i-1][0],ALTO*matriz[i-1][1]))

def dibujarCircunferencia(xc, yc, re, ri, color,lienzo):
 """Dibuja una circunferencia con centro (xc,yc)
 y radio exterior re e interior ri.
 """
 if re <= ri: return #No funcionaría el algoritmo
 def marcarPixel(x,y):
  lienzo.set_at(( x+xc, y+yc), color)
  lienzo.set_at(( x+xc,-y+yc), color)
  lienzo.set_at((-x+xc, y+yc), color)
  lienzo.set_at((-x+xc,-y+yc), color)
  lienzo.set_at(( y+xc, x+yc), color)
  lienzo.set_at(( y+xc,-x+yc), color)
  lienzo.set_at((-y+xc, x+yc), color)
  lienzo.set_at((-y+xc,-x+yc), color)
 def marcarLineaH(xi,xf,y):
  i = xi
  while i<=xf:
   marcarPixel(i,y)
   i = i+1
 limites = {}
 x = 0
 y = re
 d = 1-re
 while y>x:
  if d<0:
   d += x*2+3
  else:
   d += (x-y)*2+5
   limites[y] = [None, x]
   y = y-1
  x = x+1
 x = 0
 y = ri
 d = 1-ri
 if limites.has_key(y):
  limites[y][0] = x
 else:
  limites[y] = [x, None]
 while y>x:
  if d<0:
   d += x*2+3
   x = x+1
  else:
   d += (x-y)*2+5
   y = y-1
   x = x+1
   if limites.has_key(y):
    limites[y][0] = x
   else:
    limites[y] = [x, None]
 for cada_y, (xi,xf) in limites.iteritems():
  if xi is None:
   marcarLineaH(0,xf,cada_y)
  elif xf is None:
   marcarLineaH(xi,cada_y,cada_y)
  else:
   marcarLineaH(xi,xf,cada_y)


def circunferencia(lienzo, color, (xc,yc), radio, ancho=1):
 dibujarCircunferencia(xc, yc, radio+ancho/2, radio-ancho/2, color, lienzo)

def dibujar(pantalla, e):
 i = 0
 t = 0.0
 i=i+1
 while i<=NUMPASOS:
  #Limpiar lienzo:
  pantalla.fill(BLANCO)

  #Dibujar círculo:
  circunferencia(pantalla, COLOR_CIRCULO, e.vr((0.0,0.0)), int(e.magnitudvrx(RADIO_CIRCULO)), GRUESO_CIRCULO)

  #Dibujar el Cornoide hasta este punto:
  ii = 0
  Lii = i*NUMPASOSCURVA/float(NUMPASOS)
  while ii<=Lii:
   ttemp = math.pi/2 * ii/NUMPASOSCURVA
   pA = e.vr(cornoide(ttemp, RADIO_CIRCULO))
   pygame.draw.circle(pantalla, COLOR_CORNOIDE, pA, GRUESO_CORNOIDE/2)
   ii=ii+1

  #Calcular punto actual del cornoide:
  t = math.pi/2 * i/NUMPASOS
  p = cornoide(t, RADIO_CIRCULO)
  pr = e.vr(p)

  #Punto del círculo: 
  pcirc = RADIO_CIRCULO*math.cos(t), RADIO_CIRCULO * math.sin(t)

  #Radio:
  pygame.draw.line(pantalla, COLOR_RADIO, e.vr((0.0,0.0)), e.vr(pcirc), GRUESO_LINEA)

  #Recta tangente al círculo:
  pendienteRad = math.tan(t)
  pendienteTan = -1.0/pendienteRad
  ptan1 = e.minxv, pendienteTan * (e.minxv - pcirc[0]) + pcirc[1]
  ptan2 = e.maxxv, pendienteTan * (e.maxxv - pcirc[0]) + pcirc[1]
  pygame.draw.line(pantalla, COLOR_TANGENTE, e.vr(ptan1), e.vr(ptan2), GRUESO_LINEA)

  #Secante al círculo:
  pcirc2 = (-pcirc[0], pcirc[1])
  pygame.draw.line(pantalla, COLOR_SECANTE, e.vr(pcirc2), e.vr(pcirc), GRUESO_LINEA)

  #Segmento final:
  pygame.draw.line(pantalla, COLOR_FINAL, e.vr(pcirc2), pr, GRUESO_LINEA)

  ##Marcadores de ángulos rectos:
  pe1 = (1.0+PROP_ANG)*p[0] - PROP_ANG*pcirc[0], (1.0+PROP_ANG)*p[1] - PROP_ANG*pcirc[1]
  pe2 = p[1]+p[0]-pe1[1], p[1]-p[0]+pe1[0]
  pe3 = pe1[0] + pe2[0]-p[0], pe1[1] + pe2[1]-p[1]
  pygame.draw.line(pantalla, COLOR_TANGENTE, e.vr(pe1), e.vr(pe3), GRUESO_LINEA)
  pygame.draw.line(pantalla, COLOR_TANGENTE, e.vr(pe2), e.vr(pe3), GRUESO_LINEA)
  
  pe1 = (1.0+PROP_ANG)*pcirc[0] - PROP_ANG*p[0], (1.0+PROP_ANG)*pcirc[1] - PROP_ANG*p[1]
  pe2 = -pcirc[1]+pcirc[0]+pe1[1], pcirc[1]+pcirc[0]-pe1[0]
  pe3 = pe1[0] + pe2[0]-pcirc[0], pe1[1] + pe2[1]-pcirc[1]
  pygame.draw.line(pantalla, COLOR_TANGENTE, e.vr(pe1), e.vr(pe3), GRUESO_LINEA)
  pygame.draw.line(pantalla, COLOR_TANGENTE, e.vr(pe2), e.vr(pe3), GRUESO_LINEA)
  

  ##Puntos:
  #Centro del círculo:
  pygame.draw.circle(pantalla, COLOR_PUNTO, e.vr((0.0,0.0)), RADIO_PUNTO)
  #Punto del círculo: 
  pygame.draw.circle(pantalla, COLOR_PUNTO, e.vr(pcirc), RADIO_PUNTO)
  #Simétrico al anterior (de la secante):
  pygame.draw.circle(pantalla, COLOR_PUNTO, e.vr(pcirc2), RADIO_PUNTO)
  #Punto guía de la cornoide:
  pygame.draw.circle(pantalla, COLOR_PUNTO, pr, RADIO_PUNTO)
  
  #Dibujar y guardar si está habilitado
  actualizar(pantalla, i)
  if prueba:
   pygame.time.delay(TIEMPO_PAUSA)

  i = i+1


if __name__ == "__main__":
 global imgfinal
 
 pygame.init()

 if prueba:
  pantalla = pygame.display.set_mode((ANCHO, ALTO))
  pygame.display.set_caption("Cornoide")
 else:
  pantalla = pygame.Surface((ANCHO, ALTO))
  imgfinal = pygame.Surface((ANCHO*TAMMATRIZ, ALTO*TAMMATRIZ))

 e = escala.Escala((ANCHO, ALTO), INF_IZQ, SUP_DER)
 dibujar(pantalla, e)
 
 #Guardar imagen final
 if not prueba and NUMPASOS==16:
  for x in range(TAMMATRIZ-1):
   pygame.draw.line(imgfinal, (0,0,0), (ANCHO*(x+1),0), (ANCHO*(x+1),ALTO*TAMMATRIZ))
  for y in range(TAMMATRIZ-1):
   pygame.draw.line(imgfinal, (0,0,0), (0,ALTO*(y+1)), (ANCHO*TAMMATRIZ, ALTO*(y+1)))
  
  pygame.image.save(imgfinal, "pasos.png")
 
 raw_input("Presione una tecla para salir")

No hay comentarios:

Publicar un comentario