using System;
using System.Collections.Generic;
using Accord.Math.Optimization;
using AutoDiff;
namespace NewPlanner
{
class AccordPlanner
{
public event Action<AccordPlanner, int> DrawProgress = delegate { };
private const double Tolerance = 0.001;
readonly NonlinearObjectiveFunction _f;
readonly List<NonlinearConstraint> _constraints;
public AccordPlanner(double startPointX, double startPointY, double startAngle, double endPointX, double endPointY, double endAngle)
{
var variables = new Variable[10];
for(int i = 0; i < variables.Length; i++)
variables[i] = new Variable();
var distanceSum = BuildDistanceTerm(variables);
_f = new NonlinearObjectiveFunction(variables.Length, ds => distanceSum.Evaluate(variables, ds), ds => distanceSum.Differentiate(variables, ds));
var sx = new NonlinearConstraint(_f, ds => variables[0].Evaluate(variables, ds), ConstraintType.EqualTo, startPointX, ds => variables[0].Differentiate(variables, ds), Tolerance);
var sy = new NonlinearConstraint(_f, ds => variables[1].Evaluate(variables, ds), ConstraintType.EqualTo, startPointY, ds => variables[1].Differentiate(variables, ds), Tolerance);
var ex = new NonlinearConstraint(_f, ds => variables[variables.Length - 2].Evaluate(variables, ds), ConstraintType.EqualTo, endPointX, ds => variables[variables.Length - 2].Differentiate(variables, ds), Tolerance);
var ey = new NonlinearConstraint(_f, ds => variables[variables.Length - 1].Evaluate(variables, ds), ConstraintType.EqualTo, endPointY, ds => variables[variables.Length - 1].Differentiate(variables, ds), Tolerance);
_constraints = new List<NonlinearConstraint>{sx, sy, ex, ey};
for (int i = 5; i < variables.Length; i += 2)
{
// one distance minus the other distance should be 0
var distanceMatch = BuildDistanceMatch(variables, i);
_constraints.Add(new NonlinearConstraint(_f, ds => distanceMatch.Evaluate(variables, ds), ConstraintType.EqualTo, 0.0, ds => distanceMatch.Differentiate(variables, ds), Tolerance));
}
}
private Term BuildDistanceMatch(Variable[] vs, int i)
{
var ydi = vs[i - 0] - vs[i - 2];
var xdi = vs[i - 1] - vs[i - 3];
var yd1 = vs[i - 2] - vs[i - 4];
var xd1 = vs[i - 3] - vs[i - 5];
return TermBuilder.Power(xdi * xdi + ydi * ydi, 0.5) - TermBuilder.Power(xd1 * xd1 + yd1 * yd1, 0.5);
}
private Term BuildDistanceTerm(Variable[] vs)
{
var ret = TermBuilder.Constant(0.0);
for (int i = 3; i < vs.Length; i += 2)
{
// add the distance between two points
var xd = vs[i - 1] - vs[i - 3];
var yd = vs[i] - vs[i - 2];
ret += TermBuilder.Power(xd * xd + yd * yd, 0.5);
}
return ret;
}
public void Run()
{
var solver = new AugmentedLagrangianSolver(_f.NumberOfVariables, _constraints);
var rand = new Random(42);
for (int i = 0; i < solver.Solution.Length; i++)
{
solver.Solution[i] = rand.NextDouble() * 500;
}
// you can fill in the initial values of the Solution property
var minimum = solver.Minimize(_f);
}
}
}