using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Msagl.Core.Geometry;
using Microsoft.Msagl.Core.Layout;
using Microsoft.Msagl.Layout.Incremental;
namespace Microsoft.Msagl.Prototype.Constraints {
///
/// This doesn't work yet, but it will be a constraint that aligns nodes, optionally to some fixed orientation (horizontal, vertical, 45 degrees, etc).
///
public class AlignmentConstraint : IConstraint {
List nodes;
///
/// Create an alignment constraint for the given set of nodes
///
///
public AlignmentConstraint(IEnumerable nodes) {
this.nodes = nodes.ToList();
}
void leastSquaresLineFit(out double a, out double b) {
double mx = 0, my = 0, sx2 = 0, sy2 = 0, sxy=0, n = nodes.Count;
foreach (var v in nodes) {
double x = v.Center.X, y = v.Center.Y;
mx += x;
my += y;
sx2 += x * x;
sy2 += y * y;
sxy += x * y;
}
mx /= n;
my /= n;
double B = 0.5*((sy2 - n * my * my) - (sx2 - n * mx * mx)) / (n * mx * my - sxy);
b = Math.Sqrt(B * B + 1) - B;
//b = - Math.Sqrt(B * B + 1) - B;
a = my - b * mx;
}
#region IConstraint Members
///
/// project using a perpendicular least-squares fit
///
///
public double Project() {
double a, b, d=0;
leastSquaresLineFit(out a, out b);
// project to the line y = a + b x
foreach (var v in nodes) {
double x0 = v.Center.X, y0 = v.Center.Y;
double x = (b * y0 + x0 ) / (b * b + 1.0);
double y = a + b * x;
Point p = new Point(x, y);
d = (v.Center - p).Length;
v.Center = p;
}
return d;
}
///
/// level 1
///
public int Level {
get { return 1; }
}
///
/// Get the list of nodes involved in the constraint
///
public IEnumerable Nodes { get { return nodes;} }
#endregion
}
}