Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 03-01-2009
Avatar de aeff
aeff aeff is offline
Miembro
 
Registrado: oct 2006
Ubicación: Cuba, Guantánamo
Posts: 348
Poder: 18
aeff Va camino a la fama
¿Cómo pintar un círculo matemáticamente?

saludos!

miren colegas, el problema es que necesito pintar un círculo matemáticamente, sin usar el método Ellipse del Canvas ya que con este método si el Pen.Width = 1 e intento ir "cerrando el radio" y repintar un nuevo círculo quedan pixeles sin pintar, mi objetivo es lograr un Degradado Radial parecido al de PhotoShop, pero lo que necesito primeramente es logarar que no ocurra lo que acabo de explicar, si uso la fórmula matemática del círculo: R^2 = (X - H)^2 + (Y - K)^2, y despejo para halla a que valor de X le corresponde en Y según el radio, me sucede lo siguiente:

Código Delphi [-]
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  R: Real;
implementation
{$R *.DFM}
uses Math;
  function GetY(R, X: Real ): Real;
  var
    H, K, solve1, solve2: real;
  begin
    // R^2 = (X - H)^2 + (Y - K)^2
    H := R;
    K := R;
    solve1 := sqr(R) - sqr ( X - H );
    solve2 := (sqrt( abs(solve1) )) + k;
    Result := solve2;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  X: Real;
  Y: Integer;
  Value: Byte;
begin
  X := 0.000;
  Screen.Cursor := crHourGlass;
  while X <= R * 2 do
    begin
      Y := Round(GetY(R, X)) ;
      Value := 255 * Round(Y * (sin(DegToRad(Y))));
      Canvas.Pixels[ 200  - Round(R) + Round(X), 200 - round(R) + Y ] := RGB(Value, Value, Value);
      Canvas.Pixels[ 200  - Round(R) + Round(X), 200 + round(R) - Y  ] := RGB(Value, Value, Value);
      X := X + 0.1;
    end;
  Screen.Cursor := crDefault
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  R := 100;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 1 to 100 do
    begin
      R := I;
      Button1Click(self);
    end;
end;

nuevamente existen pixeles que no lograr cerrar el arco completamente,

espero que me hallan entendido y que me puedan responder.

mil gracias de antemano,
saludos!
aeff!
Responder Con Cita
  #2  
Antiguo 03-01-2009
[coso] coso is offline
Miembro Premium
 
Registrado: may 2008
Ubicación: Girona
Posts: 1.678
Poder: 0
coso Va por buen camino
hola, creo que te has hecho un lio. Te dejo el codigo, y te recomiendo que lo entiendas

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
     x,y,r,i,j : integer;
begin
     x := 150;
     y := 150;
     r := 50;
     for i := x-r to x+r do
     for j := y-r to y+r do
          if ((i-x)*(i-x) + (j-y)*(j-y)) < r*r then canvas.pixels[i,j] := (j+i)*3;

end;

procedure TForm1.Button2Click(Sender: TObject);
var
     x,y,r,i,j : integer;
     phi       : double;
begin
     x := 150;
     y := 350;
     r := 50;
     phi := 0;
     while phi < 2*PI do
     begin
          i := Round(x + r*cos(phi));
          j := Round(y + r*sin(phi));
          canvas.pixels[i,j] := i+j;
          phi := phi + 0.001;
     end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
     x,y,r,i,j : integer;
     rd : double;
     cl : array of TColor;
begin
     x := 150;
     y := 150;
     r := 50;

     setlength(cl,r);

     for i := 0 to length(cl) - 1 do
          cl[i] := Round(255-i*255/r)*$010000 ;

     for i := x-r to x+r do
     for j := y-r to y+r do
     begin
          rd := (i-x)*(i-x) + (j-y)*(j-y);
          if rd < r*r then canvas.pixels[i,j] := cl[Round(sqrt(rd))];
     end;

     setlength(cl,0);
end;

Última edición por coso fecha: 03-01-2009 a las 19:33:41.
Responder Con Cita
  #3  
Antiguo 03-01-2009
Avatar de aeff
aeff aeff is offline
Miembro
 
Registrado: oct 2006
Ubicación: Cuba, Guantánamo
Posts: 348
Poder: 18
aeff Va camino a la fama
saludos, bueno, ¿me puedes explicar el ejemplo del button 2?, ¿por que es seno y coseno? si en la fórmula del círculo no veo esto,

** nota: no tengo conocimientos fuertes de matemática, por esto es que paso tanto trabajo**

mil gracias de antemano colega!

saludos!
aeff!
Responder Con Cita
  #4  
Antiguo 03-01-2009
[coso] coso is offline
Miembro Premium
 
Registrado: may 2008
Ubicación: Girona
Posts: 1.678
Poder: 0
coso Va por buen camino
A ver...es trigonometria: en un triangulo rectangulo (con un angulo de 90 grados o PI/2 radiantes)...

sino de angulo (phi) = lado opuesto (y) / hipotenusa (r)=> y = r*sin(phi) . Para desplazarlo al centro que tu quieras, y = cy + r*sin(phi)

cosino de angulo (phi) = lado adyacente (x) / hipotenusa (r) => x = r * cos(phi). Para desplazarlo al centro, x = cx + r*sin(phi)

para dibujar el circulo, entonces, vas encontrando las coordenadas x,y manteniendo fija la r, recorriendo 2*PI radianes (360º) "fabricando" los triangulos rectangulos

ya que estamos, prueba :

Código Delphi [-]
procedure TForm1.Button2Click(Sender: TObject);
var
     x,y,i,j : integer;
     phi       : double;
begin
     x := 150;
     y := 350;
     phi := 0;
     while phi < 1000 do
     begin
          i := Round(x + phi*cos(phi));
          j := Round(y + phi*sin(phi));
          canvas.pixels[i,j] := i+j;
          phi := phi + 0.001;
     end;
end;
Imágenes Adjuntas
Tipo de Archivo: jpg Nuevo Imagen de mapa de bits.JPG (13,3 KB, 25 visitas)

Última edición por coso fecha: 03-01-2009 a las 23:30:17.
Responder Con Cita
  #5  
Antiguo 03-01-2009
Robert01 Robert01 is offline
Miembro
 
Registrado: feb 2006
Ubicación: Córdoba, Argentina
Posts: 895
Poder: 19
Robert01 Va por buen camino
Hola

Yo te explico, disculpame que me meta.

x + r*cos(phi)) esto es el valor de X más la proyección de r sobre ese mismo eje de coordenadas,
y + r*sin(phi)) es el valor de y más el valor de r proyectado sobre el otro eje.

En resumen, te da las coordenadas de un punto (i,j), son valores enteros por eso usa trunc para tomar solamente la parte entera de las ecuaciones anteriores.

Está usando coordenadas polares me parece si mal no recuerdo

Mirá aquí

Saludos

Disculpame coso
Responder Con Cita
  #6  
Antiguo 03-01-2009
[coso] coso is offline
Miembro Premium
 
Registrado: may 2008
Ubicación: Girona
Posts: 1.678
Poder: 0
coso Va por buen camino
Cita:
Está usando coordenadas polares me parece si mal no recuerdo
si, pasando polares a cartesianas o rectangulares

Cita:
Disculpame coso
pq? si no lo he inventado yo y lo que has dicho es cierto . Saludos de nuevo
Responder Con Cita
  #7  
Antiguo 04-01-2009
Avatar de aeff
aeff aeff is offline
Miembro
 
Registrado: oct 2006
Ubicación: Cuba, Guantánamo
Posts: 348
Poder: 18
aeff Va camino a la fama
ñoooooo! ahora si que veo lo linda que es la matemática, nunca me inmaginé como aplicar de esta forma las razones trigonometricas seno y coseno, mil gracias a todos por su ayuda,

por último, ¿como puedo hacer este círculo con relleno y que no se demore? porque usando este método de hallar lado opuesto y lado adyacente hacemos un recorrido hasta 360º de 0.001 en 0.001, y esto provoca que si voy disminuyendo el radio y vuelvo a pintar el círculo de esta forma nuevamente se producirá el ciclo hasta 360º , inmagínense que haga un Degradado Radial con un círculo que tenga como radio 800px, ¿cuanto tardará???..

espero que puedan ayudar nuevamente,

mil gracias de antemano!
AEff!
Responder Con Cita
  #8  
Antiguo 04-01-2009
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.734
Poder: 20
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
Lo que puedes hacer es pensarlo al reves...
Tienes un cirulo de 800px de diámetro. Por lo tanto entra dentro de un cuadrado de 800px con centro en (x,y).
Lo que puede hacer es ir leyendo cada pixel y ver si está dentro del círuculo.
- averiguas el valor del radio para (x,y).
--- para esto utilizas r=sqrt(x²+y²).
- si el radio es menor o igual a 400, está dentro del círculo.
--- luego pudes decidir qué color le corresponde según el valor del radio.
--- (radio(1)= rojo puro, radio(400)=azul puro, radio(200)= 50%rojo+50%azul, ...)
- si es mayor, lo descartas.

De esta manera la cantidad de iteraciones es 800x800=64000 (y solo en algunas se pinta)

Última edición por duilioisola fecha: 04-01-2009 a las 14:57:26.
Responder Con Cita
  #9  
Antiguo 04-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Como recomendación extra, sería útil que en vez de usar Pixels[] emplearas ScanLine(). El acceso es mucho más rápido.

Tal vez sea un poquito más complicado y requiera unas cuantas lineas más de código, pero se gana mucho en perfomance.
En otras ocasiones se habló de scanline, e incluso hay código con ejemplos de uso. Recomiendo una búsqueda con dicho término.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #10  
Antiguo 06-01-2009
Avatar de aeff
aeff aeff is offline
Miembro
 
Registrado: oct 2006
Ubicación: Cuba, Guantánamo
Posts: 348
Poder: 18
aeff Va camino a la fama
miren, la solución que encontré, ¿que opinan?, para no calentarme mucho la cabeza:

Código Delphi [-]
  type TColorPercent = record
    Color: TColor;
    Percent: 0..100;
  end;

  procedure Circle(ACanvas: TCanvas; X, Y, Radio: Integer);
  var
    pLeft, pTop, pDimX, pDimY: Integer;
  begin
    with aCanvas do
      begin
        Brush.Color := Pen.Color;
        pLeft := X - Radio;
        pTop  := Y - Radio;
        pDimX := X + Radio;
        pDimY := Y + Radio;
        Ellipse(pLeft, pTop, pDimX, pDimY);
      end;
  end;

  function GetChannelIn(X1, X2: Byte; Index, Max: LongInt): Byte;
  var
    vPercentIndex, vDifference, vPercentDiff: Real;
  begin
    vPercentIndex := 0.0;
    try
    // p/t = x/100
    // Index/max = x/100
    // index/max * 100 = x
      if Max = 0 then Max := 1; 
      vPercentIndex := Index / Max * 100;
    except

    end;
      vDifference := X2 - X1;
    // p/t  = x/100
    // p/vDifference = vPercentIndex/100
    // vPercentDiff = vPercentIndex / 100 *  vDifference;
      vPercentDiff := vPercentIndex / 100 *  vDifference;
      Result := X1 + Round(vPercentDiff);
  end;

  {-«------------------------------------------------------------------------»-}

  function GetGradientValue(aColor1, aColor2: TColor; Index, Max: Longint): TColor;
  var
    Color1, Color2: Integer;
    R1, G1, B1, R2, G2, B2, nR, nG, nB: Byte;
  begin
    Color1 := ColorToRGB(aColor1);
    Color2 := ColorToRGB(aColor2);
    R1 := GetRValue(Color1);  G1 := GetGValue(Color1);  B1 := GetBValue(Color1);
    R2 := GetRValue(Color2);  G2 := GetGValue(Color2);  B2 := GetBValue(Color2);

    nR := GetChannelIn(R1, R2, Index, Max);
    nG := GetChannelIn(G1, G2, Index, Max);
    nB := GetChannelIn(B1, B2, Index, Max);

    Result := TColor(RGB(nR, nG, nB));
  end;

 procedure GetRadialFigure(aWidth, aHeight: Integer; aColorList: array of TColorPercent;
                                             var vResult: TBitmap);
  var
    aBitmap: TBitmap;
    aRadio, aSubRadio, CX{Centro X}, CY{Centro Y},
    Index, xFrom, xTo, xRect: Integer;
    aColor1, aColor2, I: TColor;
  begin

    if High(aColorList) <= 0 then Exit;
    aBitmap := TBitmap.Create;
    aBitmap.Assign(vResult);
    aBitmap.PixelFormat := pf24bit;
    aBitmap.Width := aWidth;
    aBitmap.Height := aHeight;
    aRadio := Round(Sqrt( Sqr(aWidth) + Sqr(aHeight) ) / 2);
    CX := aWidth div 2;
    CY := aHeight div 2;

    Index := High(aColorList);


    while Index > 0 do
      begin
        xFrom := (aColorList[Index -1].Percent);
        xTo := (aColorList[Index].Percent);
        xFrom := Round(xFrom / 100 * aRadio);
        xTo := Round(xTo / 100 * aRadio);
        aSubRadio := xTo;  {Índice, o nuevo radio, o radio drecementativo}
        xRect := xTo - xFrom;  {Valor máximo}

        aColor1 := aColorList[Index -1].Color; {Menor}
        aColor2 := aColorList[Index].Color;  {Mayor}
        I := xRect;

        while aSubRadio > xFrom do
          begin
            aBitmap.Canvas.Pen.Color := GetGradientValue(aColor1, aColor2, I, xRect);
            Circle(aBitmap.Canvas, CX, CY, aSubRadio);
            aSubRadio := aSubRadio - 1;
            Dec(I);
          end;
        Dec(Index);
      end;

    vResult.Assign(aBitmap);
    aBitmap.Free;
  end;

ahora, añado un TImage y un Button y en el evento OnCLick del button coloco esto:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  aBmp: TBitmap;
  lstColors: array of TColorPercent;
begin
       //
  SetLength(lstColors, 2);
  lstColors[0].Percent := 0; lstColors[0].Color := clRed;
  lstColors[1].Percent := 100; lstColors[1].Color := clYellow;
  aBmp := TBitmap.Create;
  aBmp.Width := 200;
  aBmp.Height := 200;
  aBmp.PixelFormat := pf24bit;
  GetRadialFigure(200,200, lstColors, aBmp);
  Image1.Picture.Assign(aBmp);
end;

¿bueno, que opinan?

saludos!
aeff!
Responder Con Cita
  #11  
Antiguo 06-01-2009
[coso] coso is offline
Miembro Premium
 
Registrado: may 2008
Ubicación: Girona
Posts: 1.678
Poder: 0
coso Va por buen camino
hombre, personalmente lo haria de otra manera, segun para que quiero utilizarlo, pero si a ti te va bien, perfecto
Responder Con Cita
  #12  
Antiguo 12-01-2009
Avatar de MAXIUM
MAXIUM MAXIUM is offline
Miembro
 
Registrado: may 2005
Posts: 1.488
Poder: 20
MAXIUM Va camino a la fama
Usando el algoritmo de Bresenham's
http://sophia.javeriana.edu.co/~cbus...imitivas2D.pdf
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Un Falso NYT Circulo el 12 de Noviembre RONPABLO La Taberna 0 13-11-2008 23:23:00
Círculo sin relleno bosterito Gráficos 2 01-02-2007 22:41:02
cómo recortar (en circulo) un formulario en delphi? rls Gráficos 2 02-06-2006 09:15:14
Como pintar la fila de un DBGrid Gustavo Gowdak OOP 2 04-05-2006 21:34:04
El círculo delphi.com.ar Humor 11 28-04-2004 21:22:42


La franja horaria es GMT +2. Ahora son las 03:59:39.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi