Friday, 17 July 2009

Implementando automated linked objects con Delphi parte I

Hoy os traigo una nueva aplicación con la que llevo peleándome 1 semana y que corresponde a la solución de la conexión automática entre objetos (visualizarlo por pantalla). Muchas veces me he encontrado con aplicaciones gráficas que permiten insertar un objeto en pantalla y conectarlo con otro y que ésta conexión sea automática y que busque una forma posible sin tocar los 2 objetos. Pues bien, ésto es lo que he conseguido con mi aplicación. Aún está en una fase de desarrollo pero empiezo mostrando el patrón utilizado para la correcta composición de las clases evitando codificaciones tediosas y haciendo el código altamente inteligible. Aquí os dejo unos pantallazos de mi aplicación:


Desde la aplicación, podemos variar las propiedades de las cajas e indicar la salida del conector. El diagrama UML para su codificación os lo presento aquí:


  • Presentación del diseño:
Mi solución consiste en disponer de una clase TBox, que es la que se presenta en pantalla. Cada caja tiene sus propiedades, vértices, color, centro, punto de conexión, tamaño, etc. Pero ella misma no se puede pintar en ningún sitio. Ése trabajo se lo transmite al TBoxManager. Éste se encarga de los cálculos matemáticos correspondientes al recubrimiento del área. Hace los cálculos correspondientes sobre detección de puntos en el plano, en el área interior de la caja.
Luego disponemos de 2 clases que se encargan pintado en un TCanvas. En este caso el TBoxPainter y el TLinkPainter se encargar de hacer el pintado de las cajas y los enlaces en la pantalla. Es el propio TBoxPainter el que llama a la caja para pintarla y no la propia caja (Principio de Hollywood, no me llames tú ya te llamaremos nosotros). El mismo funcionamiento para el TLinkPainter, que recoge 2 cajas y realiza el enlace entre ellas mediante sus funciones internas.

Aquí os dejo la aplicación en una primera fase de desarrollo, Thundax Geometric Links v1.0.0 build 3. Aún me queda todo el tema de las propiedades y corregir alguno de los movimientos y posición que no se resuelve correctamente. Una vez tenga hecho el algoritmo lo podré fusionar con mi anterior aplicación Thundax NeuralLinking.


Aquí os muestro parte del código para la generación de la aplicación y la configuración de las clases diseñadas:




procedure DrawAll;
begin
SourceBox := TBox.Create(Point(StrToInt(edit1.text), StrToInt(edit2.text)), 8, StrToInt(Edit5.text), clYellow, clAqua);
SourceBox.SetLinkDirection(up1.checked, down1.checked, left1.checked, right1.checked);
TargetBox := TBox.Create(Point(StrToInt(edit3.text), StrToInt(edit4.text)), 8, StrToInt(Edit5.text), clLime, clAqua);
TargetBox.SetLinkDirection(up2.checked, down2.checked, left2.checked, right2.checked);

BoxM := TBoxManager.Create(SourceBox, TargetBox);
BoxP := TBoxPainter.Create(image1);
BoxL := TLinkPainter.Create(image1, SourceBox, TargetBox);

BoxP.DrawBox(SourceBox);
BoxP.DrawBox(TargetBox);
end;

type
TDirection = (isUp, isDown, isLeft, isRight);

TBox = class(TObject)
private
FColor: integer;
FSize: integer;
FOffset: integer;
FDirection: TDirection;
FlinkColor: integer;
FlinkPoint: TPoint;
FcenterPoint: TPoint;
function getIntersectionPoint(): TPoint;
procedure SetColor(const Value: integer);
procedure SetOffset(const Value: integer);
procedure SetSize(const Value: integer);
procedure SetDirection(const Value: TDirection);
procedure SetlinkColor(const Value: integer);
procedure SetcenterPoint(const Value: TPoint);
procedure SetlinkPoint(const Value: TPoint);
public
vertex: array[0..3] of TPoint;
property centerPoint: TPoint read FcenterPoint write SetcenterPoint;
property linkPoint: TPoint read FlinkPoint write SetlinkPoint;
property Direction: TDirection read FDirection write SetDirection;
property intersection: TPoint read getIntersectionPoint;
property Offset: integer read FOffset write SetOffset;
property Size: integer read FSize write SetSize;
property Color: integer read FColor write SetColor;
property linkColor: integer read FlinkColor write SetlinkColor;
constructor Create(centerPoint: TPoint; Size: integer; Offset: integer; Color: integer; linkColor: integer);
procedure SetLink(point: TPoint);
function BetweenX(point: TPoint): boolean;
function BetweenY(point: TPoint): boolean;
procedure SetLinkDirection(up, down, left, right: boolean);
function PointInside(point : TPoint) : boolean;
end;


type
TBoxManager = class(TObject)
private
FSourceBox: TBox;
FTargetBox: TBox;
procedure SetSourceBox(const Value: TBox);
procedure SetTargetBox(const Value: TBox);
function PointInsideRegion(testPoint: TPoint): boolean;
public
sourceNodes: array[0..3] of TPoint;
targetNodes: array[0..3] of TPoint;
property SourceBox: TBox read FSourceBox write SetSourceBox;
property TargetBox: TBox read FTargetBox write SetTargetBox;
constructor Create(SourceBox: TBox; TargetBox: TBox);
function intersected(): boolean;
end;

type
TBoxPainter = class(TObject)
private
Fimage: TImage;
FlinkColor: integer;
procedure Setimage(const Value: TImage);
procedure DrawLine(point1, point2: TPoint; colorLine: integer);
procedure DrawRectangle(BackGroundColor, RectangleColor: integer);
public
property image: TImage read Fimage write Setimage;
constructor Create(image: TImage);
procedure DrawBox(Box: TBox);
end;

type
TLinkPainter = class(TObject)
private
SourceBox: TBox;
TargetBox: TBox;
FlinkColor: integer;
Fimage: TImage;
procedure DrawLine(point1, point2: TPoint; colorLine: integer);
procedure SetlinkColor(const Value: integer);
procedure Setimage(const Value: TImage);
procedure DrawX(var SourcePoint: TPoint; TargetPoint: TPoint);
procedure DrawY(var SourcePoint: TPoint; TargetPoint: TPoint);
procedure DrawMidXY(var SourcePoint: TPoint; TargetPoint: TPoint);
procedure DrawOffsetX(var SourcePoint: TPoint; TargetPoint: TPoint; Offset: integer);
procedure DrawXYXOffsetX_target(var SourcePoint: TPoint; TargetPoint: TPoint; OffSet: integer);
procedure DrawXYXOffsetX_Source(var SourcePoint: TPoint; TargetPoint: TPoint; OffSet: integer);
procedure DrawYXYOffset(var SourcePoint: TPoint; TargetPoint: TPoint; OffSet: integer);
procedure DrawXY(var SourcePoint: TPoint; TargetPoint: TPoint);
procedure DrawOffsetY(var SourcePoint: TPoint; TargetPoint: TPoint; Offset: integer);
public
property image: TImage read Fimage write Setimage;
property linkColor: integer read FlinkColor write SetlinkColor;
constructor Create(image: TImage; SourceBox, TargetBox: TBox);
procedure Draw(var SourcePoint: TPoint; TargetPoint: TPoint; OffSet: integer);
end;




espero que os guste!.

0 comments:

Post a Comment