Hola chavos! Me da gusto saludarlos y que me acompañen a realizar más aplicaciones de graficación. El día de hoy vamos a continuar con aplicaciones en C#, vamos a volver a realizar la aplicación del algoritmo DDA para dibujar líneas pero ésta vez lo vamos a hacer utilizando las librerías de Open GL.
Lo primero que tenemos que hacer es descargar la aplicación taoframework (en mi caso estoy usando la versión 2.1.0). Lo instalamos normalmente dando "Next" a cada ventana que nos salga. Ahora creamos una nueva aplicación en consola en C#. Aun no podemos utilizar las librerías de Open GL sino que tenemos que agregar las referencias al nuestro proyecto, lo anterior lo hacemos abriendo el menú "Proyecto", luego "Agregar referencia...", después nos vamos a la pestaña "Examinar" y ahí buscamos la carpeta donde hayamos instalado el taoframework y en alguna de las carpetas buscamos los archivos "Tao.OpenGL.dll" y "Tao.FreeGlut.dll" y le damos clic a "Aceptar". Ahora tenemos que agregar los "using" para poder acceder a las clases de estas librerías, agregamos los siguientes "using" al final de los que están cargados por defecto:
using Tao.FreeGlut;
using Tao.OpenGl;
Ahora declaramos las siguientes variables de manera local:
static double x1, y1, x2, y2;
Ahora dentro del método Main() que es el principal de nuestra aplicación, escribimos el siguiente código:
static void Main(string[] args)
{
Console.WriteLine("introduzca el valor de X1");
x1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("introduzca el valor de Y1");
y1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("introduzca el valor de X2");
x2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("introduzca el valor de Y2");
y2 = Convert.ToDouble(Console.ReadLine());
Glut.glutInit();//funciones propias de opengl
Glut.glutInitDisplayMode(Glut.GLUT_SINGLE | Glut.GLUT_RGB);
Glut.glutInitWindowSize(640, 480);//creamos una ventana
Glut.glutCreateWindow("**************Algoritmo DDA**************");//colocamos titulo a la ventana
//llamamos a la funcion dda
Glut.glutDisplayFunc(dda);
Glut.glutMainLoop();
}
Después declaramos un método estático llamado dda(), el cual dibujará unas líneas que dividirán la pantalla representando los 4 cuadrantes y llamará al método que dibujará la línea DDA:
public static void dda()
{
//componentes necesarios de opengl
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);//limpia el buffer de la pantall
Gl.glColor3f(0.6F, 0.6F, 0.6F);//poner color a los pixeles
Gl.glLoadIdentity();//''muy importante;
Gl.glPointSize(0.5f);//medida de los puntos
Gl.glBegin(Gl.GL_POINTS);//funcion para dibujar puntos
//dibujando el plano
float z = -1, w = 1, c = 0;
for (int i = 0; i < 200; i++)
{
Gl.glColor3f(w, c, z);
Gl.glVertex2d(z, 0);
Gl.glVertex2d(0, w);
z += .01f;
w -= .01f;
c += .1f;
}
Gl.glEnd();//termina funcion para dibujar puntos
//pasamos las
Gl.glPointSize(3.0f);//sirve para el tamaño de los pixeles
Gl.glColor3f(1.0f, 0.0f, 0.0f);//sirve para el color de los pixeles
ddaDibujar(x1, y1, x2, y2);
}
Finalmente escribimos el método que contiene el algoritmo para dibujar la línea DDA en este caso el nombre del método es ddaDibujar() y el código es el siguiente:
public static void ddaDibujar(double x1, double y1, double x2, double y2)
{
double xinicial = x1, yinicial = y1, xfinal = x2, yfinal = y2, x, y;
double deltax, deltay, xincremento, yincremento;
double pasos;
deltax = xfinal - xinicial;
deltay = yfinal - yinicial;
if (Math.Abs(deltax) > Math.Abs(deltay))
pasos = Math.Abs(deltax);
else
pasos = Math.Abs(deltay);
xincremento = (deltax / pasos) / 25;//10;
yincremento = (deltay / pasos) / 25;// 10;
x = xinicial;
y = yinicial;
Gl.glBegin(Gl.GL_POINTS);
Gl.glVertex2d(x, y);//funcion que pinta un pixel en las coordenadas especificadas
for (double k = .1; k <= pasos; k += .1)
{
x = (x + xincremento);
y = (y + yincremento);
Gl.glVertex2d(x, y);
}
Gl.glEnd();
//termina dda
}
Y eso es todo amigos, si instalaron bien el taoframework y agregaron bien las referencias de las librerías a la aplicación no deberían de tener problemas ya que el resto fue bastante sencillo ahora compilamos y corremos nuestra aplicación y nos saldrá una ventana de consola pidiendo los valores de x1, y1, x2 y y2, que serán las coordenadas iniciales y finales de la línea a dibujar:
Podemos teclear los valore que nosotros deseemos, tanto valores negativos como valores positivos ya que tenemos representados los 4 cuadrantes. En mi caso a manera de ejemplo colocaré las coordenadas de: 0, 0, 1, 1. La línea que me saldrá a mi estará representada en el primer cuadrante debido a que estoy utilizando solo valores positivos, aquí lo tenemos:
Y bien amigos pues eso es todo por esta ocasión, los espero en la próxima para ver más figuras que podemos graficar y las diferentes maneras que tenemos para hacerlo. La próxima semana regresaremos a realizar aplicaciones en C++ Builder que ha sido nuestra principal herramienta de programación a lo largo de este semestre. Hasta la próxima amigos!.
miércoles, 11 de abril de 2012
martes, 10 de abril de 2012
Linea DDA en C#
Hola una vez más amigos, me alegro de poder saludarlos de nueva cuenta y hay que seguir con más aplicaciones de programación, pero esta vez no serán en C++ Builder, sino que la aplicación de hoy la programaremos en C#. La aplicación que vamos a realizar será la misma que hicimos la vez pasada del algoritmo DDA para dibujar líneas solo que ahora estará en C#.

Bien pues empezamos, lo primero será colocar los siguientes componentes en la Forma:
-1 pictureBox
-1 panel
Dentro del panel colocamos los siguientes componentes:
-6 label
-4 textBox
-5 button
Además también necesitaremos:
-1 colorDialog
-3 timer
Los componentes pueden acomodarlos de la manera como ustedes gusten como siempre, en mi caso yo los acomode de la siguiente manera:
Ahora para nuestra aplicación también necesitaremos crear nuestra propia clase. Para esto nos vamos al menú "Proyecto" y luego "Agregar clase..." y le damos el nombre de "Graficos".
Luego necesitaremos agregar un "using" para poder utilizar las clases de los componentes que colocamos sobre la Forma, la siguiente línea la agregamos al final de los "using" ya por default:
using System.Windows.Forms;
Bien ahora si comenzamos con la codificación del método para dibujar la linea DDA, al igual que la aplicación realizada en C++ Builder, nuestro método tendrá 2 sobrecargas, una para dibujar la línea normal y la otra para dibujarla con el color que deseemos. A diferencia de C++ Builder, aquí además de los 4 parámetros que necesitamos, agregaremos un parámetro más, el cual será el pictureBox donde estamos graficando. Enseguida tenemos el código de nuestro primer método LineaDDA():
public void lineaDDA(int x1, int y1, int x2, int y2, PictureBox p1)
{
int dx, dy, pasos, k;
float x_inc, y_inc, x, y;
dx = x2 - x1;
dy = y2 - y1;
if (Math.Abs(dx) > Math.Abs(dy))
pasos = Math.Abs(dx);
else
pasos = Math.Abs(dy);
x_inc = (float)dx / pasos;
y_inc = (float)dy / pasos;
x = x1;
y = y1;
Bitmap bmp = new Bitmap(p1.ClientSize.Width, p1.ClientSize.Height);
bmp.SetPixel((int)x, (int)y, Color.Gray);
for (k = 1; k < pasos + 1; k++)
{
x = x + x_inc;
y = y + y_inc;
bmp.SetPixel((int)x, (int)y, Color.Gray);
}
Graphics g = p1.CreateGraphics();
g.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
}
Ahora codificamos la segunda sobrecarga del método, con el parámetro del color:
public void lineaDDA(int x1, int y1, int x2, int y2, PictureBox p1, Color color)
{
int dx, dy, pasos, k;
float x_inc, y_inc, x, y;
dx = x2 - x1;
dy = y2 - y1;
if (Math.Abs(dx) > Math.Abs(dy))
pasos = Math.Abs(dx);
else
pasos = Math.Abs(dy);
x_inc = (float)dx / pasos;
y_inc = (float)dy / pasos;
x = x1;
y = y1;
Bitmap bmp = new Bitmap(p1.ClientSize.Width, p1.ClientSize.Height);
bmp.SetPixel((int)x, (int)y, Color.Red);
for (k = 1; k < pasos + 1; k++)
{
x = x + x_inc;
y = y + y_inc;
bmp.SetPixel((int)x, (int)y, color);
}
Graphics g = p1.CreateGraphics();
g.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
}
Ahora nos vamos al código de nuestro Form1.cs. Ahí declarmos las siguientes variables y objetos de manera global:
Graficos g = new Graficos();
int x1, y1, x2, y2, lenght=80;
Color color = Color.Black;
bool cono=false, circ=false, pol=false;
Ahora abrimos el primer botón, el cual en mi caso es el botón que nos servirá para cambiar el color de la línea. En ese botón escribimos el siguiente código:
private void button1_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
color = colorDialog1.Color;
}
Ahora damos clic en el button2, el cual será el que trazará la línea con las coordenadas dadas en los textBox, el código lo tenemos a continuación:
private void button2_Click(object sender, EventArgs e)
{
this.Refresh();
x1 = Convert.ToInt16(textBox1.Text);
y1 = Convert.ToInt16(textBox2.Text);
x2 = Convert.ToInt16(textBox3.Text);
y2 = Convert.ToInt16(textBox4.Text);
g.lineaDDA(x1, y1, x2, y2, pictureBox1, color);
}
En nuestra aplicación también tendremos varios efectos generados con líneas, el primer botón habilitará el primer efecto es caso de estar inhabilitado y lo inhabilitará en caso de que esté habilitado:
private void button3_Click(object sender, EventArgs e)
{
if (cono == false)
{
cono = true;
timer1.Enabled = true;
}
else
{
cono = false;
timer1.Enabled = false;
}
}
El siguiente botón hace exactamente lo mismo que el anterior solo que con el segundo efecto que generaremos:
private void button4_Click(object sender, EventArgs e)
{
if (circ == false)
{
circ = true;
timer2.Enabled = true;
}
else
{
circ = false;
timer2.Enabled = false;
}
}
Ahora hacemos doble clic en el último botón el cual hará lo mismo que los 2 anteriores solo que con el último efecto que vamos a generar:
private void button5_Click(object sender, EventArgs e)
{
if (pol == false)
{
pol = true;
timer3.Enabled = true;
}
else
{
pol = false;
timer3.Enabled = false;
}
}
Cada uno de los efectos estará dentro de un timer. Vamos a codificar el primero, el cual generará el efecto de que se está dibujando un cono con líneas de diferentes colores:
private void timer1_Tick(object sender, EventArgs e)
{
int centro_x = 150;
int centro_y = 150;
Graphics gr = pictureBox1.CreateGraphics();
float pos_x, pos_y;
int angle;
Random ran = new Random();
Pen pluma;
for (angle = 0; angle < 360 * 10; angle++)
{
pos_x = (float)(centro_x + lenght * Math.Sin(angle / (180 * Math.PI)));
pos_y = (float)(centro_y + lenght * Math.Cos(angle / (180 * Math.PI)));
pluma = new Pen(Color.FromArgb(ran.Next(256), ran.Next(256), ran.Next(256)));
gr.DrawLine(pluma, centro_x, centro_y, pos_x+80, pos_y+180);
}
Thread.Sleep(100);
}
Ahora vamos a codificar el efecto que estará en el segundo timer. Este efecto dibujará un circulo con líneas de diferentes colores:
private void timer2_Tick(object sender, EventArgs e)
{
int centro_x = 150;
int centro_y = 150;
Graphics gr = pictureBox1.CreateGraphics();
float pos_x, pos_y;
int angle;
Random ran = new Random();
Pen pluma;
for (angle = 0; angle < 360*10; angle++)
{
pos_x = (float)(centro_x + lenght * Math.Sin(angle / (180 * Math.PI)));
pos_y = (float)(centro_y + lenght * Math.Cos(angle / (180 * Math.PI)));
pluma = new Pen(Color.FromArgb(ran.Next(256), ran.Next(256), ran.Next(256)));
gr.DrawLine(pluma, centro_x, centro_y, pos_x, pos_y);
}
}
Finalmente codificamos el último de nuestros efectos, el cuál dibujará un cuadrado que gira sobre una de sus esquinas dibujando un par de círculos concéntricos, el código lo tenemos a continuación:
private void timer3_Tick(object sender, EventArgs e)
{
int centro_x = pictureBox1.Width / 2;
int centro_y = pictureBox1.Height / 2;
lenght = 90;
int angle;
float pos_x, pos_y, pos_x2, pos_y2, pos_x3, pos_y3;
double hypot = Math.Sqrt(lenght * lenght + lenght * lenght);
Random ran = new Random();
for (angle = 0; angle < 360; angle++)
{
color = Color.FromArgb(ran.Next(255), ran.Next(255), ran.Next(255));
pos_y = (float)(centro_y + lenght * Math.Sin(angle / 180.0 * Math.PI));
pos_x = (float)(centro_x + lenght * Math.Cos(angle / 180.0 * Math.PI));
pos_y2 = (float)(centro_y + hypot * Math.Sin((angle + 45) / 180.0 * Math.PI));
pos_x2 = (float)(centro_x + hypot * Math.Cos((angle + 45) / 180.0 * Math.PI));
g.lineaDDA((int)pos_x, (int)pos_y, (int)pos_x2, (int)pos_y2, pictureBox1, color);
pos_y3 = (float)(centro_y + lenght * Math.Sin((angle + 90) / 180.0 * Math.PI));
pos_x3 = (float)(centro_x + lenght * Math.Cos((angle + 90) / 180.0 * Math.PI));
g.lineaDDA((int)pos_x2, (int)pos_y2, (int)pos_x3, (int)pos_y3, pictureBox1, color);
g.lineaDDA((int)pos_x3, (int)pos_y3, (int)centro_x, (int)centro_y, pictureBox1, color);
}
Thread.Sleep(1);
}
Bien ahora solo compilamos y corremos nuestra aplicación y vemos los diferentes resultados que tenemos. Deben ser como los siguientes:

Bien amigos eso es todo por el día de hoy. Espero que hayan comprendido bien el funcionamiento de nuestro programa en C# que prácticamente son muy pocas las diferencias entre éste y el programa que hicimos en C++ Builder y que ambos realizan lo mismo. Nos vemos en la próxima para continuar con más aplicaciones y aprendiendo un poco más de graficación, ya sea en C++ Builder o en C#. Hasta pronto amigos!.
lunes, 9 de abril de 2012
Linea DDA
Hola amigos espero que estén de lo mejor y me alegro de saludarlos de nuevo y de que me acompañen a realizar más aplicaciones en C++ Builder. En esta ocasión vamos a comenzar con el trazo de líneas mediante el algoritmo conocido como DDA (Analizador Diferencial Digital).
Antes de codificar este algoritmo vamos a explicar un poco de como funciona. Lo que hace el algoritmo de la línea DDA es ir calculando las posiciones de cada uno de los pixeles a lo largo de una línea. Esta tarea la lleva a cabo realizando pasos o incrementos unitarios en una de las coordenadas, y realizando los cálculos necesarios para encontrar el valor de la otra coordenada. Básicamente ese es el funcionamiento del algoritmo.
Bien pues comenzamos con nuestra aplicación para dibujar nuestra línea DDA. Ésta aplicación tendrá bastantes componentes dentro de la Forma, dichos componentes los tenemos en la siguiente lista:
-1 PaintBox
-1 ColorDialog
-7 Timer (todos tienen que estar con su propiedad Enabled en false)
-1 Panel
Dentro del Panel tenemos los siguientes componentes:
-1 Label
-1 ComboBox, y en su propiedad Items agregamos las siguientes cadenas:
-Cono
-Círculo
-Polígono
-Efecto Propio 1
-Efecto Propio 3
-Efecto Propio 4
-3 Button
-1GroupBox
Dentro del GroupBox tendremos los siguientes componentes:
-5 Label
-4 Edit
-1 SpeedButton (podemos crear nuestro propio Bitmap para agregarlo a su propiedad Glyph, lo hacemos desde el Image Editor accesible desde el menú Tools de C++ Builder)
Y por la parte visual de nuestra aplicación eso sería todo. Los componentes pueden acomodarlos de la manera que ustedes gusten, en mi caso yo lo hice de la siguiente manera:
Ahora vamos con la parte del código. Nuestra línea DDA la dibujaremos desde una clase que vamos a crear nosotros mismos. Para hacer esto abrimos el menú "File", después la primera opción "New" y seleccionamos "Unit". A nuestra nueva clase la llamaremos "Graficos".
Para crear nuestra clase gráficos primero nos vamos al archivo H de la nueva unidad que creamos, y definimos el constructor el cual recibirá el Canvas del componente donde estemos dibujando y lo asignará al de la clase Graficos para con el dibujar la línea DDA, además también definiremos el método LineaDDA(), el cual tendrá 2 sobrecargas, la primera para dibujar la línea normalmente y la segunda para dibujar la línea con un color que hayamos elegido. El código del archivo H de nuestra clase Graficos lo tenemos a continuación:
class Graficos
{
TCanvas *canvas;
public:
Graficos(TCanvas *CanvaS)
{
canvas = CanvaS;
}
int round(float n);
void LineaDDA(int x1, int y1, int x2, int y2);
void LineaDDA(int x1, int y1, int x2, int y2, TColor color);
};
Debemos cuidar que el código anterior lo hayamos escrito antes de la línea:
#endif
Ahora en el archivo .cpp, en la parte superior escribimos la línea de código para incluir la clase Math en nuestra aplicación ya que la utilizaremos más adelante:
#include <Math.h>
Ahora debajo de la línea de código:
#pragma package(smart_init)
comenzamos a escribir nuestros métodos para la línea DDA.
Primero escribiremos un método propio para redondear los números que deseemos. El código es bastante sencillo y lo tenemos a continuación:
int Graficos::round(float n)
{
return int(n+0.5);
}
//-----------------------------------------------------------------------------
Ahora codificamos el método para dibujar nuestra línea DDA los parámetros que necesitamos son las coordenadas iniciales de la línea y las coordenadas finales. El código para dibujar la línea DDA es el siguiente:
void Graficos::LineaDDA(int x1, int y1, int x2, int y2)
{
int dx, dy, steps, k;
float x_inc, y_inc, x, y;
dx = x2 - x1;
dy = y2 - y1;
if (abs(dx) > abs(dy))
steps = abs(dx);
else
steps = abs(dy);
x_inc = (float)dx/steps;
y_inc = (float)dy/steps;
x = x1;
y = y1;
canvas->Pixels[floor(x+0.5)][floor(y+0.5)];
for (k = 1; k < steps+1; k++)
{
x = x + x_inc;
y = y + y_inc;
canvas->Pixels[floor(x+0.5)][floor(y+0.5)];
}
}
//-------------------------------------------------------------------------------
Ahora escribimos la segunda sobrecarga del método LineaDDA(), en la cual incluimos el color personalizado de la línea, el código es prácticamente el mismo:
void Graficos::LineaDDA(int x1, int y1, int x2, int y2, TColor color)
{
int dx, dy, steps, k;
float x_inc, y_inc, x, y;
dx = x2 - x1;
dy = y2 - y1;
if (abs(dx) > abs(dy))
steps = abs(dx);
else
steps = abs(dy);
x_inc = (float)dx/steps;
y_inc = (float)dy/steps;
x = x1;
y = y1;
canvas->Pixels[floor(x+0.5)][floor(y+0.5)] = color;
for (k = 1; k < steps+1; k++)
{
x = x + x_inc;
y = y + y_inc;
canvas->Pixels[floor(x+0.5)][floor(y+0.5)] = color;
}
}
//-------------------------------------------------------------------------------
Y con eso tenemos lista nuestra clase Graficos desde la cual podremos dibujar nuestra Linea DDA.
Ahora nos vamos al archivo .cpp de nuestra aplicación y ahí declaramos de manera global las siguientes variables, las cuales son 4 enteros que serán las coordenadas iniciales y finales de la línea en el momento de dibujarla de manera dinámica con el mouse, y un puntero de la clase Graficos para poder llamar los métodos LineaDDA():
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graficos *graf;
int x1, y1, x2, y2;
//---------------------------------------------------------------------------
Ahora en el evento en el que llamamos a la creación de nuestra Forma colocamos el siguiente código para inicializar los valores y crear el objeto "graf":
_fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
graf = new Graficos(PaintBox1->Canvas);
ComboBox1->ItemIndex = 0;
}
//---------------------------------------------------------------------------
Bien ahora abrimos el evento OnMouseDown del PaintBox que habíamos colocado en la Forma y en el evento escribimos el siguiente código:
void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if (Shift.Contains(ssLeft))
{
x1 = X;
y1 = Y;
}
}
//---------------------------------------------------------------------------
Ahora abrimos el evento OnMouseMove también del PaintBox y escribimos el código siguiente:
void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if(Shift.Contains(ssLeft))
PaintBox1MouseUp(Sender, mbLeft, Shift, X, Y);
}
//---------------------------------------------------------------------------
Y finalmente abrimos el evento OnMouseUp del PaintBox y tecleamos el código que tenemos a continuación:
void __fastcall TForm1::PaintBox1MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button==mbLeft)
{
x2 = X;
y2 = Y;
Refresh();
graf->LineaDDA(x1, y1, x2, y2, Canvas->Pen->Color);
Edit1->Text = x1;
Edit2->Text = y1;
Edit3->Text = x2;
Edit4->Text = y2;
}
}
//---------------------------------------------------------------------------
Ahora comenzamos con la codificación de los componentes primero hacemos doble clic en el SpeedButton y escribimos el siguiente código:
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
if (ColorDialog1->Execute())
Canvas->Pen->Color = ColorDialog1->Color;
}
//---------------------------------------------------------------------------
Ahora damos doble clic en el Button1 y escribimos el siguiente código:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
PaintBox1->Refresh();
graf->LineaDDA(Edit1->Text.ToInt(), Edit2->Text.ToInt(), Edit3->Text.ToInt(), Edit4->Text.ToInt(), Canvas->Pen->Color);
}
//---------------------------------------------------------------------------
Ahora damos clic en el Button2 el cual iniciará unos efectos que vamos a formar con las líneas que vayamos dibujando, dependiendo de cual de los efectos hayamos elegido en el ComboBox1:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
switch(ComboBox2->ItemIndex)
{
case 0:
Timer1->Enabled = true;
break;
case 1:
Timer2->Enabled = true;
break;
case 2:
Timer3->Enabled = true;
break;
case 3:
Timer4->Enabled = true;
break;
case 4:
Timer5->Enabled = true;
break;
case 5:
Timer6->Enabled = true;
break;
case 6:
Timer7->Enabled = true;
break;
}
}
//---------------------------------------------------------------------------
Después damos doble clic en el Button3 el cual detendrá el efecto con líneas que este seleccionado en el ComboBox1:
void __fastcall TForm1::Button3Click(TObject *Sender)
{
switch(ComboBox2->ItemIndex)
{
case 0:
Timer1->Enabled = false;
break;
case 1:
Timer2->Enabled = false;
break;
case 2:
Timer3->Enabled = false;
break;
case 3:
Timer4->Enabled = false;
break;
case 4:
Timer5->Enabled = false;
break;
case 5:
Timer6->Enabled = false;
break;
case 6:
Timer7->Enabled = false;
break;
}
}
//---------------------------------------------------------------------------
Ahora vamos a codificar los efectos que se irán formando cada efecto estará dentro de un Timer. El primero de nuestros efectos formará un cono dibujando líneas que generen ese efecto, el código es el siguiente:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
int angle;
TColor color;
float x_pos, y_pos;
int x_center = PaintBox1->ClientWidth/4;
int y_center = PaintBox1->ClientHeight/4;
int length = 80;
for (angle=0; angle<360; angle++)
{
color = (TColor)random(52548899);
y_pos = y_center+length*sin(angle/180.0*M_PI);
x_pos = x_center+length*cos(angle/180.0*M_PI);
graf->LineaDDA(x_center, y_center, x_pos+80, y_pos+180, color);
}
}
//---------------------------------------------------------------------------
El segundo efecto formará un circulo dibujando líneas, el código lo tenemos a continuación:
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
int angle;
TColor color;
float x_pos, y_pos;
int x_center = PaintBox1->ClientWidth/4;
int y_center = PaintBox1->ClientHeight/4;
int length = 80;
for (angle=0; angle<360; angle++)
{
color = (TColor)random(52548899);
y_pos = y_center+length*sin(angle/180.0*M_PI);
x_pos = x_center+length*cos(angle/180.0*M_PI);
graf->LineaDDA(x_center, y_center, x_pos, y_pos, color);
}
}
//---------------------------------------------------------------------------
El tercero de los efecto es un cuadrado dibujado por líneas que girará y formara el efecto de 2 círculos circuncéntricos:
void __fastcall TForm1::Timer3Timer(TObject *Sender)
{
float x_pos, y_pos, x_pos2, y_pos2, x_pos3, y_pos3;
int x_center = PaintBox1->ClientWidth/2;
int y_center = PaintBox1->ClientHeight/2;
int length = 120;
int angle;
TColor color;
double hypot = sqrt(length * length + length * length);
for (angle = 0; angle < 360; angle++)
{
color = (TColor)random(52548899);
y_pos = (float)(y_center + length * sin(angle / 180.0 * M_PI));
x_pos = (float)(x_center + length * cos(angle / 180.0 * M_PI));
y_pos2 = (float)(y_center + hypot * sin((angle + 45) / 180.0 * M_PI));
x_pos2 = (float)(x_center + hypot * cos((angle + 45) / 180.0 * M_PI));
graf->LineaDDA(x_pos, y_pos, x_pos2, y_pos2, color);
y_pos3 = (float)(y_center + length * sin((angle + 90) / 180.0 * M_PI));
x_pos3 = (float)(x_center + length * cos((angle + 90) / 180.0 * M_PI));
graf->LineaDDA(x_pos2, y_pos2, x_pos3, y_pos3, color);
graf->LineaDDA(x_pos3, y_pos3, x_center, y_center, color);
Sleep(10);
}
}
//---------------------------------------------------------------------------
El efecto siguiente dará la impresión de estar dibujando un diamante mediante líneas:
void __fastcall TForm1::Timer4Timer(TObject *Sender)
{
int angle;
TColor color;
float x_pos, y_pos;
int x_center = PaintBox1->ClientWidth/4;
int y_center = PaintBox1->ClientHeight/4;
int length = 80;
for (angle=0; angle<360; angle++)
{
color = (TColor)random(52548899);
y_pos = y_center+length*sin(angle/180.0*M_PI)*3;
x_pos = x_center+length*cos(angle/180.0*M_PI*10);
graf->LineaDDA(x_pos+130, x_center+130, y_center+130, y_pos+130, color);//(x_center, y_center, x_pos, y_pos, color);
}
}
//---------------------------------------------------------------------------
El siguiente efecto son líneas que se van dibujando desde el centro hacia las esquinas para terminar dibujando un cuadrado con un círculo inscrito dentro:
void __fastcall TForm1::Timer5Timer(TObject *Sender)
{
Refresh();
int i,x,posx,posy;
float y;
posx=PaintBox1->ClientWidth-48;
posy=PaintBox1->ClientHeight-48;
TColor color;
for(i=0,x=posx,y=posy-200;i<21;x-=15,y+=10,i++)
{
color = (TColor)random(52548899);
graf->LineaDDA(x,posy,posx,y, color);
Sleep(10);
}
posx=44;
posy=PaintBox1->ClientHeight-48;
for(i=0,x=posx,y=posy-200;i<21;x+=15,y+=10,i++)
{
color = (TColor)random(52548899);
graf->LineaDDA(x,posy,posx,y,color);
Sleep(10);
}
posx=44;
posy=44;
for(i=0,x=posx,y=posy+200;i<21;x+=15,y-=10,i++)
{
color = (TColor)random(52548899);
graf->LineaDDA(x,posx,posy,y,color);
Sleep(10);
}
posx=PaintBox1->ClientWidth-48;
posy=44;
for(i=0,x=posx,y=posy+200;i<21;x-=15,y-=10,i++)
{
color = (TColor)random(52548899);
graf->LineaDDA(x,posy,posx,y,color);
Sleep(10);
}
}
//---------------------------------------------------------------------------
El penúltimo de los efectos dibujará líneas verticales y horizontales para que quede finalmente una cuadrícula:
void __fastcall TForm1::Timer6Timer(TObject *Sender)
{
Refresh();
TColor color;
color = (TColor)random(52548899);
for(int x = 0; x < Width; x += 20)
{
graf->LineaDDA(x, 0, x, Height, color);
Sleep(10);
}
for(int y = 0; y < Height; y += 20)
{
graf->LineaDDA(0, y, Width, y, color);
Sleep(10);
}
}
//---------------------------------------------------------------------------
El último de los efectos dibujará dos 2 círculos a la vez para terminar formando un efecto de un ovalo al centro rodeado de líneas a su alrededor:
void __fastcall TForm1::Timer7Timer(TObject *Sender)
{
float x_pos, y_pos, x_pos2, y_pos2, x_pos3, y_pos3;
int x_center = PaintBox1->ClientWidth/2-50;
int y_center = PaintBox1->ClientHeight/2;
int length = 120;
int angle;
TColor color;
double hypot = sqrt(length * length + length * length);
for (angle = 0; angle < 360; angle++)
{
color = (TColor)random(52548899);
y_pos = (float)(y_center + length * sin(angle / 180.0 * M_PI));
x_pos = (float)(x_center + length * cos(angle / 180.0 * M_PI));
y_pos2 = (float)(y_center + hypot * sin((angle + 45) / 180.0 * M_PI));
x_pos2 = (float)(x_center + hypot * cos((angle + 45) / 180.0 * M_PI));
graf->LineaDDA(x_pos+100, y_pos, x_pos2, y_pos2, color);
y_pos3 = (float)(y_center + length * sin((angle + 90) / 180.0 * M_PI));
x_pos3 = (float)(x_center + length * cos((angle + 90) / 180.0 * M_PI));
graf->LineaDDA(x_pos2+100, y_pos2, x_pos3, y_pos3, color);
Sleep(10);
}
}
//---------------------------------------------------------------------------
Y con eso terminamos amigos, este programa estuvo un poco largo y medio complicado pero finalmente lo terminamos. Ahora solo compilamos y corremos nuestra aplicación y podemos dibujar la línea dando clic y arrastrando el mouse. Y podemos dar clic al botón "Iniciar" para comenzar a ver nuestros efectos, nuestra aplicación debería verse de la siguiente manera:


Y bien amigos pues eso es todo por esta ocasión espero que hayan comprendido muy bien la aplicación del día de hoy ya que con ella continuaremos trabajando para realizar aplicaciones mas adelante. Por lo pronto me despido de ustedes y los espero en la próxima ocasión para continuar practicando. Hasta la vista chavos!.
domingo, 8 de abril de 2012
Fractal De Landscape
Que onda chavos pues aquí nos encontramos de nueva cuenta para finalizar con este tema de los fractales, y como les había comentado en la ocasión pasada el fractal que nos falta es un fractal que genera un paisaje, dicho paisaje consta de montañas, el mar y el sol. Este fractal que vamos a programar se le conoce como escena fractal o fractal de Landscape.
Bien pues comenzamos ya con el final de este tema. Para empezar lo primero que haremos será cambiar el color de la Forma ya que dependiendo del color que le pongamos a la Forma es el color que van a tener las montañas de nuestra escena fractal, ustedes pueden elegir el color que mas les guste o que mas se acople al paisaje, yo en mi caso elegí el color gris para la Forma. Después todo lo que necesitamos es colocar un Timer sobre la Forma y terminamos con la parte gráfica, nuestra Forma debe de haber quedado de la siguiente manera:
Bueno ahora continuamos con la parte del código. Primero nos vamos al archivo H y en la parte de declaraciones privadas escribimos las siguientes variables:
private: // User declarations
int MAXSIZE,MAXLEVEL;
double frctl[1000];
int cw,ch,x1;
Ahora en la parte de declaraciones públicas escribimos las siguientes definiciones de los métodos que utilizaremos más adelante:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::subdivide(int f1, int f2, double std, double ratio);
void TForm1::fractal(int y1, int y2, int maxlevel, double h, double scale);
void TForm1::draw_fractal(void);
Ahora nos regresamos a la Forma y abrimos el evento OnCreate de nuestra Forma y en él escribimos el siguiente código para darle valor a las variables apenas corra nuestra aplicación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
x1=10;
MAXSIZE=1000;
MAXLEVEL=6;
cw=ClientWidth-10;
ch=ClientHeight-10;
this->DoubleBuffered = true;
}
//---------------------------------------------------------------------------
También escribimos en la línea final del código pasado la asignación de la propiedad DoubleBuffered en true, para con esto reducir el parpadeo que se genera al momento de repintar o refrescar la Forma.
Ahora vamos a codificar los métodos que utilizaremos para generar el fractal, el primero que codificaremos será el método llamado fractal():
void TForm1::fractal(int y1,int y2,int maxlevel,double h,double scale)
{
int first, last;
double ratio,std;
first=0;
last=(int)pow(2.0,(double)maxlevel);
frctl[first]=y1;
frctl[last]=y2;
ratio=1.0/pow(2.0,h);
std=scale*ratio;
subdivide(first,last,std,ratio);
}
//--------------------------------------------------------------------------------
Continuamos codificando los métodos ahora le toca el turno al método conocido como subdivide(), el código lo tenemos a continuación:
void TForm1::subdivide(int p1,int p2,double std,double ratio)
{
int midpnt;
double stdmid;
midpnt = (p1 + p2) / 2;
if(midpnt != p1 && midpnt != p2)
{
frctl[midpnt] = (frctl[p1] + frctl[p2]) / 2 + (double)((random(16)-8)) /8.0*std;
stdmid = std * ratio;
subdivide(p1,midpnt,stdmid,ratio);
subdivide(midpnt,p2,stdmid,ratio);
}
}
//-------------------------------------------------------------------------------
Para terminar de codificar los 3 métodos que vamos a utilizar codificamos el último de los métodos el cual lo hemos llamado draw_fractal():
void TForm1::draw_fractal()
{
int i,x,xinc,l;
l=(int)pow(2.0,(double)MAXLEVEL);
xinc = cw / l * 3 / 2;
this->Canvas->MoveTo(0,100);
for(i=0,x=0;i<l;i++,x+=xinc)
this->Canvas->LineTo(x,(int)frctl[i]);
}
//---------------------------------------------------------------------------------
Y con eso terminamos la parte de codificación de los métodos ya solo nos resta teclear el código que irá dentro del Timer y que es el que irá generando el efecto. En el código del Timer hemos agregado una variable x1 que se irá incrementando cada vez que se vuelva a ejecutar el Timer y así dar el efecto de que el sol está en movimiento. Además también hacemos uso de la función FloodFill(), la cual nos sirve para rellenar un área especifica que tenga un color, con otro color que nosotros hayamos especificado. Los parámetros de esta función consta de un par de coordenadas que estén dentro del área que deseamos colorear, el color que tiene el área que deseamos colorear, y el parámetro fsSurface que pintará el área completamente hasta encontrar otro color (si desean conocer más sobre esta función pueden colocar el cursor sobre la palabra FloodFill y oprimir la tecla F1 y se abrirá el menú de ayuda y ahí podrán leer más sobre el funcionamiento de ésta función). El código del Timer1 lo tenemos a continuación:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
x1++;
this->Repaint();
randomize();
this->Canvas->Pen->Color=clBlack;
this->Canvas->Brush->Color=clSkyBlue;
fractal(100,100,MAXLEVEL,0.5,50.0);
draw_fractal();
this->Canvas->FloodFill(1,1,this->Color,fsSurface);
this->Canvas->Brush->Color=clTeal;
fractal(170,170,MAXLEVEL,0.9,30.0);
draw_fractal();
this->Canvas->FloodFill(1,ch-1,this->Color,fsSurface);
this->Canvas->Brush->Color=clYellow;
this->Canvas->Ellipse(10+x1,10,80+x1,80);
this->Canvas->FloodFill(cw,50,this->Color,fsSurface);
}
//---------------------------------------------------------------------------
Y pues eso es todo chavos ya solo queda compilar y ejecutar nuestra aplicación y automáticamente comenzará a generar el efecto debido a que el código lo escribimos en un Timer. El efecto de nuestra escena fractal debería de ser como lo que tenemos a continuación:
Y con este último fractal podemos dar por terminado este tema de los fractales. Si quieren pueden seguir buscando y en internet encontrarán muchísimos ejemplos más sobre fractales y si quieren seguir practicando pues pueden programarlos en C++ Builder. Bien pues gracias por haberme acompañado y nos vemos en la próxima ocasión para seguir realizando más aplicaciones de C++ pero ahora con un tema diferente. Hasta pronto amigos!.
Bien pues comenzamos ya con el final de este tema. Para empezar lo primero que haremos será cambiar el color de la Forma ya que dependiendo del color que le pongamos a la Forma es el color que van a tener las montañas de nuestra escena fractal, ustedes pueden elegir el color que mas les guste o que mas se acople al paisaje, yo en mi caso elegí el color gris para la Forma. Después todo lo que necesitamos es colocar un Timer sobre la Forma y terminamos con la parte gráfica, nuestra Forma debe de haber quedado de la siguiente manera:
Bueno ahora continuamos con la parte del código. Primero nos vamos al archivo H y en la parte de declaraciones privadas escribimos las siguientes variables:
private: // User declarations
int MAXSIZE,MAXLEVEL;
double frctl[1000];
int cw,ch,x1;
Ahora en la parte de declaraciones públicas escribimos las siguientes definiciones de los métodos que utilizaremos más adelante:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::subdivide(int f1, int f2, double std, double ratio);
void TForm1::fractal(int y1, int y2, int maxlevel, double h, double scale);
void TForm1::draw_fractal(void);
Ahora nos regresamos a la Forma y abrimos el evento OnCreate de nuestra Forma y en él escribimos el siguiente código para darle valor a las variables apenas corra nuestra aplicación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
x1=10;
MAXSIZE=1000;
MAXLEVEL=6;
cw=ClientWidth-10;
ch=ClientHeight-10;
this->DoubleBuffered = true;
}
//---------------------------------------------------------------------------
También escribimos en la línea final del código pasado la asignación de la propiedad DoubleBuffered en true, para con esto reducir el parpadeo que se genera al momento de repintar o refrescar la Forma.
Ahora vamos a codificar los métodos que utilizaremos para generar el fractal, el primero que codificaremos será el método llamado fractal():
void TForm1::fractal(int y1,int y2,int maxlevel,double h,double scale)
{
int first, last;
double ratio,std;
first=0;
last=(int)pow(2.0,(double)maxlevel);
frctl[first]=y1;
frctl[last]=y2;
ratio=1.0/pow(2.0,h);
std=scale*ratio;
subdivide(first,last,std,ratio);
}
//--------------------------------------------------------------------------------
Continuamos codificando los métodos ahora le toca el turno al método conocido como subdivide(), el código lo tenemos a continuación:
void TForm1::subdivide(int p1,int p2,double std,double ratio)
{
int midpnt;
double stdmid;
midpnt = (p1 + p2) / 2;
if(midpnt != p1 && midpnt != p2)
{
frctl[midpnt] = (frctl[p1] + frctl[p2]) / 2 + (double)((random(16)-8)) /8.0*std;
stdmid = std * ratio;
subdivide(p1,midpnt,stdmid,ratio);
subdivide(midpnt,p2,stdmid,ratio);
}
}
//-------------------------------------------------------------------------------
Para terminar de codificar los 3 métodos que vamos a utilizar codificamos el último de los métodos el cual lo hemos llamado draw_fractal():
void TForm1::draw_fractal()
{
int i,x,xinc,l;
l=(int)pow(2.0,(double)MAXLEVEL);
xinc = cw / l * 3 / 2;
this->Canvas->MoveTo(0,100);
for(i=0,x=0;i<l;i++,x+=xinc)
this->Canvas->LineTo(x,(int)frctl[i]);
}
//---------------------------------------------------------------------------------
Y con eso terminamos la parte de codificación de los métodos ya solo nos resta teclear el código que irá dentro del Timer y que es el que irá generando el efecto. En el código del Timer hemos agregado una variable x1 que se irá incrementando cada vez que se vuelva a ejecutar el Timer y así dar el efecto de que el sol está en movimiento. Además también hacemos uso de la función FloodFill(), la cual nos sirve para rellenar un área especifica que tenga un color, con otro color que nosotros hayamos especificado. Los parámetros de esta función consta de un par de coordenadas que estén dentro del área que deseamos colorear, el color que tiene el área que deseamos colorear, y el parámetro fsSurface que pintará el área completamente hasta encontrar otro color (si desean conocer más sobre esta función pueden colocar el cursor sobre la palabra FloodFill y oprimir la tecla F1 y se abrirá el menú de ayuda y ahí podrán leer más sobre el funcionamiento de ésta función). El código del Timer1 lo tenemos a continuación:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
x1++;
this->Repaint();
randomize();
this->Canvas->Pen->Color=clBlack;
this->Canvas->Brush->Color=clSkyBlue;
fractal(100,100,MAXLEVEL,0.5,50.0);
draw_fractal();
this->Canvas->FloodFill(1,1,this->Color,fsSurface);
this->Canvas->Brush->Color=clTeal;
fractal(170,170,MAXLEVEL,0.9,30.0);
draw_fractal();
this->Canvas->FloodFill(1,ch-1,this->Color,fsSurface);
this->Canvas->Brush->Color=clYellow;
this->Canvas->Ellipse(10+x1,10,80+x1,80);
this->Canvas->FloodFill(cw,50,this->Color,fsSurface);
}
//---------------------------------------------------------------------------
Y pues eso es todo chavos ya solo queda compilar y ejecutar nuestra aplicación y automáticamente comenzará a generar el efecto debido a que el código lo escribimos en un Timer. El efecto de nuestra escena fractal debería de ser como lo que tenemos a continuación:
Y con este último fractal podemos dar por terminado este tema de los fractales. Si quieren pueden seguir buscando y en internet encontrarán muchísimos ejemplos más sobre fractales y si quieren seguir practicando pues pueden programarlos en C++ Builder. Bien pues gracias por haberme acompañado y nos vemos en la próxima ocasión para seguir realizando más aplicaciones de C++ pero ahora con un tema diferente. Hasta pronto amigos!.
sábado, 7 de abril de 2012
Fractal De Sierpinski
Hola de nuevo amigos me da gusto saludarlos una vez mas y poder seguir practicando con mas aplicaciones en C++ Builder. Bueno ya casi hemos terminado con el tema de los fractales, pero aun nos quedan un par de ejemplo mas para realizar. El fractal que programaremos el día de hoy es el conocido como fractal de Sierpinski.
Bien amigos pues el día de hoy lo haremos un poco más rápido de lo normal debido a que tengo un poco de prisa, entonces me saltaré la parte de cambiarle el color a la Forma y lo único que haré en ella será colocar un botón con la leyenda "Dibujar Sierpinski". Nuestra Forma queda de la siguiente manera:
Bien ahora pasamos a la parte de código y primero nos vamos al archivo H y en la parte de declaraciones privadas declaramos las siguientes variables que utilizaremos más adelante y la definición de los métodos que declararemos más adelante y que son los que nos darán el efecto del fractal:
private: // User declarations
int depth;
int w,h;
void subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3);
void drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3);
Ahora nos preparamos para generar el efecto del fractal de Sierpinski y primero que nada tenemos que abrir el evento OnCreate de la Forma y en él escribimos el código que tenemos a continuación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
depth=7;
this->ClientWidth=640;
this->ClientHeight=480;
w=this->ClientWidth;
h=this->ClientHeight;
}
//---------------------------------------------------------------------------
Bien enseguida vamos a codificar los métodos definidos anteriormente primero lo haremos con el método drawSierpinski(), el código de dicho método lo tenemos a continuación:
//Esta funcion dibujara solo 1 triangulo y entonces empezara la funcion de recursividad a si mismo
void TForm1::drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3)
{
//Aqui dibujamos las 3 lineas del triangulo, uniendo los 3 puntos para generar lineas
this->Canvas->Pen->Color=(TColor)random(65000);
this->Canvas->MoveTo(x1,y1);
this->Canvas->LineTo(x2,y2);
this->Canvas->MoveTo(x2,y2);
this->Canvas->LineTo(x3,y3);
this->Canvas->MoveTo(x3,y3);
this->Canvas->LineTo(x1,y1);
//Llamamos a la funcion de recursividad y pintara el resto de los tringulos, las 3 esquinas de triangulo son simempre el centro de su posicion
subTriangle
(
1, //Esto representa la primer recursicion
(x1 + x2) / 2, //coordenada x de la primera esquina
(y1 + y2) / 2, //coordenada y de la primera esquina
(x1 + x3) / 2, //coordenada x de la segunda esquina
(y1 + y3) / 2, //coordenada y de la segunda esquina
(x2 + x3) / 2, //coordenada x de la tercera esquina
(y2 + y3) / 2 //coordenada y de la tercera esquina
);
}
//-------------------------------------------------------------------------------
Ahora codificaremos el siguiente método el cual es llamado subTriangle(), el código se muestra enseguida:
//La funcion de recursividad subtriangulo pintara todo lo que esta dentro del tringulo mayor a este
void TForm1::subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3)
{
Sleep(10);
//Dibujamos los 3 lados del subtriangulo
this->Canvas->MoveTo(x1,y1);
this->Canvas->LineTo(x2,y2);
this->Canvas->MoveTo(x2,y2);
this->Canvas->LineTo(x3,y3);
this->Canvas->MoveTo(x3,y3);
this->Canvas->LineTo(x1,y1);
//Llamadas a si mismo 3 veces con nuevas esquinas,pero solo si el actual numero de recurrencias es menor que la profundidad maxima
if(n < depth)
{
//Triangulo mas pequeño #1
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x1 + x2) / 2 + (x2 - x3) / 2, //coordenada x de la primera esquina
(y1 + y2) / 2 + (y2 - y3) / 2, //coordenada y de la primera esquina
(x1 + x2) / 2 + (x1 - x3) / 2, //coordenada x de la segunda esquina
(y1 + y2) / 2 + (y1 - y3) / 2, //coordenada y de la segunda esquina
(x1 + x2) / 2, //coordendaa x de la tercera esquina
(y1 + y2) / 2 //coordenada y de la tercera esquina
);
//Triangulo mas pequeño #2
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x3 + x2) / 2 + (x2 - x1) / 2,
(y3 + y2) / 2 + (y2 - y1) / 2,
(x3 + x2) / 2 + (x3 - x1) / 2,
(y3 + y2) / 2 + (y3 - y1) / 2,
(x3 + x2) / 2,
(y3 + y2) / 2
);
//Triangulo mas pequeño #3
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x1 + x3) / 2 + (x3 - x2) / 2,
(y1 + y3) / 2 + (y3 - y2) / 2,
(x1 + x3) / 2 + (x1 - x2) / 2,
(y1 + y3) / 2 + (y1 - y2) / 2,
(x1 + x3) / 2,
(y1 + y3) / 2
);
}
}
//---------------------------------------------------------------------------------
El código de los 2 métodos anteriores es algo largo y relativamente un poco complicado sin embargo en el código se incluyen comentarios para ayudarnos a saber que hace cada parte del código y así comprender mejor el comportamiento de este fractal.
Ya para terminar solo nos resta escribir la llamada al método drawSierpinski() dentro del evento clic del Button1 (solo se hace la llamada el método drawSierpinski() ya que dentro de éste método se llama al segundo método que es el subTriangle()), el código lo tenemos enseguida:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
Sleep(1);
Button1->Enabled=false;
//Llamamos a la función de Sierpinski (funciona con cualquier esquina dentro de la pantalla)
//Asignamos las coordenadas del tringulo principal "el mas grande"
drawSierpinski(10, h - 10, w - 10, h - 10, w / 2, 10);
Button1->Enabled=true;
Button1->SetFocus();
}
//---------------------------------------------------------------------------
Bien chavos pues eso es todo lo que tenemos que hacer ahora solo compilamos y corremos nuestra aplicación y observamos el efecto que nos genera el cual es un poco tardado así que solo dejen el programa correr tranquilamente, dicho efecto debe ser como lo que tenemos enseguida:
Y bueno amigos eso fue todo por hoy, ya solo nos queda un fractal más para concluir con este tema, el fractal restante es el conocido como fractal de Landscape, y nos genera el efecto de un paisaje. Pero todo eso ya lo veremos en la siguiente ocasión. Hasta la próxima amigos!.
Bien amigos pues el día de hoy lo haremos un poco más rápido de lo normal debido a que tengo un poco de prisa, entonces me saltaré la parte de cambiarle el color a la Forma y lo único que haré en ella será colocar un botón con la leyenda "Dibujar Sierpinski". Nuestra Forma queda de la siguiente manera:
Bien ahora pasamos a la parte de código y primero nos vamos al archivo H y en la parte de declaraciones privadas declaramos las siguientes variables que utilizaremos más adelante y la definición de los métodos que declararemos más adelante y que son los que nos darán el efecto del fractal:
private: // User declarations
int depth;
int w,h;
void subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3);
void drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3);
Ahora nos preparamos para generar el efecto del fractal de Sierpinski y primero que nada tenemos que abrir el evento OnCreate de la Forma y en él escribimos el código que tenemos a continuación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
depth=7;
this->ClientWidth=640;
this->ClientHeight=480;
w=this->ClientWidth;
h=this->ClientHeight;
}
//---------------------------------------------------------------------------
Bien enseguida vamos a codificar los métodos definidos anteriormente primero lo haremos con el método drawSierpinski(), el código de dicho método lo tenemos a continuación:
//Esta funcion dibujara solo 1 triangulo y entonces empezara la funcion de recursividad a si mismo
void TForm1::drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3)
{
//Aqui dibujamos las 3 lineas del triangulo, uniendo los 3 puntos para generar lineas
this->Canvas->Pen->Color=(TColor)random(65000);
this->Canvas->MoveTo(x1,y1);
this->Canvas->LineTo(x2,y2);
this->Canvas->MoveTo(x2,y2);
this->Canvas->LineTo(x3,y3);
this->Canvas->MoveTo(x3,y3);
this->Canvas->LineTo(x1,y1);
//Llamamos a la funcion de recursividad y pintara el resto de los tringulos, las 3 esquinas de triangulo son simempre el centro de su posicion
subTriangle
(
1, //Esto representa la primer recursicion
(x1 + x2) / 2, //coordenada x de la primera esquina
(y1 + y2) / 2, //coordenada y de la primera esquina
(x1 + x3) / 2, //coordenada x de la segunda esquina
(y1 + y3) / 2, //coordenada y de la segunda esquina
(x2 + x3) / 2, //coordenada x de la tercera esquina
(y2 + y3) / 2 //coordenada y de la tercera esquina
);
}
//-------------------------------------------------------------------------------
Ahora codificaremos el siguiente método el cual es llamado subTriangle(), el código se muestra enseguida:
//La funcion de recursividad subtriangulo pintara todo lo que esta dentro del tringulo mayor a este
void TForm1::subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3)
{
Sleep(10);
//Dibujamos los 3 lados del subtriangulo
this->Canvas->MoveTo(x1,y1);
this->Canvas->LineTo(x2,y2);
this->Canvas->MoveTo(x2,y2);
this->Canvas->LineTo(x3,y3);
this->Canvas->MoveTo(x3,y3);
this->Canvas->LineTo(x1,y1);
//Llamadas a si mismo 3 veces con nuevas esquinas,pero solo si el actual numero de recurrencias es menor que la profundidad maxima
if(n < depth)
{
//Triangulo mas pequeño #1
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x1 + x2) / 2 + (x2 - x3) / 2, //coordenada x de la primera esquina
(y1 + y2) / 2 + (y2 - y3) / 2, //coordenada y de la primera esquina
(x1 + x2) / 2 + (x1 - x3) / 2, //coordenada x de la segunda esquina
(y1 + y2) / 2 + (y1 - y3) / 2, //coordenada y de la segunda esquina
(x1 + x2) / 2, //coordendaa x de la tercera esquina
(y1 + y2) / 2 //coordenada y de la tercera esquina
);
//Triangulo mas pequeño #2
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x3 + x2) / 2 + (x2 - x1) / 2,
(y3 + y2) / 2 + (y2 - y1) / 2,
(x3 + x2) / 2 + (x3 - x1) / 2,
(y3 + y2) / 2 + (y3 - y1) / 2,
(x3 + x2) / 2,
(y3 + y2) / 2
);
//Triangulo mas pequeño #3
subTriangle
(
n+1, //numero de recurrencias para la siguiente llamada con aumento de 1
(x1 + x3) / 2 + (x3 - x2) / 2,
(y1 + y3) / 2 + (y3 - y2) / 2,
(x1 + x3) / 2 + (x1 - x2) / 2,
(y1 + y3) / 2 + (y1 - y2) / 2,
(x1 + x3) / 2,
(y1 + y3) / 2
);
}
}
//---------------------------------------------------------------------------------
El código de los 2 métodos anteriores es algo largo y relativamente un poco complicado sin embargo en el código se incluyen comentarios para ayudarnos a saber que hace cada parte del código y así comprender mejor el comportamiento de este fractal.
Ya para terminar solo nos resta escribir la llamada al método drawSierpinski() dentro del evento clic del Button1 (solo se hace la llamada el método drawSierpinski() ya que dentro de éste método se llama al segundo método que es el subTriangle()), el código lo tenemos enseguida:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
Sleep(1);
Button1->Enabled=false;
//Llamamos a la función de Sierpinski (funciona con cualquier esquina dentro de la pantalla)
//Asignamos las coordenadas del tringulo principal "el mas grande"
drawSierpinski(10, h - 10, w - 10, h - 10, w / 2, 10);
Button1->Enabled=true;
Button1->SetFocus();
}
//---------------------------------------------------------------------------
Bien chavos pues eso es todo lo que tenemos que hacer ahora solo compilamos y corremos nuestra aplicación y observamos el efecto que nos genera el cual es un poco tardado así que solo dejen el programa correr tranquilamente, dicho efecto debe ser como lo que tenemos enseguida:
Y bueno amigos eso fue todo por hoy, ya solo nos queda un fractal más para concluir con este tema, el fractal restante es el conocido como fractal de Landscape, y nos genera el efecto de un paisaje. Pero todo eso ya lo veremos en la siguiente ocasión. Hasta la próxima amigos!.
viernes, 6 de abril de 2012
Fractal De Malthus 2
Que onda chavos me da gusto saludarlos de nuevo y en esta ocasión para continuar con el tema de los fractales, programaremos el fractal conocido como el fractal de Malthus 2, como ya se los había dicho en la vez pasada.
Bien pues rápidamente comencemos. Lo primero será como ya hemos estado acostumbrando hacer será cambiar el color de la Forma. Como ya les había mencionado en ocasiones pasadas esto es opcional, si quieren lo pueden hacer e incluso pueden elegir el color que ustedes deseen, en mi caso yo cambiaré el color de la Forma a color rojo. Inmediatamente después tenemos que colocar un botón sobre la Forma.
Nuestra interfaz debería verse mas o menos de la siguiente manera, dependiendo de lo que hayan elegido ustedes:
Ahora nos vamos a la parte del código la cual será bastante sencilla. Primero nos vamos al archivo H y en la parte de declaraciones privadas declaramos las siguientes variables:
private: // User declarations
int maxX, maxY;
Luego en la parte de las declaraciones públicas escribimos la definición del método ExtranioConfinador(), el cual es diferente a los que ya hemos utilizado antes a pesar de tener el mismo nombre:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::ExtranioConfinador();
Bueno ahora nos vamos a la Forma y en sus respectivos eventos buscamos el evento OnCreate y damos doble clic, luego en él escribimos el siguiente código:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
maxX = this->ClientWidth;
maxY = this->ClientHeight;
}
//---------------------------------------------------------------------------
Es hora pues de codificar el método ExtranioConfinador(), el código que necesitaremos para poder generar el efecto del fractal es el que tenemos a continuación:
void TForm1::ExtranioConfinador()
{
int i, j, k, l, Color, Contador;
double PobAnt, PobNueva, X, Y, Razon;
PobAnt = PobNueva = 0.0;
Razon = 2.3;
Y = 0;
for ( j = 1; j <= 15; j++)
{
Color++;
if ( Color > clWhite )
Color = clBlue;
for ( k = 1; k <= 10; k++ )
{
Contador = 0;
Razon = Razon + 0.01;
PobAnt = 0.01;
for ( i = 1; i <= 1000; i++)
{
PobNueva = Razon * ( PobAnt * ( 1 - PobAnt ) );
X = PobNueva - PobAnt;
this->Canvas->Pixels[(X*maxX/2)+maxX/2][(maxY/2)-(Y*maxY/2)]=(TColor)Color;
if( PobAnt == PobNueva )
Contador++;
else
Contador = 0;
if( Contador > 100 )
i = 10000;
PobAnt = PobNueva;
Y = X;
}
}
}
this->Canvas->TextOutA(10, 10, "Flujo Maltusiano");
}
//---------------------------------------------------------------------------
Ya para terminar damos doble clic en el botón que habíamos colocado sobre la Forma y en el escribimos la llamada el método ExtranioConfinador(), el código es así:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
ExtranioConfinador();
}
//---------------------------------------------------------------------------
Y es todo chavos ahora todo lo que tenemos que hacer es compilar y correr nuestra aplicación y aquí tenemos el efecto que se debe de generar:
Bien chavos por esta ocasión fue todo, como pueden ir viendo generar los fractales es algo bastante sencillo y rápido pero también muy interesante debido a los efectos que se van formando. Aun nos quedan unos cuantos por ver, pero eso ya será en otra ocasión. Hasta la vista amigos!.
Bien pues rápidamente comencemos. Lo primero será como ya hemos estado acostumbrando hacer será cambiar el color de la Forma. Como ya les había mencionado en ocasiones pasadas esto es opcional, si quieren lo pueden hacer e incluso pueden elegir el color que ustedes deseen, en mi caso yo cambiaré el color de la Forma a color rojo. Inmediatamente después tenemos que colocar un botón sobre la Forma.
Nuestra interfaz debería verse mas o menos de la siguiente manera, dependiendo de lo que hayan elegido ustedes:
Ahora nos vamos a la parte del código la cual será bastante sencilla. Primero nos vamos al archivo H y en la parte de declaraciones privadas declaramos las siguientes variables:
private: // User declarations
int maxX, maxY;
Luego en la parte de las declaraciones públicas escribimos la definición del método ExtranioConfinador(), el cual es diferente a los que ya hemos utilizado antes a pesar de tener el mismo nombre:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::ExtranioConfinador();
Bueno ahora nos vamos a la Forma y en sus respectivos eventos buscamos el evento OnCreate y damos doble clic, luego en él escribimos el siguiente código:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
maxX = this->ClientWidth;
maxY = this->ClientHeight;
}
//---------------------------------------------------------------------------
Es hora pues de codificar el método ExtranioConfinador(), el código que necesitaremos para poder generar el efecto del fractal es el que tenemos a continuación:
void TForm1::ExtranioConfinador()
{
int i, j, k, l, Color, Contador;
double PobAnt, PobNueva, X, Y, Razon;
PobAnt = PobNueva = 0.0;
Razon = 2.3;
Y = 0;
for ( j = 1; j <= 15; j++)
{
Color++;
if ( Color > clWhite )
Color = clBlue;
for ( k = 1; k <= 10; k++ )
{
Contador = 0;
Razon = Razon + 0.01;
PobAnt = 0.01;
for ( i = 1; i <= 1000; i++)
{
PobNueva = Razon * ( PobAnt * ( 1 - PobAnt ) );
X = PobNueva - PobAnt;
this->Canvas->Pixels[(X*maxX/2)+maxX/2][(maxY/2)-(Y*maxY/2)]=(TColor)Color;
if( PobAnt == PobNueva )
Contador++;
else
Contador = 0;
if( Contador > 100 )
i = 10000;
PobAnt = PobNueva;
Y = X;
}
}
}
this->Canvas->TextOutA(10, 10, "Flujo Maltusiano");
}
//---------------------------------------------------------------------------
Ya para terminar damos doble clic en el botón que habíamos colocado sobre la Forma y en el escribimos la llamada el método ExtranioConfinador(), el código es así:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
ExtranioConfinador();
}
//---------------------------------------------------------------------------
Y es todo chavos ahora todo lo que tenemos que hacer es compilar y correr nuestra aplicación y aquí tenemos el efecto que se debe de generar:
Bien chavos por esta ocasión fue todo, como pueden ir viendo generar los fractales es algo bastante sencillo y rápido pero también muy interesante debido a los efectos que se van formando. Aun nos quedan unos cuantos por ver, pero eso ya será en otra ocasión. Hasta la vista amigos!.
jueves, 5 de abril de 2012
Fractal De Malthus 1
Hola chavos! Espero que anden de lo mejor y yo aquí ando pasando rápidamente para mostrarles otro ejemplo de los fractales por supuesto programado en C++ Builder. En esta ocasión el fractal que programaremos será el conocido como el fractal de Malthus 1.
Bien pues como siempre ya saben que el primer paso que realizo es opcional, si quieren pueden seguirlo y si no pues no hay problema todo funcionará normalmente. Lo primero que haré yo será cambiar el color de la Forma en su propiedad color buscamos el color clTeal y lo elegimos. Ahora colocamos un botón sobre la Forma y eso será todo lo que tenemos que hacer sobre la Forma, la cual nos quedará de la siguiente manera:
Bien ahora nos cambiamos a la parte del editor de código y nos vamos al archivo cabecera del programa, es decir al archivo H y en la parte de declaraciones privadas tecleamos las siguientes variables:
private: // User declarations
int maxX, maxY, MaxGen;
Ahora en la parte de las declaraciones públicas escribimos la siguiente definición del método ExtranioConfinador(), que aunque su nombre es igual al método que utilizamos en el fractal pasado su funcionamiento es completamente diferente:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::ExtranioConfinador();
Bueno ahora nos vamos a la Forma y en sus eventos elegimos el llamado OnCreate y le damos doble clic, ahí tecleamos el siguiente código, que nos servirá para que las siguientes variables tomen un valor cada vez que ejecutemos nuestra aplicación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
MaxGen = 0x00FF;
maxX = this->ClientWidth;
maxY = this->ClientHeight;
}
//---------------------------------------------------------------------------
Enseguida escribimos el método ExtranioConfinador(), el código que necesitamos para generar el efecto del fractal es el que tenemos a continuación:
void TForm1::ExtranioConfinador()
{
int i, j, k, l, Color, Contador, X, Y;
double PobAnt, PobNueva, Razon;
PobNueva = 0.0;
Razon = 2.3;
Color = clBlack;
for( j = 1; j <= 151; j++ )
{
Color++;
if( Color >= clWhite )
Color = clBlue;
Contador = 0;
Razon += 0.01;
PobAnt = 0.01;
for( i = 1; i <= MaxGen; i++ )
{
PobNueva = Razon * ( PobAnt * ( 1 - PobAnt ) );
X = PobAnt * maxX;
Y = maxY - ( PobNueva * maxY );
this->Canvas->Pixels[X][Y] = (TColor)Color;
if ( PobAnt == PobNueva )
Contador++;
else
Contador = 0;
if ( Contador > 10 )
i = MaxGen;
PobAnt = PobNueva;
}
this->Canvas->TextOutA(10, 10, "Flujo Maltusiano");
Sleep(5);
}
}
//---------------------------------------------------------------------------
Finalmente solo queda escribir la llamada al método en el evento OnClic del botón que habíamos colocado sobre la Forma:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
ExtranioConfinador();
}
//---------------------------------------------------------------------------
Y así de fácil fue todo chavos ahora compilamos y corremos nuestra aplicación y si hicimos todo correctamente obtendremos un efecto como el siguiente:
Bueno amigos pues ya hemos visto un montón de fractales diferentes pero aun nos quedan unos cuantos más por mostrar, ya que como les había dicho antes este tema es bastante amplio e interesante. Por hoy eso fue todo chavos nos vemos en la siguiente ocasión para continuar con más de este mismo tema y mostrar otro fractal parecido al de hoy conocido como el fractal de Malthus 2, hasta entonces amigos!!.
Bien pues como siempre ya saben que el primer paso que realizo es opcional, si quieren pueden seguirlo y si no pues no hay problema todo funcionará normalmente. Lo primero que haré yo será cambiar el color de la Forma en su propiedad color buscamos el color clTeal y lo elegimos. Ahora colocamos un botón sobre la Forma y eso será todo lo que tenemos que hacer sobre la Forma, la cual nos quedará de la siguiente manera:
Bien ahora nos cambiamos a la parte del editor de código y nos vamos al archivo cabecera del programa, es decir al archivo H y en la parte de declaraciones privadas tecleamos las siguientes variables:
private: // User declarations
int maxX, maxY, MaxGen;
Ahora en la parte de las declaraciones públicas escribimos la siguiente definición del método ExtranioConfinador(), que aunque su nombre es igual al método que utilizamos en el fractal pasado su funcionamiento es completamente diferente:
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void TForm1::ExtranioConfinador();
Bueno ahora nos vamos a la Forma y en sus eventos elegimos el llamado OnCreate y le damos doble clic, ahí tecleamos el siguiente código, que nos servirá para que las siguientes variables tomen un valor cada vez que ejecutemos nuestra aplicación:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
MaxGen = 0x00FF;
maxX = this->ClientWidth;
maxY = this->ClientHeight;
}
//---------------------------------------------------------------------------
Enseguida escribimos el método ExtranioConfinador(), el código que necesitamos para generar el efecto del fractal es el que tenemos a continuación:
void TForm1::ExtranioConfinador()
{
int i, j, k, l, Color, Contador, X, Y;
double PobAnt, PobNueva, Razon;
PobNueva = 0.0;
Razon = 2.3;
Color = clBlack;
for( j = 1; j <= 151; j++ )
{
Color++;
if( Color >= clWhite )
Color = clBlue;
Contador = 0;
Razon += 0.01;
PobAnt = 0.01;
for( i = 1; i <= MaxGen; i++ )
{
PobNueva = Razon * ( PobAnt * ( 1 - PobAnt ) );
X = PobAnt * maxX;
Y = maxY - ( PobNueva * maxY );
this->Canvas->Pixels[X][Y] = (TColor)Color;
if ( PobAnt == PobNueva )
Contador++;
else
Contador = 0;
if ( Contador > 10 )
i = MaxGen;
PobAnt = PobNueva;
}
this->Canvas->TextOutA(10, 10, "Flujo Maltusiano");
Sleep(5);
}
}
//---------------------------------------------------------------------------
Finalmente solo queda escribir la llamada al método en el evento OnClic del botón que habíamos colocado sobre la Forma:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
this->Repaint();
ExtranioConfinador();
}
//---------------------------------------------------------------------------
Y así de fácil fue todo chavos ahora compilamos y corremos nuestra aplicación y si hicimos todo correctamente obtendremos un efecto como el siguiente:
Bueno amigos pues ya hemos visto un montón de fractales diferentes pero aun nos quedan unos cuantos más por mostrar, ya que como les había dicho antes este tema es bastante amplio e interesante. Por hoy eso fue todo chavos nos vemos en la siguiente ocasión para continuar con más de este mismo tema y mostrar otro fractal parecido al de hoy conocido como el fractal de Malthus 2, hasta entonces amigos!!.
Suscribirse a:
Entradas (Atom)