unit GenericGraph.Global;
interface
uses
SysUtils,
Generics.Collections,
GenericGraph.ColorSchemes,
Variants;
type
{$REGION 'Documentation'}
/// <summary>
/// Definition for a marker, used for edges, vertices and graphs
/// </summary>
{$ENDREGION}
TMarker = Variant;
{$REGION 'Documentation'}
/// <summary>
/// An associative List of Markers
/// </summary>
{$ENDREGION}
TMarkerList = TDictionary<
string, TMarker>;
TCore =
class
Marker: TMarkerList;
{$REGION 'Documentation'}
/// <summary>
/// The degree is used in an undirected graph and determined the amount
/// of direct neighbours to a vertex
/// </summary>
{$ENDREGION}
Degree: Integer;
function HasAdditionalAttributes: Boolean;
virtual;
destructor Destroy;
override;
procedure Mark( Key:
String; Value: TMarker );
function GetMark( Key:
String ): TMarker;
function HasMark( Key:
String ): Boolean;
procedure UnMark( Key:
String );
function HasAnyMark( ): Boolean;
procedure ClearMarks( );
end;
TCore<T> =
class( TCore )
Data: T;
end;
{$REGION 'Documentation'}
/// <summary>
/// Contains attributes to customize the output of a TVertex
/// </summary>
{$ENDREGION}
TVertexOutputAttributes =
record
Caption:
String;
Shape:
String;
Color: TGraphVizColor;
FontColor: TGraphVizColor;
FillColor:
String;
FontSize: Integer;
FontName:
String;
ReverseDirection: Boolean;
end;
{$REGION 'Documentation'}
/// <summary>
/// Represents a single vertex in the graph
/// </summary>
{$ENDREGION}
TVertex<T> =
class( TCore<T> )
public
Name:
String;
OutputAttributes: TVertexOutputAttributes;
{$REGION 'Documentation'}
/// <summary>
/// The in-degree is used in an directed graph and determines the amount
/// of edges entering a vertex
/// </summary>
{$ENDREGION}
DegreeIn: Integer;
{$REGION 'Documentation'}
/// <summary>
/// The out-degree is used in an directed graph and determines the amount
/// of edges�leaving a vertex
/// </summary>
{$ENDREGION}
DegreeOut: Integer;
function HasAdditionalAttributes: Boolean;
override;
end;
{$REGION 'Documentation'}
/// <summary>
/// A simple ordered list of vertices
/// </summary>
{$ENDREGION}
TVertexList<T> =
class( TList < TVertex < T >> );
{$REGION 'Documentation'}
/// <summary>
/// Contains attributes to customize the output of a TEdge
/// </summary>
{$ENDREGION}
TEdgeOutputOptions =
record
Caption:
String;
Color:
String;
Style:
String;
end;
{$REGION 'Documentation'}
/// <summary>
/// Represents a single edge in the graph
/// First attribute is the data assigned to the edge
/// Second attribute is the data assigned to the vertex (should match your implementation of TVertex<V>)
/// </summary>
{$ENDREGION}
TEdge<T, V> =
class( TCore<T> )
VertexA: TVertex<V>;
VertexB: TVertex<V>;
Directed: Boolean;
Degree_Reverse: Integer;
Weight: Integer;
OutputAttributes: TEdgeOutputOptions;
constructor Create( pDirected: Boolean );
function HasAdditionalAttributes( ): Boolean;
override;
end;
TEdgeList<T, V> =
class( TList < TEdge < T, V >> );
TGraphOutputOptions =
record
NodeSep: Double;
RenderAsNonDirectedGraph: Boolean;
// Added by mc.botha
TrueColor, Splines, Overlap: Boolean;
BGColor: TGraphVizColor;
end;
EBasicGraphException =
Exception;
EDuplicateEdge =
class( EBasicGraphException );
implementation
{ TCore }
procedure TCore.ClearMarks;
begin
FreeAndNil( Marker );
end;
destructor TCore.Destroy;
begin
FreeAndNil( Marker );
inherited;
end;
function TCore.GetMark( Key:
String ): TMarker;
begin
Result := Null;
if Assigned( Marker )
then
begin
if Marker.ContainsKey( Key )
then
Result := Marker.Items[Key];
end;
end;
function TCore.HasAdditionalAttributes: Boolean;
begin
Result := False;
end;
function TCore.HasAnyMark: Boolean;
begin
Result := False;
if Assigned( Marker )
then
Result := Marker.Count > 0;
end;
function TCore.HasMark( Key:
String ): Boolean;
begin
Result := False;
if Assigned( Marker )
then
Result := Marker.ContainsKey( Key );
end;
procedure TCore.Mark( Key:
String; Value: TMarker );
begin
if not Assigned( Marker )
then
Marker := TMarkerList.Create;
if Marker.ContainsKey( Key )
then
Marker.Items[Key] := Value
else
Marker.Add( Key, Value );
end;
procedure TCore.UnMark( Key:
String );
begin
Assert( Assigned( Marker ) );
if Marker.ContainsKey( Key )
then
Marker.Remove( Key );
if Marker.Count = 0
then
FreeAndNil( Marker );
end;
{ TVertex<T> }
function TVertex<T>.HasAdditionalAttributes: Boolean;
begin
Result := ( Trim( OutputAttributes.Shape ) <> '
' )
or ( Trim( OutputAttributes.Caption ) <> '
' )
or ( Trim( OutputAttributes.Color ) <> '
' )
or
( Trim( OutputAttributes.FontColor ) <> '
' )
or ( OutputAttributes.FontSize <> 0 )
or ( OutputAttributes.ReverseDirection )
or
( Trim( OutputAttributes.FontName ) <> '
' );
end;
{ TEdge<T, V> }
constructor TEdge<T, V>.Create( pDirected: Boolean );
begin
inherited Create;
Directed := pDirected;
Weight := 1;
end;
function TEdge<T, V>.HasAdditionalAttributes: Boolean;
begin
Result := ( Trim( OutputAttributes.Caption ) <> '
' )
or ( Trim( OutputAttributes.Color ) <> '
' )
or ( Trim( OutputAttributes.Style ) <> '
' );
end;
end.