using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Msagl.Core.Layout;
namespace Microsoft.Msagl.Layout.Incremental
{
static internal class Feasibility
{
///
/// Very small extra padding used for VPad to ensure feasibility
///
public const double Pad = 1e-4;
///
/// Obtain a starting configuration that is feasible with respect to the structural
/// constraints. This is necessary to avoid e.g. cycles in the constraint graph;
/// for example, dragging the root of a downward-pointing tree downward below other
/// nodes of the tree can result in auto-generation of constraints generating some
/// constraints with the root on the right-hand side, and the structural constraints
/// have it on the left-hand side.
///
/// When AvoidOverlaps==true and we reach ConstraintLevel>=2 then we also need to remove
/// overlaps... prior to this we need to force horizontal resolving of overlaps
/// between *all* nodes involved in vertical equality constraints (i.e. no skipping),
/// and then vertical overlap resolution of all nodes involved in horizontal equality
/// constraints
///
static internal void Enforce(FastIncrementalLayoutSettings settings, int currentConstraintLevel, IEnumerable nodes, List horizontalConstraints, List verticalConstraints, IEnumerable clusterHierarchies, Func clusterSettings)
{
foreach (LockPosition l in settings.locks)
{
l.Project();
}
ResetPositions(nodes);
double dblVpad = settings.NodeSeparation + Pad;
double dblHpad = settings.NodeSeparation;
double dblCVpad = settings.ClusterMargin + Pad;
double dblCHpad = settings.ClusterMargin;
for (int level = settings.MinConstraintLevel; level <= currentConstraintLevel; ++level)
{
// to obtain a feasible solution when equality constraints are present we need to be extra careful
// but the solution below is a little bit crummy, is not currently optimized when there are no
// equality constraints and we do not really have any scenarios involving equality constraints at
// the moment, and also the fact that it turns off DeferToVertical causes it to resolve too
// many overlaps horizontally, so let's skip it for now.
//if (level >= 2 && settings.AvoidOverlaps)
//{
// RemoveOverlapsOnEqualityConstraints(dblVpad, dblHpad, horizontalConstraints, verticalConstraints);
//}
var hsSolver = new AxisSolver(true, nodes, clusterHierarchies,
level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
hsSolver.structuralConstraints = horizontalConstraints;
hsSolver.OverlapRemovalParameters = new Core.Geometry.OverlapRemovalParameters
{
AllowDeferToVertical = true,
ConsiderProportionalOverlap = settings.IdealEdgeLength.EdgeDirectionConstraints != Core.Geometry.Directions.None
};
hsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
hsSolver.SetDesiredPositions();
hsSolver.Solve();
ResetPositions(nodes);
var vsSolver = new AxisSolver(false, nodes, clusterHierarchies,
level >= 2 && settings.AvoidOverlaps, level, clusterSettings);
vsSolver.structuralConstraints = verticalConstraints;
vsSolver.Initialize(dblHpad, dblVpad, dblCHpad, dblCVpad, v => v.Center);
vsSolver.SetDesiredPositions();
vsSolver.Solve();
ResetPositions(nodes);
}
}
/////
///// When AvoidOverlaps==true and we reach ConstraintLevel>=2 then we also need to remove
///// overlaps... prior to this we need to force horizontal resolving of overlaps
///// between *all* nodes involved in vertical equality constraints (i.e. no skipping),
///// and then vertical overlap resolution of all nodes involved in horizontal equality
///// constraints
/////
/////
/////
/////
/////
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
//static private void RemoveOverlapsOnEqualityConstraints(double dblVpad, double dblHpad, List horizontalConstraints, List verticalConstraints)
//{
// var verticalEqualityConstraints = from c in verticalConstraints
// let sc = c as VerticalSeparationConstraint
// where sc != null && sc.IsEquality
// select new { sc.BottomNode, sc.TopNode };
// var vvs = (from c in verticalEqualityConstraints
// select (FiNode)c.BottomNode.AlgorithmData).Union(
// from c in verticalEqualityConstraints
// select (FiNode)c.TopNode.AlgorithmData).AsEnumerable();
// var hSolver = new AxisSolver(true, vvs, null, true, 2);
// hSolver.OverlapRemovalParameters = new Core.Geometry.OverlapRemovalParameters
// {
// AllowDeferToVertical = false
// };
// hSolver.Initialize(dblHpad + Pad, dblVpad + Pad, 0, v=>v.Center);
// hSolver.SetDesiredPositions();
// hSolver.Solve();
// var horizontalEqualityConstraints = from c in horizontalConstraints
// let sc = c as HorizontalSeparationConstraint
// where sc != null && sc.IsEquality
// select new { sc.LeftNode, sc.RightNode };
// var hvs = (from c in horizontalEqualityConstraints
// select (FiNode)c.LeftNode.AlgorithmData).Union(
// from c in horizontalEqualityConstraints
// select (FiNode)c.RightNode.AlgorithmData).AsEnumerable();
// var vSolver = new AxisSolver(false, hvs, null, true, 2);
// vSolver.Initialize(dblHpad + Pad, dblVpad + Pad, 0, v=>v.Center);
// vSolver.SetDesiredPositions();
// vSolver.Solve();
//}
private static void ResetPositions(IEnumerable nodes)
{
foreach (FiNode v in nodes)
{
v.previousCenter = v.desiredPosition = v.mNode.Center;
}
}
}
}