mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 19:18:14 +02:00
TLvlGraph: Minimize length of edges
git-svn-id: trunk@60884 -
This commit is contained in:
parent
8924c68247
commit
d83b4c7a53
@ -281,6 +281,7 @@ type
|
||||
|
||||
procedure FindIndependentGraphs;
|
||||
procedure CreateTopologicalLevels(HighLevels, ReduceBackEdges: boolean); // create levels from edges
|
||||
procedure MinimizeEdgeLens(HighLevels: boolean); // requires that BackEdge have been processed by procedure MarkBackEdges
|
||||
procedure SplitLongEdges(SplitMode: TLvlGraphEdgeSplitMode); // split long edges by adding hidden nodes
|
||||
procedure ScaleNodeDrawSizes(NodeGapAbove, NodeGapBelow,
|
||||
HardMaxTotal, HardMinOneNode, SoftMaxTotal, SoftMinOneNode: integer; out PixelPerWeight: single);
|
||||
@ -302,6 +303,7 @@ type
|
||||
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
|
||||
lgoMinimizeEdgeLens, // If nodes are not fixed to a level by neighbours on both side, find the level which reduces total edge len the most
|
||||
lgoHighlightNodeUnderMouse, // when mouse over node highlight node and its edges
|
||||
lgoHighlightEdgeNearMouse, // when mouse near an edge highlight edge and its edges, lgoHighlightNodeUnderMouse takes precedence
|
||||
lgoMouseSelects
|
||||
@ -734,6 +736,71 @@ type
|
||||
procedure ConsistencyCheck;
|
||||
end;
|
||||
|
||||
(** For MinimizeEdgeLens **)
|
||||
TGraphEdgeLenMinimizerTree = class;
|
||||
|
||||
{ TGraphEdgeLenMinimizerNode }
|
||||
|
||||
TGraphEdgeLenMinimizerNode = class(TAVLTreeNode)
|
||||
protected
|
||||
FTree: TGraphEdgeLenMinimizerTree;
|
||||
function GetLevel: Integer; virtual;
|
||||
procedure SetLevel(AValue: Integer); virtual;
|
||||
function GetInSibling(Index: Integer): TGraphEdgeLenMinimizerNode; virtual;
|
||||
function GetOutSibling(Index: Integer): TGraphEdgeLenMinimizerNode; virtual;
|
||||
function GetOutSiblingDistance(Index: Integer): Integer; virtual;
|
||||
class function MapLevel(ALvl, {%H-}LvlCount: Integer): integer; virtual;
|
||||
public
|
||||
Node: TLvlGraphNode;
|
||||
NextExtNodeTowardsLowerLevel: TGraphEdgeLenMinimizerNode;
|
||||
MaxLevel, LevelDiff, VisitedId: Integer;
|
||||
MinSubGraphLevel, MaxSubGraphLevel: Integer;
|
||||
(* gelOnlyPush:
|
||||
Nodes that have no shorten-able OutEdges.
|
||||
Either no OutEdges at all, or all OutEdges are directly (len=1) connected
|
||||
to another gelOnlyPush
|
||||
Only move them, to make space for a moved none-gelOnlyPush node.
|
||||
*)
|
||||
Flags: set of (gelOnlyPush);
|
||||
public
|
||||
property Level: Integer read GetLevel write SetLevel;
|
||||
function OutSiblingCount: Integer; virtual;
|
||||
property OutSibling[Index: Integer]: TGraphEdgeLenMinimizerNode read GetOutSibling;
|
||||
property OutSiblingDistance[Index: Integer]: Integer read GetOutSiblingDistance;
|
||||
function InSiblingCount: Integer; virtual;
|
||||
property InSibling[Index: Integer]: TGraphEdgeLenMinimizerNode read GetInSibling;
|
||||
end;
|
||||
|
||||
TGraphEdgeLenMinimizerNodeClass = class of TGraphEdgeLenMinimizerNode;
|
||||
|
||||
{ TGraphEdgeLenMinimizerReverseNode }
|
||||
|
||||
TGraphEdgeLenMinimizerReverseNode = class(TGraphEdgeLenMinimizerNode)
|
||||
protected
|
||||
function GetLevel: Integer; override;
|
||||
procedure SetLevel(AValue: Integer); override;
|
||||
function GetInSibling(Index: Integer): TGraphEdgeLenMinimizerNode; override;
|
||||
function GetOutSibling(Index: Integer): TGraphEdgeLenMinimizerNode; override;
|
||||
function GetOutSiblingDistance(Index: Integer): Integer; override;
|
||||
class function MapLevel(ALvl, LvlCount: Integer): integer; override;
|
||||
public
|
||||
function OutSiblingCount: Integer; override;
|
||||
function InSiblingCount: Integer; override;
|
||||
end;
|
||||
|
||||
{ TGraphEdgeLenMinimizerTree }
|
||||
|
||||
TGraphEdgeLenMinimizerTree = class(TAvlTree)
|
||||
public
|
||||
Graph: TLvlGraph;
|
||||
ExtNodeWithHighestLevel, ExtNodeWithLowestLevel :TGraphEdgeLenMinimizerNode;
|
||||
constructor Create;
|
||||
function GetTreeNode(Node: TLvlGraphNode): TGraphEdgeLenMinimizerNode;
|
||||
function AddGraphNode(Node: TLvlGraphNode): TGraphEdgeLenMinimizerNode;
|
||||
function MapLevel(ALvl: Integer): integer;
|
||||
end;
|
||||
|
||||
|
||||
procedure LvlGraphMinimizeCrossings(Graph: TLvlGraph);
|
||||
var
|
||||
g: TMinXGraph;
|
||||
@ -1046,6 +1113,141 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TGraphEdgeLenMinimizerTree }
|
||||
|
||||
function CompareEdgeLenMinimizerNodes(Node1, Node2: Pointer): integer;
|
||||
begin
|
||||
Result:=ComparePointer(Node1,Node2);
|
||||
end;
|
||||
|
||||
function CompareLGNodeWithEdgeLenMinimizerNode(GNode, ANode: Pointer): integer;
|
||||
begin
|
||||
Result:=ComparePointer(GNode,ANode);
|
||||
end;
|
||||
|
||||
constructor TGraphEdgeLenMinimizerTree.Create;
|
||||
begin
|
||||
inherited Create(@CompareEdgeLenMinimizerNodes);
|
||||
NodeClass := TGraphEdgeLenMinimizerNode;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerTree.GetTreeNode(Node: TLvlGraphNode): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result:=TGraphEdgeLenMinimizerNode(FindKey(Pointer(Node),@CompareLGNodeWithEdgeLenMinimizerNode));
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerTree.AddGraphNode(Node: TLvlGraphNode
|
||||
): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result:=TGraphEdgeLenMinimizerNode(NodeClass.Create);
|
||||
Result.FTree := Self;
|
||||
Result.Node:=Node;
|
||||
Result.Data:=Node;
|
||||
if ExtNodeWithHighestLevel = nil then
|
||||
ExtNodeWithHighestLevel := Result
|
||||
else
|
||||
ExtNodeWithLowestLevel.NextExtNodeTowardsLowerLevel := Result;
|
||||
ExtNodeWithLowestLevel := Result;
|
||||
Add(Result);
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerTree.MapLevel(ALvl: Integer): integer;
|
||||
begin
|
||||
Result := TGraphEdgeLenMinimizerNodeClass(NodeClass).MapLevel(ALvl, Graph.LevelCount);
|
||||
end;
|
||||
|
||||
{ TGraphEdgeLenMinimizerNode }
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.GetLevel: Integer;
|
||||
begin
|
||||
Result := Node.Level.Index;
|
||||
end;
|
||||
|
||||
procedure TGraphEdgeLenMinimizerNode.SetLevel(AValue: Integer);
|
||||
begin
|
||||
Node.Level := FTree.Graph.Levels[AValue];
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.GetInSibling(Index: Integer
|
||||
): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := FTree.GetTreeNode(Node.InEdges[Index].Source);
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.GetOutSiblingDistance(Index: Integer
|
||||
): Integer;
|
||||
begin
|
||||
Result := Node.OutEdges[Index].Target.Level.Index - Node.Level.Index;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.GetOutSibling(Index: Integer
|
||||
): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := FTree.GetTreeNode(Node.OutEdges[Index].Target);
|
||||
end;
|
||||
|
||||
class function TGraphEdgeLenMinimizerNode.MapLevel(ALvl, LvlCount: Integer
|
||||
): integer;
|
||||
begin
|
||||
Result := ALvl;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.OutSiblingCount: Integer;
|
||||
begin
|
||||
Result := Node.OutEdgeCount;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerNode.InSiblingCount: Integer;
|
||||
begin
|
||||
Result := Node.InEdgeCount;
|
||||
end;
|
||||
|
||||
{ TGraphEdgeLenMinimizerReverseNode }
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.GetInSibling(Index: Integer
|
||||
): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := FTree.GetTreeNode(Node.OutEdges[Index].Target);
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.GetOutSibling(Index: Integer
|
||||
): TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := FTree.GetTreeNode(Node.InEdges[Index].Source);
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.GetOutSiblingDistance(Index: Integer
|
||||
): Integer;
|
||||
begin
|
||||
Result := Node.Level.Index - Node.InEdges[Index].Source.Level.Index;
|
||||
end;
|
||||
|
||||
class function TGraphEdgeLenMinimizerReverseNode.MapLevel(ALvl,
|
||||
LvlCount: Integer): integer;
|
||||
begin
|
||||
Result := LvlCount - 1 - ALvl;
|
||||
end;
|
||||
|
||||
procedure TGraphEdgeLenMinimizerReverseNode.SetLevel(AValue: Integer);
|
||||
begin
|
||||
Node.Level := FTree.Graph.Levels[MinSubGraphLevel + MaxSubGraphLevel - AValue];
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.GetLevel: Integer;
|
||||
begin
|
||||
Result := MinSubGraphLevel + MaxSubGraphLevel - Node.Level.Index;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.OutSiblingCount: Integer;
|
||||
begin
|
||||
Result := Node.InEdgeCount;
|
||||
end;
|
||||
|
||||
function TGraphEdgeLenMinimizerReverseNode.InSiblingCount: Integer;
|
||||
begin
|
||||
Result := Node.OutEdgeCount;
|
||||
end;
|
||||
|
||||
{ TLvlGraphEdgeStyle }
|
||||
|
||||
procedure TLvlGraphEdgeStyle.SetMouseDistMax(AValue: integer);
|
||||
@ -2780,6 +2982,9 @@ begin
|
||||
|
||||
Graph.MarkBackEdges;
|
||||
|
||||
if lgoMinimizeEdgeLens in Options then
|
||||
Graph.MinimizeEdgeLens(lgoHighLevels in Options);
|
||||
|
||||
Graph.SplitLongEdges(EdgeStyle.SplitMode);
|
||||
|
||||
// permutate nodes within levels to avoid crossings
|
||||
@ -3507,6 +3712,282 @@ begin
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TLvlGraph.MinimizeEdgeLens(HighLevels: boolean);
|
||||
(* This method can only minize edges in certain graphs.
|
||||
Therefore some edges may not be fully minimized.
|
||||
|
||||
Possible TODOs
|
||||
* gelOnlyPush:
|
||||
- For Edges with len>1, check if the target node is reachable via len=1 nodes.
|
||||
If yes the edge cannot be shortened
|
||||
- Collect all InEntries for each entire group, so that CalculateCostForMoveUp can
|
||||
calculate the cost for the entire group at once.
|
||||
* Check for nodes in front of the current node, that are free to pull up.
|
||||
If a node has several InEdges, they may prevent it from moving.
|
||||
And in turn the node itself may prevent any of those sources from moving.
|
||||
*)
|
||||
var
|
||||
NodeTree: TGraphEdgeLenMinimizerTree; // tree of TGraphEdgeLenMinimizerNode sorted by Node
|
||||
VisitingId: Integer;
|
||||
|
||||
procedure UpdateMaxLevelsForSiblings(ExtNode: TGraphEdgeLenMinimizerNode);
|
||||
var
|
||||
i: Integer;
|
||||
Sibling: TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
for i := 0 to ExtNode.InSiblingCount - 1 do begin
|
||||
Sibling := ExtNode.InSibling[i];
|
||||
Sibling.MaxLevel := Min(Sibling.MaxLevel, ExtNode.MaxLevel-1);
|
||||
Assert(Sibling.MaxLevel >= Sibling.Level, 'UpdateMaxLevelsForSiblings: Sibling.MinLevel <= Sibling.Level');
|
||||
Assert(Sibling.Level < ExtNode.Level, 'UpdateMaxLevelsForSiblings: Sibling.Level > ExtNode.Level');
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure MaybeMarkOnlyPush(ExtNode: TGraphEdgeLenMinimizerNode);
|
||||
var
|
||||
i: Integer;
|
||||
Sibling: TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
for i := 0 to ExtNode.OutSiblingCount - 1 do begin
|
||||
if ExtNode.OutSiblingDistance[i] > 1 then exit;
|
||||
Sibling := ExtNode.OutSibling[i];
|
||||
assert(Sibling.Level - ExtNode.Level = 1, 'MaybeMarkOnlyPush: Dist = 1');
|
||||
if not (gelOnlyPush in Sibling.Flags) then exit;
|
||||
end;
|
||||
Include(ExtNode.Flags, gelOnlyPush);
|
||||
end;
|
||||
|
||||
function CalculateCostForMoveUp(CalcExtNode: TGraphEdgeLenMinimizerNode; var CalcNewLevel: Integer): Integer;
|
||||
function CheckInEdgeSavingsQuick(InEdgeExtNode: TGraphEdgeLenMinimizerNode; MaxSavingNeeded: Integer): Integer;
|
||||
var
|
||||
i, j, l, d, SiblingCanSave: Integer;
|
||||
InSibling, ReverseSibling: TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := 0;
|
||||
l := InEdgeExtNode.Level - 1;
|
||||
for i := 0 to InEdgeExtNode.InSiblingCount - 1 do begin
|
||||
InSibling := InEdgeExtNode.InSibling[i];
|
||||
SiblingCanSave := 0;
|
||||
if InSibling.Level < l then
|
||||
continue;
|
||||
if InSibling.InSiblingCount >= InSibling.OutSiblingCount-1 then
|
||||
continue;
|
||||
for j := 0 to InSibling.OutSiblingCount - 1 do begin
|
||||
ReverseSibling := InSibling.OutSibling[j];
|
||||
d := ReverseSibling.Level - InSibling.Level;
|
||||
if (ReverseSibling = InEdgeExtNode) then
|
||||
continue;
|
||||
if d <= 1 then
|
||||
break;
|
||||
if d < MaxSavingNeeded then
|
||||
MaxSavingNeeded := d;
|
||||
end;
|
||||
if (d <= 1) and (ReverseSibling <> InEdgeExtNode) then begin // loop aborted
|
||||
continue;
|
||||
end;
|
||||
for j := 0 to InSibling.OutSiblingCount - 1 do begin
|
||||
ReverseSibling := InSibling.OutSibling[j];
|
||||
if (ReverseSibling = InEdgeExtNode) then
|
||||
continue;
|
||||
d := ReverseSibling.Level - InSibling.Level;
|
||||
SiblingCanSave := SiblingCanSave + Min(MaxSavingNeeded, d);
|
||||
end;
|
||||
SiblingCanSave := SiblingCanSave - InSibling.InSiblingCount;
|
||||
Result := Result + max(0, SiblingCanSave);
|
||||
end;
|
||||
end;
|
||||
procedure SetNewLevelDiffRecursive(TargetExtNode: TGraphEdgeLenMinimizerNode; TargetNewLevel: Integer;
|
||||
out CostChangesAtLevel: integer);
|
||||
var
|
||||
Diff, i, SiblingCostChangesAtLevel: Integer;
|
||||
FirstMove: Boolean;
|
||||
SiblingNode: TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Assert(TargetNewLevel <= TargetExtNode.MaxLevel, 'CalculateCostForMoveUp(): TargetNewLevel < MaxLevel');
|
||||
Assert(TargetNewLevel < LevelCount, 'CalculateCostForMoveUp(): TargetNewLevel < LevelCount');
|
||||
CostChangesAtLevel := TargetExtNode.Level + 1; // Applies, if this node is NOT pushed
|
||||
Diff := TargetNewLevel - TargetExtNode.Level;
|
||||
FirstMove := TargetExtNode.VisitedId <> VisitingId; // The same node may be pushed several times, if more than one edge leads here
|
||||
TargetExtNode.VisitedId := VisitingId;
|
||||
if FirstMove then
|
||||
TargetExtNode.LevelDiff := 0
|
||||
else
|
||||
CostChangesAtLevel := TargetExtNode.MaxLevel+1; // correct limit has been applied before / in case next line does exit
|
||||
if Diff <= TargetExtNode.LevelDiff then
|
||||
exit;
|
||||
TargetExtNode.LevelDiff := Diff;
|
||||
CostChangesAtLevel := TargetExtNode.MaxLevel+1; // Best case we can go to MaxLevel, then cost goes to infinite
|
||||
if (TargetExtNode.InSiblingCount > 1) then // One InEdge is from the pushing node
|
||||
CostChangesAtLevel := TargetExtNode.Level + Diff + 1; // could be more, if the nodes can be pulled free of cost
|
||||
for i := 0 to TargetExtNode.InSiblingCount - 1 do begin
|
||||
SiblingNode := TargetExtNode.InSibling[i];
|
||||
if SiblingNode.VisitedId <> VisitingId then
|
||||
SiblingNode.LevelDiff := 0;
|
||||
end;
|
||||
for i := 0 to TargetExtNode.OutSiblingCount - 1 do begin
|
||||
SiblingNode := TargetExtNode.OutSibling[i];
|
||||
SetNewLevelDiffRecursive(SiblingNode, TargetNewLevel + 1, SiblingCostChangesAtLevel);
|
||||
if SiblingCostChangesAtLevel - 1 < CostChangesAtLevel then
|
||||
CostChangesAtLevel := SiblingCostChangesAtLevel - 1;
|
||||
end;
|
||||
end;
|
||||
function DoCalculateCostForMoveUp(ExtNode: TGraphEdgeLenMinimizerNode): Integer;
|
||||
var
|
||||
i: Integer;
|
||||
SiblingNode: TGraphEdgeLenMinimizerNode;
|
||||
begin
|
||||
Result := 0;
|
||||
if (ExtNode.VisitedId = VisitingId) or (ExtNode.LevelDiff = 0) then
|
||||
exit;
|
||||
ExtNode.VisitedId := VisitingId;
|
||||
// InEdges get longer
|
||||
for i := 0 to ExtNode.InSiblingCount - 1 do
|
||||
Result := Result + ExtNode.LevelDiff - ExtNode.InSibling[i].LevelDiff;
|
||||
for i := 0 to ExtNode.OutSiblingCount - 1 do begin
|
||||
SiblingNode := ExtNode.OutSibling[i];
|
||||
Result := Result - ExtNode.LevelDiff + SiblingNode.LevelDiff;
|
||||
Result := Result + DoCalculateCostForMoveUp(SiblingNode);
|
||||
end;
|
||||
end;
|
||||
var
|
||||
NextCostChangesAtLevel, i: Integer;
|
||||
begin
|
||||
inc(VisitingId);
|
||||
SetNewLevelDiffRecursive(CalcExtNode, CalcNewLevel, NextCostChangesAtLevel);
|
||||
dec(NextCostChangesAtLevel); // the last level use-able without extra cost
|
||||
Assert(NextCostChangesAtLevel <= CalcExtNode.MaxLevel, 'CalculateCostForMoveUp: NextCostChangesAtLevel <= CalcExtNode.MaxLevel');
|
||||
Assert(NextCostChangesAtLevel >= CalcNewLevel, 'CalculateCostForMoveUp: NextCostChangesAtLevel >= CalcNewLevel');
|
||||
if (NextCostChangesAtLevel > CalcNewLevel) and (NextCostChangesAtLevel <= CalcExtNode.MaxLevel) then begin
|
||||
CalcNewLevel := NextCostChangesAtLevel;
|
||||
inc(VisitingId);
|
||||
SetNewLevelDiffRecursive(CalcExtNode, CalcNewLevel, NextCostChangesAtLevel);
|
||||
end;
|
||||
inc(VisitingId);
|
||||
Result := DoCalculateCostForMoveUp(CalcExtNode);
|
||||
if Result >= 0 then
|
||||
Result := Result - CheckInEdgeSavingsQuick(CalcExtNode, CalcNewLevel - CalcExtNode.Level)
|
||||
else
|
||||
if Result = 0 then begin
|
||||
inc(Result); // zero cost should be moved only, if it might block on of its InEdges
|
||||
for i := 0 to CalcExtNode.InSiblingCount - 1 do begin
|
||||
if CalcExtNode.InSibling[i].Level = CalcExtNode.Level - 1 then begin
|
||||
dec(Result); // return 0 => at least one node that might be blocked
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure PushLevelUpRecursive(ExtNode: TGraphEdgeLenMinimizerNode; NewLevel: Integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Assert(NewLevel < LevelCount, 'PushLevelUpRecursive: NewLevel < LevelCount');
|
||||
if ExtNode.Level >= NewLevel then
|
||||
exit;
|
||||
ExtNode.Level:=NewLevel;
|
||||
|
||||
for i := 0 to ExtNode.OutSiblingCount - 1 do
|
||||
PushLevelUpRecursive(ExtNode.OutSibling[i], NewLevel + 1);
|
||||
end;
|
||||
|
||||
function TryMoveNode(ExtNode: TGraphEdgeLenMinimizerNode): boolean;
|
||||
var
|
||||
BestCost, ConsecutiveBadCost, Cost, BestLvl, i, mx: Integer;
|
||||
begin
|
||||
Result := False;
|
||||
BestCost := 0;
|
||||
ConsecutiveBadCost := 0;
|
||||
|
||||
mx := ExtNode.MaxLevel-1;
|
||||
i := ExtNode.Level;
|
||||
while i < mx do begin
|
||||
inc(i);
|
||||
Cost := CalculateCostForMoveUp(ExtNode, i);
|
||||
if Cost > 0 then begin
|
||||
ConsecutiveBadCost := ConsecutiveBadCost + 1;
|
||||
if ConsecutiveBadCost >= 3 then
|
||||
break; // give up
|
||||
end
|
||||
else
|
||||
if Cost <= BestCost then begin
|
||||
ConsecutiveBadCost := 0;
|
||||
BestCost := Cost;
|
||||
BestLvl := i;
|
||||
end;
|
||||
end;
|
||||
|
||||
inc(mx);
|
||||
Cost := CalculateCostForMoveUp(ExtNode, mx);
|
||||
if Cost <= BestCost then begin
|
||||
BestCost := Cost;
|
||||
BestLvl := mx;
|
||||
end;
|
||||
|
||||
//DebugLn([' BestCost: ',ExtNode.Node.Caption, ' from ', ExtNode.Level, ' to idx ', BestLvl,' (', ExtNode.Level+1 ,'..', ExtNode.MaxLevel,') cost ', BestCost ]);
|
||||
Result := BestCost < 0;
|
||||
if Result then
|
||||
PushLevelUpRecursive(ExtNode, BestLvl);
|
||||
end;
|
||||
|
||||
var
|
||||
i, l, j: Integer;
|
||||
ExtNode: TGraphEdgeLenMinimizerNode;
|
||||
DidMove: Boolean;
|
||||
CurrentSubGraph: TLvlGraphSubGraph;
|
||||
begin
|
||||
NodeTree:=TGraphEdgeLenMinimizerTree.Create;
|
||||
NodeTree.Graph:=Self;
|
||||
VisitingId := 0;
|
||||
if HighLevels then
|
||||
NodeTree.NodeClass := TGraphEdgeLenMinimizerReverseNode;
|
||||
|
||||
try
|
||||
// init NodeTree // Add highest level first, so nodes can be linked in initial order
|
||||
for j := LevelCount-1 downto 0 do begin
|
||||
l := NodeTree.MapLevel(j);
|
||||
for i := 0 to Levels[l].Count - 1 do begin
|
||||
ExtNode := NodeTree.AddGraphNode(Levels[l].Nodes[i]);
|
||||
CurrentSubGraph := SubGraphs[ExtNode.Node.SubGraph];
|
||||
ExtNode.MaxLevel := CurrentSubGraph.HighestLevel;
|
||||
ExtNode.MinSubGraphLevel := CurrentSubGraph.LowestLevel;
|
||||
ExtNode.MaxSubGraphLevel := CurrentSubGraph.HighestLevel;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Update MaxLevel
|
||||
ExtNode := NodeTree.ExtNodeWithHighestLevel;
|
||||
while ExtNode <> nil do begin
|
||||
UpdateMaxLevelsForSiblings(ExtNode);
|
||||
ExtNode := ExtNode.NextExtNodeTowardsLowerLevel;
|
||||
end;
|
||||
|
||||
// gelOnlyPush: Mark nodes, with no outgoing edges that could be shortened (push would push entire subtree)
|
||||
ExtNode := NodeTree.ExtNodeWithHighestLevel;
|
||||
while ExtNode <> nil do begin
|
||||
if ExtNode.MaxLevel > ExtNode.Level then
|
||||
MaybeMarkOnlyPush(ExtNode);
|
||||
ExtNode := ExtNode.NextExtNodeTowardsLowerLevel;
|
||||
end;
|
||||
|
||||
repeat
|
||||
DidMove := False;
|
||||
ExtNode := TGraphEdgeLenMinimizerNode(NodeTree.FindLowest);
|
||||
while ExtNode<> nil do begin
|
||||
if (ExtNode.OutSiblingCount > 0) and (ExtNode.MaxLevel > ExtNode.Level) and
|
||||
not(gelOnlyPush in ExtNode.Flags)
|
||||
then
|
||||
if TryMoveNode(ExtNode) then
|
||||
DidMove := True;
|
||||
ExtNode := TGraphEdgeLenMinimizerNode(ExtNode.Successor);
|
||||
end;
|
||||
until not DidMove;
|
||||
|
||||
finally
|
||||
NodeTree.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLvlGraph.SplitLongEdges(SplitMode: TLvlGraphEdgeSplitMode);
|
||||
// replace edges over several levels into several short edges by adding hidden nodes
|
||||
type
|
||||
|
Loading…
Reference in New Issue
Block a user