mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-19 13:39:30 +02:00
TLvlGraph: Reduce amount of BackEdges
git-svn-id: trunk@60883 -
This commit is contained in:
parent
6fac9c5998
commit
8924c68247
@ -280,7 +280,7 @@ type
|
|||||||
property LevelClass: TLvlGraphLevelClass read FLevelClass;
|
property LevelClass: TLvlGraphLevelClass read FLevelClass;
|
||||||
|
|
||||||
procedure FindIndependentGraphs;
|
procedure FindIndependentGraphs;
|
||||||
procedure CreateTopologicalLevels(HighLevels: boolean); // create levels from edges
|
procedure CreateTopologicalLevels(HighLevels, ReduceBackEdges: boolean); // create levels from edges
|
||||||
procedure SplitLongEdges(SplitMode: TLvlGraphEdgeSplitMode); // split long edges by adding hidden nodes
|
procedure SplitLongEdges(SplitMode: TLvlGraphEdgeSplitMode); // split long edges by adding hidden nodes
|
||||||
procedure ScaleNodeDrawSizes(NodeGapAbove, NodeGapBelow,
|
procedure ScaleNodeDrawSizes(NodeGapAbove, NodeGapBelow,
|
||||||
HardMaxTotal, HardMinOneNode, SoftMaxTotal, SoftMinOneNode: integer; out PixelPerWeight: single);
|
HardMaxTotal, HardMinOneNode, SoftMaxTotal, SoftMinOneNode: integer; out PixelPerWeight: single);
|
||||||
@ -300,6 +300,7 @@ type
|
|||||||
type
|
type
|
||||||
TLvlGraphCtrlOption = (
|
TLvlGraphCtrlOption = (
|
||||||
lgoAutoLayout, // automatic graph layout after graph was changed
|
lgoAutoLayout, // automatic graph layout after graph was changed
|
||||||
|
lgoReduceBackEdges, // CreateTopologicalLevels (AutoLayout) will attempts to find an order with less BackEdges
|
||||||
lgoHighLevels, // put nodes topologically at higher levels
|
lgoHighLevels, // put nodes topologically at higher levels
|
||||||
lgoHighlightNodeUnderMouse, // when mouse over node highlight node and its edges
|
lgoHighlightNodeUnderMouse, // when mouse over node highlight node and its edges
|
||||||
lgoHighlightEdgeNearMouse, // when mouse near an edge highlight edge and its edges, lgoHighlightNodeUnderMouse takes precedence
|
lgoHighlightEdgeNearMouse, // when mouse near an edge highlight edge and its edges, lgoHighlightNodeUnderMouse takes precedence
|
||||||
@ -2775,7 +2776,7 @@ begin
|
|||||||
Graph.FindIndependentGraphs;
|
Graph.FindIndependentGraphs;
|
||||||
|
|
||||||
// distribute the nodes on levels and mark back edges
|
// distribute the nodes on levels and mark back edges
|
||||||
Graph.CreateTopologicalLevels(lgoHighLevels in Options);
|
Graph.CreateTopologicalLevels(lgoHighLevels in Options, lgoReduceBackEdges in Options);
|
||||||
|
|
||||||
Graph.MarkBackEdges;
|
Graph.MarkBackEdges;
|
||||||
|
|
||||||
@ -3203,7 +3204,7 @@ begin
|
|||||||
OnSelectionChanged(Self);
|
OnSelectionChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLvlGraph.CreateTopologicalLevels(HighLevels: boolean);
|
procedure TLvlGraph.CreateTopologicalLevels(HighLevels, ReduceBackEdges: boolean);
|
||||||
var
|
var
|
||||||
ExtNodes: TAvlTree; // tree of TGraphLevelerNode sorted by Node
|
ExtNodes: TAvlTree; // tree of TGraphLevelerNode sorted by Node
|
||||||
MaxLevel: Integer;
|
MaxLevel: Integer;
|
||||||
@ -3250,6 +3251,200 @@ var
|
|||||||
ExtNode.InPath:=false;
|
ExtNode.InPath:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure DoReduceBackEdges(var MaxLevel: integer; StartLevel, SubGraphIdx: integer);
|
||||||
|
var
|
||||||
|
MaybeReduceMaxLevel: Boolean;
|
||||||
|
|
||||||
|
function IncomingBackEdgeCount(ExtReceivingNode: TGraphLevelerNode;
|
||||||
|
PretendLevel: Integer; out HasSiblingOnPretendLevel: Boolean;
|
||||||
|
out NextLowelSiblingAtLevel: integer): integer;
|
||||||
|
var
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
i, c: Integer;
|
||||||
|
ExtFromNode: TGraphLevelerNode;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
HasSiblingOnPretendLevel := False;
|
||||||
|
NextLowelSiblingAtLevel := StartLevel-1;
|
||||||
|
Node := ExtReceivingNode.Node;
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.OutEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.InEdgeCount;
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtFromNode := GetExtNode(Node.OutEdges[i].Target)
|
||||||
|
else
|
||||||
|
ExtFromNode := GetExtNode(Node.InEdges[i].Source);
|
||||||
|
if ExtFromNode.Level >= PretendLevel then // include equal => they will need to be pushed up, if the node is inserted at this level
|
||||||
|
inc(Result);
|
||||||
|
if ExtFromNode.Level = PretendLevel then
|
||||||
|
HasSiblingOnPretendLevel := True
|
||||||
|
else
|
||||||
|
if (ExtFromNode.Level > NextLowelSiblingAtLevel) and (ExtFromNode.Level < PretendLevel) then
|
||||||
|
NextLowelSiblingAtLevel := ExtFromNode.Level;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
procedure AdjustSiblingLevels(ExtAdjustNode: TGraphLevelerNode; NewLevel: integer; Force: Boolean = False);
|
||||||
|
var
|
||||||
|
i, c, OldLevel: Integer;
|
||||||
|
ExtSiblingNode: TGraphLevelerNode;
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
begin
|
||||||
|
if ExtAdjustNode.InPath then
|
||||||
|
exit;
|
||||||
|
ExtAdjustNode.InPath := True;
|
||||||
|
|
||||||
|
if (ExtAdjustNode.Level > NewLevel) and not force then begin
|
||||||
|
Node := ExtAdjustNode.Node;
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.OutEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.InEdgeCount;
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtSiblingNode := GetExtNode(Node.OutEdges[i].Target)
|
||||||
|
else
|
||||||
|
ExtSiblingNode := GetExtNode(Node.InEdges[i].Source);
|
||||||
|
if (ExtSiblingNode.Level >= NewLevel) and (ExtSiblingNode.Level < ExtAdjustNode.Level) then
|
||||||
|
NewLevel := ExtSiblingNode.Level + 1;
|
||||||
|
end;
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.InEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.OutEdgeCount;
|
||||||
|
// check backlinks
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtSiblingNode := GetExtNode(Node.InEdges[i].Source)
|
||||||
|
else
|
||||||
|
ExtSiblingNode := GetExtNode(Node.OutEdges[i].Target);
|
||||||
|
if (ExtSiblingNode.Level = NewLevel) then
|
||||||
|
NewLevel := ExtSiblingNode.Level + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (ExtAdjustNode.Level = NewLevel) and not Force then begin
|
||||||
|
ExtAdjustNode.InPath := False;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
OldLevel := ExtAdjustNode.Level;
|
||||||
|
ExtAdjustNode.Level := NewLevel;
|
||||||
|
if NewLevel > MaxLevel then
|
||||||
|
MaxLevel := NewLevel;
|
||||||
|
if OldLevel = MaxLevel then
|
||||||
|
MaybeReduceMaxLevel := True;
|
||||||
|
|
||||||
|
Node := ExtAdjustNode.Node;
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.InEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.OutEdgeCount;
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtSiblingNode := GetExtNode(Node.InEdges[i].Source)
|
||||||
|
else
|
||||||
|
ExtSiblingNode := GetExtNode(Node.OutEdges[i].Target);
|
||||||
|
if ExtSiblingNode.Level >= OldLevel then // do not adjust other BackEdges
|
||||||
|
AdjustSiblingLevels(ExtSiblingNode, NewLevel + 1);
|
||||||
|
end;
|
||||||
|
// maybe new backegdes on the InEdge side
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.OutEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.InEdgeCount;
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtSiblingNode := GetExtNode(Node.OutEdges[i].Target)
|
||||||
|
else
|
||||||
|
ExtSiblingNode := GetExtNode(Node.InEdges[i].Source);
|
||||||
|
if ExtSiblingNode.Level = NewLevel then // do not adjust other BackEdges
|
||||||
|
AdjustSiblingLevels(ExtSiblingNode, NewLevel + 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
ExtAdjustNode.InPath := False;
|
||||||
|
end;
|
||||||
|
var
|
||||||
|
AVLNode: TAVLTreeNode;
|
||||||
|
ExtNode, ExtTargetNode: TGraphLevelerNode;
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
LvlIdx, LowerLvl, BackEdgeCnt, TotalBackEdgeCnt: Integer;
|
||||||
|
i, c, j, BestLvl: integer;
|
||||||
|
BackEdgeList: array of TGraphLevelerNode;
|
||||||
|
SiblingOnLvl: Boolean;
|
||||||
|
begin
|
||||||
|
SetLength(BackEdgeList, NodeCount);
|
||||||
|
MaybeReduceMaxLevel := False;
|
||||||
|
AVLNode := ExtNodes.FindLowest;
|
||||||
|
while AVLNode <> nil do begin
|
||||||
|
ExtNode := TGraphLevelerNode(AVLNode.Data);
|
||||||
|
AVLNode := AVLNode.Successor;
|
||||||
|
Node := ExtNode.Node;
|
||||||
|
if (Node.SubGraph <> SubGraphIdx) then
|
||||||
|
Continue;
|
||||||
|
|
||||||
|
BackEdgeCnt := 0;
|
||||||
|
if HighLevels then
|
||||||
|
c := Node.InEdgeCount
|
||||||
|
else
|
||||||
|
c := Node.OutEdgeCount;
|
||||||
|
if c > Length(BackEdgeList) then
|
||||||
|
SetLength(BackEdgeList, c);
|
||||||
|
LvlIdx := ExtNode.Level;
|
||||||
|
for i := 0 to c - 1 do begin
|
||||||
|
if HighLevels then
|
||||||
|
ExtTargetNode := GetExtNode(Node.InEdges[i].Source)
|
||||||
|
else
|
||||||
|
ExtTargetNode := GetExtNode(Node.OutEdges[i].Target);
|
||||||
|
if ExtTargetNode.Level < LvlIdx then begin
|
||||||
|
j := 0;
|
||||||
|
while (j < BackEdgeCnt) and (BackEdgeList[j].Level < ExtTargetNode.Level) do
|
||||||
|
inc(j);
|
||||||
|
move(BackEdgeList[j], BackEdgeList[j+1], (BackEdgeCnt-j)*SizeOf(TGraphLevelerNode));
|
||||||
|
BackEdgeList[j] := ExtTargetNode;
|
||||||
|
inc(BackEdgeCnt);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if BackEdgeCnt = 0 then
|
||||||
|
Continue;
|
||||||
|
|
||||||
|
BestLvl := ExtNode.Level;
|
||||||
|
TotalBackEdgeCnt := BackEdgeCnt + IncomingBackEdgeCount(ExtNode, BestLvl, SiblingOnLvl, LowerLvl);
|
||||||
|
BestLvl := LowerLvl + 1;
|
||||||
|
while BackEdgeCnt > 0 do begin
|
||||||
|
dec(BackEdgeCnt);
|
||||||
|
i := BackEdgeList[BackEdgeCnt].Level;
|
||||||
|
while (BackEdgeCnt > 0) and (BackEdgeList[BackEdgeCnt - 1].Level = i) do
|
||||||
|
dec(BackEdgeCnt);
|
||||||
|
c := BackEdgeCnt + IncomingBackEdgeCount(ExtNode, i, SiblingOnLvl, LowerLvl);
|
||||||
|
if c < TotalBackEdgeCnt then begin
|
||||||
|
BestLvl := LowerLvl + 1;
|
||||||
|
TotalBackEdgeCnt := c;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if BestLvl < ExtNode.Level then begin
|
||||||
|
ExtNode.Level := BestLvl;
|
||||||
|
AdjustSiblingLevels(ExtNode, BestLvl, True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
if MaybeReduceMaxLevel then begin
|
||||||
|
MaxLevel := StartLevel;
|
||||||
|
AVLNode := ExtNodes.FindLowest;
|
||||||
|
while AVLNode <> nil do begin
|
||||||
|
ExtNode := TGraphLevelerNode(AVLNode.Data);
|
||||||
|
AVLNode := AVLNode.Successor;
|
||||||
|
if ExtNode.Node.SubGraph <> SubGraphIdx then
|
||||||
|
continue;
|
||||||
|
if ExtNode.Level > MaxLevel then
|
||||||
|
MaxLevel := ExtNode.Level;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
i, g, GroupMinLevel: Integer;
|
i, g, GroupMinLevel: Integer;
|
||||||
Node: TLvlGraphNode;
|
Node: TLvlGraphNode;
|
||||||
@ -3282,8 +3477,12 @@ begin
|
|||||||
Continue;
|
Continue;
|
||||||
Traverse(GetExtNode(Node), GroupMinLevel);
|
Traverse(GetExtNode(Node), GroupMinLevel);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if ReduceBackEdges then
|
||||||
|
DoReduceBackEdges(MaxLevel, CurrentSubGraph.FLowestLevel, CurrentSubGraph.Index);
|
||||||
CurrentSubGraph.FHighestLevel := MaxLevel;
|
CurrentSubGraph.FHighestLevel := MaxLevel;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// set levels
|
// set levels
|
||||||
LevelCount:=Max(LevelCount,MaxLevel+1);
|
LevelCount:=Max(LevelCount,MaxLevel+1);
|
||||||
for i:=0 to NodeCount-1 do begin
|
for i:=0 to NodeCount-1 do begin
|
||||||
|
Loading…
Reference in New Issue
Block a user