[DUG] Venn Diagrams
Alister Christie
alister at SalesPartner.co.nz
Tue Aug 2 16:28:03 NZST 2005
I was feeling bored today so I wrote a component to do Venn Diagrams (as
you do when bored) - now can anybody find a use for it?
I did have in the back of my mind that it could be a way for the users
of my software to select stuff out of a database. If tomorrow is
equally exciting I may extend it to 3 sets and have it create some SQL
along similar lines to the LogicString property (although with 3 sets
the number of combinations would be huge)
Anyway Comments...
unit VennDiagram;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Graphics;
type
TVennDiagram = class(TGraphicControl)
private
FSelectedOutside: boolean;
FSelectedMiddle: boolean;
FSelectedLeft: boolean;
FSelectedRight: boolean;
FRightDescription: string;
FLeftDescription: string;
FShowDescriptions: boolean;
FOnChange: TNotifyEvent;
function GetCircleRadius: integer;
function GetLeftCircleCenter: TPoint;
function GetRightCircleCenter: TPoint;
procedure SetSelectedLeft(const Value: boolean);
procedure SetSelectedMiddle(const Value: boolean);
procedure SetSelectedOutside(const Value: boolean);
procedure SetSelectedRight(const Value: boolean);
procedure VennDiagramMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SetLeftDescription(const Value: string);
procedure SetRightDescription(const Value: string);
procedure SetShowDescriptions(const Value: boolean);
function GetLogicString: string;
{ Private declarations }
protected
{ Protected declarations }
property OnMouseDown;
public
{ Public declarations }
procedure Paint; override;
function InCircle(aPoint, Center: TPoint; Radius: integer): boolean;
function InsideLeftCircle(aPoint : TPoint) : boolean;
function InsideRightCircle(aPoint : TPoint) : boolean;
function InsideMiddle(aPoint : TPoint) : boolean;
constructor Create(AOwner: TComponent); override;
property LogicString : string read GetLogicString;
published
{ Published declarations }
Property SelectedOutside : boolean read FSelectedOutside write
SetSelectedOutside;
Property SelectedLeft : boolean read FSelectedLeft write
SetSelectedLeft;
Property SelectedRight : boolean read FSelectedRight write
SetSelectedRight;
Property SelectedMiddle : boolean read FSelectedMiddle write
SetSelectedMiddle;
Property LeftCircleCenter : TPoint read GetLeftCircleCenter;
Property RightCircleCenter : TPoint read GetRightCircleCenter;
property CircleRadius : integer read GetCircleRadius;
property LeftDescription : string read FLeftDescription write
SetLeftDescription;
Property RightDescription : string read FRightDescription write
SetRightDescription;
Property ShowDescriptions : boolean read FShowDescriptions write
SetShowDescriptions;
Property Font;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Additional', [TVennDiagram]);
end;
{ TVennDiagram }
constructor TVennDiagram.Create(AOwner: TComponent);
begin
inherited;
Canvas.Font.Assign(Font);
Canvas.Brush.Color := clBtnFace;
OnMouseDown := VennDiagramMouseDown;
FSelectedOutside := FALSE;
FSelectedMiddle := FALSE;
FSelectedLeft := FALSE;
FSelectedRight := FALSE;
end;
function TVennDiagram.GetCircleRadius: integer;
begin
result := Width div 4;
end;
function TVennDiagram.GetLeftCircleCenter: TPoint;
begin
result.X := Width div 3;
result.Y := Height div 2;
end;
function TVennDiagram.GetLogicString: string;
begin
//all things selected
if SelectedOutside and SelectedLeft and SelectedMiddle and
SelectedRight then
result := 'TRUE'
//3 things selected
else if SelectedLeft and SelectedMiddle and SelectedRight then
result := LeftDescription + ' or ' + RightDescription
else if SelectedOutside and SelectedLeft and SelectedMiddle then
result := LeftDescription + ' and not ' + RightDescription
else if SelectedOutside and SelectedMiddle and SelectedRight then
result := 'not ' + LeftDescription + ' and ' + RightDescription
else if SelectedOutside and SelectedLeft and SelectedRight then
result := 'not (' + LeftDescription + ' and ' + RightDescription + ')'
//2 things selected
else if SelectedOutside and SelectedLeft then
result := 'not ' + RightDescription
else if SelectedOutside and SelectedRight then
result := 'not ' + LeftDescription
else if SelectedOutside and SelectedMiddle then
result := 'not (' + LeftDescription + ' xor ' + RightDescription + ')'
else if SelectedMiddle and SelectedLeft then
result := LeftDescription
else if SelectedMiddle and SelectedRight then
result := RightDescription
else if SelectedRight and SelectedLeft then
result := LeftDescription + ' xor ' + RightDescription
//1 thing Selected
else if SelectedOutside then
result := 'not (' + LeftDescription + ' or ' + RightDescription + ')'
else if SelectedLeft then
result := LeftDescription + ' and not ' + RightDescription
else if SelectedRight then
result := 'not ' + LeftDescription + ' and ' + RightDescription
else if SelectedMiddle then
result := LeftDescription + ' xor ' + RightDescription
else
//only possibility remaining
result := 'FALSE';
end;
function TVennDiagram.GetRightCircleCenter: TPoint;
begin
result.X := 2 * Width div 3;
result.Y := Height div 2;
end;
function TVennDiagram.InCircle(aPoint, Center: TPoint;
Radius: integer): boolean;
var
DistanceFromCenter : TPoint;
begin
DistanceFromCenter.X := abs(aPoint.X-Center.X);
DistanceFromCenter.Y := abs(aPoint.Y-Center.Y);
result := Sqrt(Sqr(DistanceFromCenter.X) +
Sqr(DistanceFromCenter.Y)) < radius;
end;
function TVennDiagram.InsideLeftCircle(aPoint: TPoint): boolean;
begin
result := InCircle(aPoint, LeftCircleCenter, CircleRadius)
end;
function TVennDiagram.InsideMiddle(aPoint: TPoint): boolean;
begin
result := InsideRightCircle(aPoint) and InsideLeftCircle(aPoint)
end;
function TVennDiagram.InsideRightCircle(aPoint: TPoint): boolean;
begin
result := InCircle(aPoint, RightCircleCenter, CircleRadius)
end;
procedure TVennDiagram.Paint;
procedure CenterCircle(C : TCanvas; X, Y, R : Integer);
begin
C.Ellipse(x-r, y-r, x+r, y+r);
end;
begin
inherited;
Canvas.Brush.Color := clBtnFace;
Canvas.Rectangle(0,0,width, height);
Canvas.Brush.Style := bsClear;
CenterCircle(Canvas, LeftCircleCenter.X, LeftCircleCenter.Y,
CircleRadius);
CenterCircle(Canvas, RightCircleCenter.X, RightCircleCenter.Y,
CircleRadius);
Canvas.Brush.Style := bsSolid;
Canvas.Brush.Color := clRed;
if FSelectedOutside then
Canvas.FloodFill(2, 2, clBlack, fsBorder);
if FSelectedLeft then
Canvas.FloodFill(LeftCircleCenter.X, LeftCircleCenter.Y, clBlack,
fsBorder);
if FSelectedMiddle then
Canvas.FloodFill(width div 2, Height div 2, clBlack, fsBorder);
if FSelectedRight then
Canvas.FloodFill(RightCircleCenter.X, RightCircleCenter.Y, clBlack,
fsBorder);
if ShowDescriptions then
begin
Canvas.Font := Font;
Canvas.Brush.Style := bsClear;
Canvas.TextOut(2,2,LeftDescription);
Canvas.TextOut(width - Canvas.TextWidth(RightDescription)-2
,2,RightDescription);
end;
end;
procedure TVennDiagram.SetLeftDescription(const Value: string);
begin
FLeftDescription := Value;
Invalidate;
end;
procedure TVennDiagram.SetRightDescription(const Value: string);
begin
FRightDescription := Value;
Invalidate;
end;
procedure TVennDiagram.SetSelectedLeft(const Value: boolean);
begin
FSelectedLeft := Value;
invalidate;
end;
procedure TVennDiagram.SetSelectedMiddle(const Value: boolean);
begin
FSelectedMiddle := Value;
invalidate;
end;
procedure TVennDiagram.SetSelectedOutside(const Value: boolean);
begin
FSelectedOutside := Value;
invalidate;
end;
procedure TVennDiagram.SetSelectedRight(const Value: boolean);
begin
FSelectedRight := Value;
invalidate;
end;
procedure TVennDiagram.SetShowDescriptions(const Value: boolean);
begin
FShowDescriptions := Value;
Invalidate;
end;
procedure TVennDiagram.VennDiagramMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if DebugHook <> -1 then
begin
if InsideMiddle(Point(X,Y)) then
FSelectedMiddle := not FSelectedMiddle
else if InsideLeftCircle(Point(X,Y)) then
FSelectedLeft := not FSelectedLeft
else if InsideRightCircle(Point(X,Y)) then
FSelectedRight := not FSelectedRight
else
FSelectedOutside := not FSelectedOutside;
end;
Invalidate;
if Assigned(FOnChange) then
FOnChange(Self);
end;
end.
--
Alister Christie
Computers for People
Ph: 04 471 1849 Fax: 04 471 1266
http://www.salespartner.co.nz
PO Box 13085
Johnsonville
Wellington
More information about the Delphi
mailing list