/// <summary> /// Measure how closely the clustering of the points matches their ideal categorization. /// </summary> /// <returns>One if the clustering matches the categorization perfectly, or a number between zero and one /// if there are deviations from a perfect clustering. The worse the clustering, the lower the number.</returns> public double Measure() { if (Points == null) { // Special case for the default constructor which composes a "perfect" result. Precision = 1.0; Recall = 1.0; } else { Precision = 0.0; Recall = 0.0; var n = Points.Count; switch (n) { case 0: Precision = double.NaN; Recall = double.NaN; break; case 1: Precision = 1; Recall = 1; break; default: Parallel.Invoke( () => Precision = Points.Average(p => AverageCorrectness(p, PointsInCluster(Cluster(p)))), () => Recall = Points.Average(p => AverageCorrectness(p, PointsInCategory(Category(p)))) ); break; } } return(BCubed); }
// Returns the best center candidate. public Point GetBestCenter() { Point bestCenter = new Point(Points.Average(point => point.X), Points.Average(point => point.Y)); double minDistance = double.MaxValue; Point result = new Point(); foreach (var point in Points) { double distance = GetDistance(point, bestCenter); if (distance < minDistance) { minDistance = distance; result = point; } } return(result); }
/// <summary> /// /// </summary> /// <param name="points">les points du contour</param> /// <param name="percentLengthTolerance">Entre 0 et 1 (0% et 100%) : tolérance en % sur la longueur des côtés du losange</param> public Quadrilateral(Point[] points, double percentLengthTolerance, double percentAngleTolerance) { // ce n'est pas un losange if (points == null || points.Length != 4) { return; } this.Points = points; this.Vectors = new Vector2[points.Length]; // coordonnées des vecteurs : Point d'arrivée - Point de départ for (int i = 0; i < 4; i++) { var i_1 = i == 3 ? 0 : i + 1; this.Vectors[i].X = points[i_1].X - points[i].X; this.Vectors[i].Y = points[i_1].Y - points[i].Y; } // magnitude des vecteurs calculés une fois pour toute Lengths = new float[4]; for (int i = 0; i < 4; i++) { Lengths[i] = Vectors[i].LengthFast; if (Lengths[i] == 0) { return; // on ne tolère pas les longueurs nulles } } // tolérance sur les côtés opposés égaux for (int i = 0; i < 2; i++) { if (Math.Abs(1 - Lengths[i] / Lengths[i + 2]) > percentLengthTolerance) { return; } } Angles = new double[4]; // calculs des angles for (int i = 0; i < 4; i++) { var i_1 = i == 0 ? 3 : i - 1; Angles[i] = Math.Atan2(Vectors[i_1].Y * Vectors[i].X - Vectors[i].Y * Vectors[i_1].X, -Vectors[i].X * Vectors[i_1].X - Vectors[i].Y * Vectors[i_1].Y); } // tolérance sur les angles opposés égaux for (int i = 0; i < 2; i++) { if (Math.Abs(1 - Angles[i] / Angles[i + 2]) > percentAngleTolerance) { return; } } Center = new Vector2((float)Points.Average((x) => x.X), (float)points.Average((x) => x.Y)); MaxLength = Lengths.Max(); AverageLength = Lengths.Average(); var vect1 = (Vectors[0] - Vectors[2]).Normalized(); var vect2 = (Vectors[1] - Vectors[3]).Normalized(); if (Math.Abs(vect1.X) > Math.Abs(vect2.X)) { //Right = new Vector2(Math.Abs(vect1.X), vect1.Y); Bottom = new Vector2(vect2.X, Math.Abs(vect2.Y)); } else { //Right = new Vector2(Math.Abs(vect2.X), vect2.Y); Bottom = new Vector2(vect1.X, Math.Abs(vect1.Y)); } IsParallelogram = true; // tolérance sur les côtés adjacents for (int i = 0; i < 3; i += 2) { if (Math.Abs(1 - Lengths[i] / Lengths[i + 1]) > percentLengthTolerance) { return; } } // tolérance sur les angles opposés égaux for (int i = 0; i < 3; i += 2) { if (Math.Abs(1 - Angles[i] / Angles[i + 1]) > percentAngleTolerance) { return; } } IsSquare = true; }