private static bool UncertainSolution(RelPos2D Pos1, RelPos2D Pos2, RelPos2D Pos3) { RelPos2D[] array = new RelPos2D[] { Pos1, Pos2, Pos3 }; return ((array.Contains(RelPos2D.ll) && array.Contains(RelPos2D.gg)) || (array.Contains(RelPos2D.lg) && array.Contains(RelPos2D.gl))); }
public Tuple <Point3D, Point3D, Point3D> Solve(Point3D Target, params Point3D[] Points) { Dictionary <Point3D, double> distanceToTarget = new Dictionary <Point3D, double>(); Dictionary <Point3D, RelPos2D> relativePosition = new Dictionary <Point3D, RelPos2D>(); List <int> visited = new List <int>(); Dictionary <RelPos2D, int> countPerPosition = new Dictionary <RelPos2D, int>() { { RelPos2D.ee, 0 }, { RelPos2D.eg, 0 }, { RelPos2D.el, 0 }, { RelPos2D.ge, 0 }, { RelPos2D.gg, 0 }, { RelPos2D.gl, 0 }, { RelPos2D.le, 0 }, { RelPos2D.lg, 0 }, { RelPos2D.ll, 0 } }; foreach (var point in Points) { distanceToTarget.Add(point, TrianglePointTools.Distance(point, Target)); RelPos2D position = TrianglePointTools.RelativePosition(point, Target); relativePosition.Add(point, position); countPerPosition[position]++; } //check countPerPosition to see if there are solutions int pointsCount = Points.Length; bool noSolutions = false; foreach (var key in countPerPosition.Keys) { if (countPerPosition[key] == pointsCount) { noSolutions = true; break; } } noSolutions = noSolutions || countPerPosition[RelPos2D.ll] + countPerPosition[RelPos2D.le] + countPerPosition[RelPos2D.lg] == pointsCount || countPerPosition[RelPos2D.lg] + countPerPosition[RelPos2D.eg] + countPerPosition[RelPos2D.gg] == pointsCount || countPerPosition[RelPos2D.gg] + countPerPosition[RelPos2D.ge] + countPerPosition[RelPos2D.gl] == pointsCount || countPerPosition[RelPos2D.ll] + countPerPosition[RelPos2D.el] + countPerPosition[RelPos2D.gl] == pointsCount; if (noSolutions) { throw new Exception("No solutions."); } var orderedPoints = Points.OrderBy(point => distanceToTarget[point]); bool found = false; Point3D Point1 = null, Point2 = null, Point3 = null; RelPos2D PosPoint1, PosPoint2, PosPoint3; foreach (var point1 in orderedPoints) { Point1 = point1; PosPoint1 = relativePosition[Point1]; var point2Candidates = orderedPoints.Where(p => p != Point1) .OrderBy(p => distanceToTarget[p]); //this should not happen because we know that we have at least one solution if (point2Candidates.Count() == 0) { continue; } foreach (var point2 in point2Candidates) { Point2 = point2; PosPoint2 = relativePosition[Point2]; var point3ValidPositions = ValidPositions(PosPoint1, PosPoint2); var point3Candidates = orderedPoints.Where(p => p != Point1 && p != Point2 && point3ValidPositions.Contains(relativePosition[p])) .OrderBy(p => distanceToTarget[p]); if (point3Candidates.Count() == 0) { continue; } foreach (var point3 in point3Candidates) { Point3 = point3; PosPoint3 = relativePosition[Point3]; //check if already visited //hash subject to conflicts var hash = Point1.GetHashCode() * Point2.GetHashCode() * Point3.GetHashCode(); if (visited.Contains(hash)) { continue; } if (UncertainSolution(PosPoint1, PosPoint2, PosPoint3)) { found = TrianglePointTools.TriangleContainsPoint(Point1, Point2, Point3, Target); } else { found = true; } if (found) { break; } visited.Add(hash); } if (found) { break; } } if (found) { break; } } if (found) { return(new Tuple <Point3D, Point3D, Point3D>(Point1, Point2, Point3)); } throw new Exception("No solutions."); }
private static RelPos2D[] ValidPositions(RelPos2D Pos1, RelPos2D Pos2) { if (Pos1 == RelPos2D.ee || Pos2 == RelPos2D.ee) { return(AllPositions); } switch (Pos1) { case RelPos2D.ll: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg }); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge }); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl }); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl, RelPos2D.el }); case RelPos2D.gg: return(AllPositions); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg }); } break; case RelPos2D.le: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge }); case RelPos2D.le: return(NoPositions); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl }); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl, RelPos2D.el }); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl, RelPos2D.el, RelPos2D.ll }); case RelPos2D.ge: return(AllPositions.Except(new RelPos2D[] { Pos1, Pos2 }).ToArray()); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg }); } break; case RelPos2D.lg: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl }); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl }); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl }); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el }); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el, RelPos2D.ll }); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el, RelPos2D.ll, RelPos2D.le }); case RelPos2D.gl: return(AllPositions); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl }); } break; case RelPos2D.eg: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl, RelPos2D.el }); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl, RelPos2D.el }); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el }); case RelPos2D.eg: return(NoPositions); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll }); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll, RelPos2D.le }); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll, RelPos2D.le, RelPos2D.lg }); case RelPos2D.el: return(AllPositions.Except(new RelPos2D[] { Pos1, Pos2 }).ToArray()); } break; case RelPos2D.gg: switch (Pos2) { case RelPos2D.ll: return(AllPositions); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ge, RelPos2D.gl, RelPos2D.el, RelPos2D.ll }); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el, RelPos2D.ll }); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll }); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll }); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le }); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le, RelPos2D.lg }); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le, RelPos2D.lg, RelPos2D.eg }); } break; case RelPos2D.ge: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.le: return(AllPositions.Except(new RelPos2D[] { Pos1, Pos2 }).ToArray()); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.gl, RelPos2D.el, RelPos2D.ll, RelPos2D.le }); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll, RelPos2D.le }); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le }); case RelPos2D.ge: return(NoPositions); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg }); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg, RelPos2D.eg }); } break; case RelPos2D.gl: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg, RelPos2D.gg, RelPos2D.ge }); case RelPos2D.lg: return(AllPositions); case RelPos2D.eg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.el, RelPos2D.ll, RelPos2D.le, RelPos2D.lg }); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le, RelPos2D.lg }); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg }); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg }); case RelPos2D.el: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg }); } break; case RelPos2D.el: switch (Pos2) { case RelPos2D.ll: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg }); case RelPos2D.le: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg, RelPos2D.ge }); case RelPos2D.lg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.eg, RelPos2D.gg, RelPos2D.ge, RelPos2D.gl }); case RelPos2D.eg: return(AllPositions.Except(new RelPos2D[] { Pos1, Pos2 }).ToArray()); case RelPos2D.gg: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.ll, RelPos2D.le, RelPos2D.lg, RelPos2D.eg }); case RelPos2D.ge: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.le, RelPos2D.lg, RelPos2D.eg }); case RelPos2D.gl: return(new RelPos2D[] { RelPos2D.ee, RelPos2D.lg, RelPos2D.eg }); case RelPos2D.el: return(NoPositions); } break; } return(NoPositions); }