/// <summary> /// Returns the best path distance of the given [minDeg..maxDeg] angle set. /// If you are not sure what the inputs mean don't tinker with it. /// It uses a Golden Search algorithm. /// </summary> /// <param name="deltaDeg">What the tolerance from the perfect angle is</param> /// <exception cref="ArgumentNullException">If either <paramref name="points"/> or <paramref name="template"/> is null</exception> private static float PathDistanceAtBestAngle(List <Vector2> points, TemplateGroup.Template template, float minDeg = -45, float maxDeg = 45, float deltaDeg = 2) { if (points == null) { throw new ArgumentNullException("Points list cannot be null!"); } if (template == null) { throw new ArgumentNullException("Template cannot be null"); } // swap them if minDeg is larger than maxDeg if (maxDeg < minDeg) { float temp = minDeg; minDeg = maxDeg; maxDeg = temp; } deltaDeg = Mathf.Abs(deltaDeg); // The strategy is Golden Section Search(GSS), an efficient // algorithm that finds the minimum value in a range using the // Golden Ratio float _x1 = goldenRatio * minDeg + (1 - goldenRatio) * maxDeg; float _f1 = PathDistanceAtAngle(points, template, Mathf.Deg2Rad * _x1); float _x2 = goldenRatio * maxDeg + (1 - goldenRatio) * minDeg; float _f2 = PathDistanceAtAngle(points, template, Mathf.Deg2Rad * _x2); while (Mathf.Abs(maxDeg - minDeg) > deltaDeg) { if (_f1 < _f2) { maxDeg = _x2; _x2 = _x1; _f2 = _f1; _x1 = goldenRatio * minDeg + (1 - goldenRatio) * maxDeg; _f1 = PathDistanceAtAngle(points, template, Mathf.Deg2Rad * _x1); } else { minDeg = _x1; _x1 = _x2; _f1 = _f2; _x2 = goldenRatio * maxDeg + (1 - goldenRatio) * minDeg; _f2 = PathDistanceAtAngle(points, template, Mathf.Deg2Rad * _x2); } } return(Mathf.Min(_f1, _f2)); }
/// <summary> /// Tha path distance of a shape and a template with the shape being at a given relative rotation /// Points is compared to a template to find the average distance between corresponding points /// </summary> /// <param name="rad">Radian!!</param> /// <exception cref="ArgumentNullException">Thrown if either shape or template is null</exception> private static float PathDistanceAtAngle(List <Vector2> shape, TemplateGroup.Template template, float rad) { if (shape == null) { throw new ArgumentNullException("Shape cannot be null!"); } if (template == null) { throw new ArgumentNullException("Tempalte cannot be null!"); } return(PathDistance(RotateListToAngle(shape, rad), template)); }
/// <summary> /// Tha path distance of a shape and a template. /// Points is compared to a template to find the average distance between corresponding points /// </summary> /// <exception cref="ArgumentNullException">Thrown if either shape or template is null</exception> private static float PathDistance(List <Vector2> shape, TemplateGroup.Template template) { if (shape == null) { throw new ArgumentNullException("Shape cannot be null!"); } if (template == null) { throw new ArgumentNullException("Template cannot ben null!"); } int _pointCount = Mathf.Min(template.Points.Count, shape.Count); float _currScore = 0; for (int p = 0; p < _pointCount; p++) { _currScore += Vector2.Distance(shape[p], template.Points[p]); } return(_currScore / _pointCount); }