Jugando con Elipses en Delphi
Hoy os traigo una pequeña aplicación didáctica en delphi que dibuja elipses (mejor dicho círculos, pero utilizo el metodo elipse del TCanvas para dibujarlo) y detecta las colisiones entre estas arrastrando el mouse por encima. Observareis que es muy simple pero sirve para jugar un poco con el canvas y el ratón y ver que tipo de aplicaciones visuales podemos llegar a hacer con delphi. Al pasar el mouse por encima del objeto detecta su paso y muestra un color de colisión. Además al mover una de las elipses hacia otro objeto, se detecta la colisión entre estos y se frena el movimiento si dejarte mover el objeto. La detección es muy sencilla, mediante la posición del mouse se comprueba que la distancia de éste con el centro de cualquiera de las otras elipses sea mayor que la distancia del objeto a arrastrar y las otras elipses, un principio muy simple pero que funciona muy bien y sin tener que hacer cálculos desorbitados. Aquí os dejo la aplicación Thundax Draw Ellipses, y parte del código fuente y un pantallazo de la aplicación:

La clase TEllipse:
unit ThundaxEllipse;
interface
uses
types, Graphics, Classes, Controls;
type
TEllipse = class(TObject)
private
FborderColor: TColor;
Flength: integer;
FlineWidth: integer;
FCollisionColor: TColor;
FColor: TColor;
Fposition: TPoint;
FCanvas: TCanvas;
FDrag: boolean;
Fid: string;
Fradium: integer;
FCenter: TPoint;
procedure SetborderColor(const Value: TColor);
procedure SetCollisionColor(const Value: TColor);
procedure SetColor(const Value: TColor);
procedure Setlength(const Value: integer);
procedure SetlineWidth(const Value: integer);
procedure Setposition(const Value: TPoint);
procedure SetDrag(const Value: boolean);
procedure SetCenter(const Value: TPoint);
procedure Setid(const Value: string);
procedure Setradium(const Value: integer);
public
property position: TPoint read Fposition write Setposition;
property id: string read Fid write Setid;
property Drag: boolean read FDrag write SetDrag;
property length: integer read Flength write Setlength;
property Color: TColor read FColor write SetColor;
property borderColor: TColor read FborderColor write SetborderColor;
property lineWidth: integer read FlineWidth write SetlineWidth;
property CollisionColor: TColor read FCollisionColor write SetCollisionColor;
constructor Create(Canvas: TCanvas; center: TPoint; length: integer);
function PointInside(x, y: integer): boolean;
procedure SetMousePosition(x, y: integer);
procedure Draw(x, y: integer);
procedure EnableDrag(x, y: integer);
property Center: TPoint read FCenter write SetCenter;
property radium: integer read Fradium write Setradium;
end;
implementation
{ TEllipse }
constructor TEllipse.Create(Canvas: TCanvas; center: TPoint; length: integer);
begin
FCanvas := Canvas;
Fposition := center;
FLength := length;
FDrag := false;
FCenter := point(Fposition.x + (Flength div 2), Fposition.y + (Flength div 2));
FRadium := FLength div 2;
end;
procedure TEllipse.Draw(x, y: integer);
begin
if FDrag then
SetMousePosition(x, y);
if PointInside(x, y) then
FCanvas.Brush.Color := FCollisionColor
else
FCanvas.Brush.Color := FColor;
FCanvas.Pen.Color := FborderColor;
FCanvas.Pen.Width := 1;
FCanvas.Ellipse(Fposition.x, Fposition.y, Fposition.x + FLength, Fposition.y + FLength);
FCanvas.Font.Color := clWhite;
FCanvas.TextOut(Fposition.x + (Flength div 2) - 5, Fposition.y + (Flength div 2) - 7, FId);
end;
procedure TEllipse.EnableDrag(x, y: integer);
begin
if PointInside(x, y) then
Fdrag := true;
end;
function TEllipse.PointInside(x, y: integer): boolean;
var
x0, y0, a, b: integer;
point2: TPoint;
begin
point2 := Point(Fposition.x + Flength, FPosition.y + Flength);
x0 := (Fposition.x + point2.x) div 2;
y0 := (Fposition.y + point2.y) div 2;
a := (point2.x - Fposition.x) div 2;
b := (point2.y - Fposition.y) div 2;
result := (Sqr((x - x0) / a) + Sqr((y - y0) / b) <= 1);
end;
procedure TEllipse.SetborderColor(const Value: TColor);
begin
FborderColor := Value;
end;
procedure TEllipse.SetCenter(const Value: TPoint);
begin
FCenter := Value;
end;
procedure TEllipse.SetCollisionColor(const Value: TColor);
begin
FCollisionColor := Value;
end;
procedure TEllipse.SetColor(const Value: TColor);
begin
FColor := Value;
end;
procedure TEllipse.SetDrag(const Value: boolean);
begin
FDrag := Value;
end;
procedure TEllipse.Setid(const Value: string);
begin
Fid := Value;
end;
procedure TEllipse.Setlength(const Value: integer);
begin
Flength := Value;
end;
procedure TEllipse.SetlineWidth(const Value: integer);
begin
FlineWidth := Value;
end;
procedure TEllipse.SetMousePosition(x, y: integer);
begin
FPosition := point(x - (Flength div 2), y - (Flength div 2));
FCenter := point(Fposition.x + (Flength div 2), Fposition.y + (Flength div 2));
end;
procedure TEllipse.Setposition(const Value: TPoint);
begin
Fposition := Value;
end;
procedure TEllipse.Setradium(const Value: integer);
begin
Fradium := Value;
end;
end.
El cálculo de las colisiones:
procedure TForm3.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
i, j: integer;
Collide: boolean;
textCollision: string;
Collisions: array[1..20] of integer;
begin
DrawRectangle(clWhite, clWhite);
Memo1.lines.Clear;
textCollision := '';
Collide := false;
for i := 1 to 20 do
Collisions[i] := -1;
for i := 1 to number do
begin
for j := 1 to number do
if Ellipses[i].drag and
distanciaMouse(Point(x, y), Ellipses[i].center, Ellipses[j].center) and
Collision(ellipses[i], ellipses[j]) then
begin
Memo1.lines.add('Collide True ->' + inttostr(i) + ' ' + inttostr(j));
Collide := true;
Collisions[i] := i;
end;
end;
for i := 1 to number do
begin
if Collisions[i] = -1 then
ellipses[i].Draw(x, y)
else
ellipses[i].draw(ellipses[i].center.x, ellipses[i].center.y);
Memo1.lines.add('Collision ' + inttostr(Collisions[i]));
end;
if collide then
textCollision := 'Collision!';
StatusBar1.Panels[0].Text := 'x : ' + inttostr(x) + ' y : ' + inttostr(y) + ' ' + textCollision;
end;
function TForm3.DistanciaMouse(p1, p2, p3: TPoint): boolean;
begin
result := false;
if (p2.x <> p3.x) and (p2.y <> p3.y) then
result := (distancia(p1, p3) < distancia(p2, p3))
end;
function TForm3.Collision(p1, p2: TEllipse): boolean;
begin
result := false;
if p1 <> p2 then
result := distancia(p1.center, p2.center) < (2 * (p1.radium));
end;
function TForm3.distancia(p1, p2: TPoint): double;
begin
result := sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y));
end;
%20applied%20to%20Transformer%20models%20in%20machine%20learning.%20The%20image%20shows%20a%20neural%20networ.webp)

Comments
Post a Comment