/// <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);
        }
Esempio n. 2
0
        // 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;
        }