Figura 1.
Comunicación entre el
Canvas y el Painter
Para
que al momento de darle click en un botón en el Painter responda el Canvas hay
que agregar las posibles respuestas de Canvas para cada botón, estas son denominadas
SLOTS() y se declaran en el archivo .h con la etiqueta “public slots:”. Para
cada posible botón se declaro un slot. Esto se hizo agregando el siguiente
código a canvas.h:
public slots:
void setKind1();
void setKind2();
void setKind3();
void setKind4();
y
al mismo tiempo agregando a canvas.cpp las siguientes funciones:
void Canvas::setKind1()
{
kind
= 1;
repaint();
}
void Canvas::setKind2()
{
kind
= 2;
repaint();
}
void Canvas::setKind3()
{
kind
= 3;
repaint();
}
void Canvas::setKind4()
{
kind
= 4;
repaint();
}
las
cuales actualizan la variable kind y mandan redibujar el Canvas.
Para
que el objeto Painter pueda hacer uso de estos nuevos SLOT()’s se tiene que
conectar el comportamiento de los botones descritos anteriormente a el SLOT() que
le corresponde quedando el código de painter.cpp de la siguiente manera:
QPushButton *boton1 = new QPushButton("A");
boton1->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton1, SIGNAL(clicked()),
canvas, SLOT(setKind1()) );
QPushButton *boton2 = new QPushButton("B");
boton2->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton2, SIGNAL(clicked()),
canvas, SLOT(setKind2()) );
QPushButton *boton3 = new QPushButton("C");
boton3->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton3, SIGNAL(clicked()),
canvas, SLOT(setKind3()) );
QPushButton *boton4 = new QPushButton("D");
boton4->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( boton4, SIGNAL(clicked()),
canvas, SLOT(setKind4()) );
Dibujo de patrones.
Hasta
este momento hemos conectado Painter y Canvas, y unido sus funciones para que
se modifique que patrón de dibujo con el click de cada botón. Pero toda vía no
hemos definido los patrones así que se empezara a mostrar el código usado en
cada función para desplegar el patrón en el Canvas.
dibujo1()
Utiliza
la función dibujo1Cuadro()
para dibujar un rectángulo entre sus 4 combinaciones de sus puntos puntos:
void Canvas::dibujo1Cuadro(int x, int y, int x0, int y0, QPainter *p ){
MidPointLine(
x0+x, y0+y, x0+x, y0-y, p );
MidPointLine(
x0+x, y0-y, x0-x, y0-y, p );
MidPointLine(
x0-x, y0-y, x0-x, y0+y, p );
MidPointLine(
x0-x, y0+y, x0+x, y0+y, p );
}
Seguimos
con la implementación del patrón (Figura 2.):
void Canvas::dibujo1( QPainter *p )
{
int cx = w/2; // canvas center
int cy = h/2; // canvas center
int incrang = 5;
int l = 100;
int n = (360/incrang)/4;
// int n = 19;
for ( int i=0;
i < n; i++ ) {
float ang = i*incrang;
ang
= ang * ANGTORAD;
float val = l*cos(ang);
//float val =
l*cos(ang) + cx;
int px = Round( val );
val
= l*sin(ang);
//val = l*sin(ang) +
cy;
int py = Round( val );
//MidPointLine( cx,
cy, px, py, p );
dibujo1Cuadro(px
,py ,cx ,cy, p);
}
}
Figura 2.
dibujo2()
Utiliza
la función dibujo2Cuadro()
para dibujar un cuadro entre 4 puntos desfasados en algún ángulo:
void Canvas::dibujo2Cuadro(int x, int y, int x0, int y0, QPainter *p ){
MidPointLine(
x0+x, y0+y, x0-y, y0+x, p );
MidPointLine(
x0-y, y0+x, x0-x, y0-y, p );
MidPointLine(
x0-x, y0-y, x0+y, y0-x, p );
MidPointLine(
x0+y, y0-x, x0+x, y0+y, p );
}
Seguimos
con la implementación del patrón (Figura 3.):
void Canvas::dibujo2( QPainter *p )
{
int cx = w/2; // canvas center
int cy = h/2; // canvas center
int incrang = 10;
int l = 100;
int n = (360/incrang)/4;
// int n = 19;
for ( int i=0;
i < n; i++ ) {
float ang = i*incrang;
ang
= ang * ANGTORAD;
float val = l*cos(ang);
//float val =
l*cos(ang) + cx;
int px = Round( val );
val
= l*sin(ang);
//val = l*sin(ang) +
cy;
int py = Round( val );
//MidPointLine( cx,
cy, px, py, p );
dibujo2Cuadro(px
,py ,cx ,cy, p);
}
}
Figura 3.
dibujo3() : Hilbert
Al
inicio de la función se establecen valores como el tamaño de segmento y ángulo
inicial y procede a pasarle el control a una función denominada hilbert_level() a la cual se
le envía la información de nivel, dirección y distancia del segmento, la función
se despliega a continuación:
void Canvas::dibujo3( QPainter *p )
{
int l = w < h?w/32:h/32, angulo=0;
xo
= xd = 0; yo = yd = 0;
p->setPen("White");
MidPointLine(
0, h/2, w, h/2,
p );
MidPointLine( w/2, 0, w/2, h, p );
p->setPen("Blue");
hilbert_level(5, 0, l, p);
printf("///////////////");
}
Se
desarrollo una una función move(),
que se encarga de dibujar un segmento en una dirección, se muestra a
continuación:
void Canvas::move(int a, int l, QPainter *p){
switch(a){
case 0:yd -= l; break;
case 1 : xd -= l; break;
case 2 :yd += l; break;
case 3 : xd += l; break;
}
MidPointLine(
xo, yo, xd, yd, p );
xo=
xd;
yo=
yd;
}
La
función hilbert_level
es una función recursiva la cual dibuja el fractal de Hilbert, y se desarrolla
a continuación (Figura 4.):
void Canvas::hilbert_level(int level, int direction, int l, QPainter *p)
{
if (level==1) {
switch (direction) {
case 1:
move(3, l, p); move(2, l, 
p); move(1, l, p);
break;
case 3:
move(1, l, p);
move(0, l, p);
move(3, l, p);
break;
case 0:
move(2, l, p);
move(3, l, p);
move(0, l, p);
break;
case 2:
move(0, l, p);
move(1, l, p);
move(2, l, p);
break;
}
}
else {
switch (direction) {
case LEFT:
hilbert_level(level-1,0,l,p);
move(RIGHT,
l, p);
hilbert_level(level-1,1,l,p);
move(DOWN,
l, p);
hilbert_level(level-1,1,l,p);
move(LEFT,
l, p);
hilbert_level(level-1,2,l,p);
break;
case RIGHT:
hilbert_level(level-1,2,l,p);
move(LEFT,
l, p);
hilbert_level(level-1,3,l,p);
move(UP,
l, p);
hilbert_level(level-1,3,l,p);
move(RIGHT,
l, p);
hilbert_level(level-1,0,l,p);
break;
case UP:
hilbert_level(level-1,1,l,p);
move(DOWN,
l, p);
hilbert_level(level-1,0,l,p);
move(RIGHT,
l, p);
hilbert_level(level-1,0,l,p);
move(UP,
l, p);
hilbert_level(level-1,3,l,p);
break;
case DOWN:
hilbert_level(level-1,3,l,p);
move(UP,
l, p);
hilbert_level(level-1,2,l,p);
move(LEFT,
l, p);
hilbert_level(level-1,2,l,p);
move(DOWN,
l, p);
hilbert_level(level-1,1,l,p);
break;
}
}
}
Figura 4.
dibujo4(): KGen
Esta
función dibuja un fractal denominado KGen. Inicia estableciendo los valores
iniciales y de largo total del segmento a dibujar. Se muestra a continuación la
implementación:
void Canvas::dibujo4( QPainter *p )
{
xo
= 0; yo = h/2;
angulo
=0;
int l = w;
int i;
KGen
(l, 4, p);
}
La
funcion KGen es una función recursiva la cual es la encargada de dibujar el
fractal, se le proporciona el largo en que

se de ve dibujar el segmento al que se le esta llamando y el nivel de
implementación. Se muestra a continuación la implementación (Figura 5.):
void Canvas::KGen(int l, int nivel, QPainter *p){
if (nivel==0){
dibujo3CalculaPuntos(
l, angulo, p, nivel);
}else{
nivel--;
l=Round(l/3);
KGen(l,
nivel, p);
angulo+=60;
KGen(l,
nivel, p);
angulo-=120;
KGen(l,
nivel, p);
angulo+=60;
KGen(l,
nivel, p);
}
}
Figura 5.