// Clasifica las líneas en horizontales, verticales y otras
        public static void Clasifier(Stroke s)
        {
            double slope = ExtraMath.Slope(s, 0);


            // Si pendiente = INFINITE => vertical_strokes
            // Si pendiente<SLOPE_MAX => horizontal_strokes
            // Si pendiente>1/SLOPE_MAX=> vertical_strokes
            // En otro caso => other_strokes

            if (slope == Facade.INFINITE)
            {
                Facade.vertical_strokes.Add(s);
            }
            else
            {
                if (slope < Facade.SLOPE_MAX)
                {
                    Facade.horizontal_strokes.Add(s);
                }
                else
                {
                    if (slope > (1 / Facade.SLOPE_MAX))
                    {
                        Facade.vertical_strokes.Add(s);
                    }
                    else
                    {
                        Facade.other_strokes.Add(s);
                    }
                }
            }
        }
예제 #2
0
        // Determina la distancia que debe existir entre los puntos muestreados
        public static double DeterminingResampleSpacing(Stroke s)
        {
            double dist_between_points;
            Point  top_left     = new Point();
            Point  bottom_right = new Point();;

            // Se obtiene el BoundingBox del Stroke
            Rectangle r = s.GetBoundingBox();

            // Se asignan a top_left la esquina superior izquierda del boundingbox,
            // y a bottom_right la esquina inferior derecha.
            top_left.X = r.Left;
            top_left.Y = r.Top;

            bottom_right.X = r.Right;
            bottom_right.Y = r.Bottom;

            // Se calcula la longitud de la diagonal formada por las dos esquinas
            // calculadas
            double diagonal = ExtraMath.Distance(bottom_right, top_left);

            // Se calcula la distancia entre los puntos muestreados
            dist_between_points = diagonal / 40.0;

            return(dist_between_points);
        }
예제 #3
0
        // Determina la distancia del tramo (no la distancia más corta)
        public static double PathDistance(List <Point> resampled, int a, int b)
        {
            double distance = 0;

            for (int i = a; i < b; i++)
            {
                distance += (double)ExtraMath.Distance(resampled[i], resampled[i + 1]);
            }
            return(distance);
        }
예제 #4
0
        // Deja los puntos del stroke que esten espaciados en dist_between_points
        public static List <Point> ResamplePoints(Stroke s, double dist_between_points)
        {
            // Se crea una lista con los puntos del stroke
            List <Point> points = new List <Point>(s.GetPoints());

            // Se añade el primer punto del stroke a la coleccion de resampled
            List <Point> resampled = new List <Point>();

            resampled.Add(points[0]);

            // Se crea un nuevo punto que se utilizara mas adelante
            Point pt = new Point();

            // Se inicializa el marcador de distancia a 0
            double distance_holder = 0;

            // Se inicializa la distancia entre dos puntos
            double distance_points = 0;

            // Se recorren todos los puntos del stroke haciendo lo siguiente
            for (int i = 1; i < points.Count; i++)
            {
                // Se calcula la distancia Euclidea entre el punto actual y el anterior
                distance_points = ExtraMath.Distance(points[i - 1], points[i]);

                if ((distance_holder + distance_points) >= dist_between_points)
                {
                    // Se crea un punto nuevo (pt) localizado aproximadamente a una distancia
                    // dist_between_points del último punto muestreado
                    pt.X = (int)(points[i - 1].X +
                                 (((dist_between_points - distance_holder) / distance_points) *
                                  (points[i].X - points[i - 1].X)));
                    pt.Y = (int)(points[i - 1].Y +
                                 (((dist_between_points - distance_holder) / distance_points) *
                                  (points[i].Y - points[i - 1].Y)));

                    // Se añade el punto pt a la lista de "resampled"
                    resampled.Add(pt);

                    // Se añade el punto pt al stroke, en la posicion anterior al punto en el
                    // que estamos
                    points.Insert(i, pt);

                    distance_holder = 0;
                }
                else
                {
                    distance_holder += distance_points;
                }
            }

            return(resampled);
        }
 /// <summary>
 /// Calculated the first time it is asked for and cached after that.
 /// </summary>
 /// <returns></returns>
 public double GetConvexPerimeter()
 {
     if (this.convexPerimeter == 0)
     {
         double perim = 0;
         for (int i = 0; i < convexPoints.Length - 1; i++)
         {
             perim += ExtraMath.Distance(convexPoints[i], convexPoints[i + 1]);
         }
         convexPerimeter = perim;
     }
     return(convexPerimeter);
 }
 /// <summary>
 /// Returns the area of the convex hull, calculated as the sum of the triangles.
 /// </summary>
 /// <returns></returns>
 public double GetConvexArea()
 {
     if (this.convexArea == 0)
     {
         double area   = 0;
         Point  point1 = convexPoints[0];
         for (int i = 1; i < convexPoints.Length - 1; i++)
         {
             area += ExtraMath.CalculateTriangularArea(point1, convexPoints[i], convexPoints[i + 1]);
         }
         convexArea = area;
     }
     return(convexArea);
 }
예제 #7
0
        // Determina si la parte del stroke indicada es una línea o no
        public static bool IsLine(List <Point> resampled, int a, int b)
        {
            double distance      = (double)ExtraMath.Distance(resampled[a], resampled[b]);
            double path_distance = (double)PathDistance(resampled, a, b);

            if ((distance / path_distance) > Facade.THRESHOLD)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Uses the Andrew variant of the Graham formula for calculating
        /// convex hulls.
        /// </summary>
        /// <param name="points"></param>
        /// <returns></returns>
        public Point[] CalculateConvexHull(Point[] points)
        {
            if (points.Length < 3)
            {
                return(points);
            }

            // TODO: Implement a quicksort algorithm, and find cut off point for switching algorithms.
            points = BubblesortPoints(points);

            List <Point> upper = new List <Point>();

            upper.Add(points[0]);
            upper.Add(points[1]);

            for (int i = 2; i < points.Length; i++)
            {
                upper.Add(points[i]);
                while (upper.Count > 2 && !ExtraMath.IsRightTurn(upper[upper.Count - 3], upper[upper.Count - 2], upper[upper.Count - 1]))
                {
                    upper.RemoveAt(upper.Count - 2);
                }
            }

            List <Point> lower = new List <Point>();

            lower.Add(points[points.Length - 1]);
            lower.Add(points[points.Length - 2]);

            for (int i = points.Length - 3; i >= 0; i--)
            {
                lower.Add(points[i]);
                while (lower.Count > 2 && !ExtraMath.IsRightTurn(lower[lower.Count - 3], lower[lower.Count - 2], lower[lower.Count - 1]))
                {
                    lower.RemoveAt(lower.Count - 2);
                }
            }
            Point[] retPoints = new Point[upper.Count + lower.Count];
            for (int i = 0; i < upper.Count; i++)
            {
                retPoints[i] = upper[i];
            }
            for (int i = 0; i < lower.Count; i++)
            {
                retPoints[i + upper.Count] = lower[i];
            }
            return(retPoints);
        }
        // Compara los strokes por longitud
        private static int CompareStrokesByLength(Stroke s1, Stroke s2)
        {
            if (s1 == null)
            {
                if (s2 == null)
                {
                    // Si s1==s2==null => son iguales
                    return(0);
                }
                else
                {
                    // Si s1==null y s2!=null, s2 es mayor
                    return(-1);
                }
            }
            else
            {
                // Si s1!=null...

                if (s2 == null)
                // ...y s2==null, s1 es mayor.
                {
                    return(1);
                }
                else
                {
                    // ... y s2!=null, comparar la longitud de los 2 strokes
                    // ExtraMath.Distance(s.GetPoint(s.GetPoints().Length-1), s.GetPoint(0))
                    double s1_length = ExtraMath.Distance(s1.GetPoint(s1.GetPoints().Length - 1), s1.GetPoint(0));
                    double s2_length = ExtraMath.Distance(s2.GetPoint(s2.GetPoints().Length - 1), s2.GetPoint(0));

                    int retval = s1_length.CompareTo(s2_length);

                    if (retval != 0)
                    {
                        // Si tienen distinta longitud, el más largo es mayor

                        return(retval);
                    }
                    else
                    {
                        // Si tienen el mismo tamaño se toma el primero como mayor

                        return(1);
                    }
                }
            }
        }
        // Determina si el stroke "n" pertenece a la relación del stroke "s"
        public static bool BelongsToRelation(Stroke s, Stroke n, int index)
        {
            float dist;

            float f_index = n.NearestPoint(s.GetPoint(index), out dist);

            double stroke_lenght = ExtraMath.Distance(s.GetPoint(s.GetPoints().Length - 1), s.GetPoint(0));

            if (dist < stroke_lenght * Facade.LENGTH_PERCENTAGE)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        public static float GetFIndex(Point pt_corner, Stroke s)
        {
            double best_distance = Facade.INFINITE;
            double distance      = Facade.INFINITE;
            float  findex        = 0;

            for (int i = 0; i < s.GetPoints().Length; i++)
            {
                distance = ExtraMath.Distance(pt_corner, s.GetPoint(i));

                if (distance < best_distance)
                {
                    best_distance = distance;
                    findex        = (float)i;
                }
            }

            return(findex);
        }
예제 #12
0
        // Busca los puntos de resampled que se corresponden con esquinas
        public static List <int> GetCorners(List <Point> resampled)
        {
            // Se crea la lista donde iran las esquinas. Almacenara un conjunto de indices
            // que referencian puntos. Por ejemplo, corner(i)=j indica que el punto(j) es
            // la i-esima esquina encontrada
            List <int> corners = new List <int>();

            corners.Add(0);

            // Se crea una lista con las distancias entre dos puntos separados W puntos del punto
            // actual
            List <double> straws = new List <double>();

            for (int i = 0; i < Facade.W; i++)
            {
                straws.Add(ExtraMath.Distance(resampled[i + Facade.W], resampled[i]));
            }

            for (int i = Facade.W; i < (resampled.Count - Facade.W); i++)
            {
                straws.Add(ExtraMath.Distance(resampled[i - Facade.W], resampled[i + Facade.W]));
            }

            for (int i = (resampled.Count - Facade.W); i < resampled.Count; i++)
            {
                straws.Add(ExtraMath.Distance(resampled[i - Facade.W], resampled[i]));
            }

            // Se calcula un umbral, threshold. Para ello, ordenamos la lista de straws y calculamos
            // su mediana. Para calcular la mediana se necesita ordenar la lista. Se trabajara con una
            // copia de la lista para no modificar la original
            List <double> copy_straws = new List <double>(straws);

            copy_straws.Sort();
            int    middle = copy_straws.Count / 2;
            double median = (copy_straws.Count % 2 != 0) ?
                            (double)copy_straws[middle] :
                            ((double)copy_straws[middle] + (double)copy_straws[middle - 1]) / 2;
            double threshold = median * 0.95;

            // Ahora se recorre la lista de straws. Si la distancia es menor que el umbral, se considera
            // esquina
            double local_min;
            int    local_min_index;

            for (int i = Facade.W; i < (resampled.Count - Facade.W); i++)
            {
                if (straws[i] < threshold)
                {
                    local_min       = Facade.INFINITE;
                    local_min_index = i;

                    while (i < straws.Count && straws[i] < threshold)
                    {
                        if (straws[i] < local_min)
                        {
                            local_min       = straws[i];
                            local_min_index = i;
                        }
                        i++;
                    }
                    corners.Add(local_min_index);
                }
            }
            // Se añade el ultimo indice a corners
            corners.Add(resampled.Count - 1);

            corners = PostProcessCorners(resampled, corners, straws);

            return(corners);
        }
        // Determina la relacion en funcion de las puntas
        //    ----------     (Ningun stroke en la punta)
        //    --------->     (Se mira el stroke de la punta más cercano al resto de la flecha,
        //                    y se miran los strokes más cercanos a dicho stroke. Si uno es la
        //                    la línea larga de la flecha se trata de una asociación direccionada)
        //    --------<>     (Los strokes más cercanos al stroke más cercano a la línea larga,
        //                    son paralelos)
        //    --------|>     (Los strokes más cercanos al stroke más cercano a la línea larga,
        //                    no son paralelos)
        public static void SearchRelationships()
        {
            // Se ordenan los strokes de menor a mayor longitud
            Facade.strokes_without_recognize.Sort(CompareStrokesByLength);

            // Se le da la vuelta para tenerlos de mayor a menor longitud
            Facade.strokes_without_recognize.Reverse();

            int i = Facade.strokes_without_recognize.Count;

            do
            {
                // Se crean los strokes n1 y n2, correspondientes a los strokes más cercanos
                // al stroke s (el primero de la lista de los strokes_without_recognize)
                Stroke n1 = null;
                Stroke n2 = null;

                // Será el stroke más cercano a "s"
                Stroke n = null;

                // Se crean los strokes nn1 y nn2, correspondientes a los strokes más cercanos
                // al stroke n
                Stroke nn1 = null;
                Stroke nn2 = null;

                // Se mira el primer stroke. Si es el único, se trata de una asociación (----)
                Stroke s = Facade.strokes_without_recognize[0];

                if (i == 1)
                {
                    MessageBox.Show("asociacion porque queda 1 stroke");
                    CreateAssociation(s);
                    i -= 1;
                }
                else
                {
                    // Se miran los strokes mas cercanos a los extremos del primer stroke
                    // (n1 para el primer extremo y n2 para el segundo)
                    NearbyStrokes(s, ref n1, ref n2, Facade.strokes_without_recognize, 1);

                    // Se comprueba que estén a menos de un 10% de la longitud del stroke
                    // inicial. Si es así, pertenecen a la relación. En caso contrario se
                    // trata de una asociación (----)( se crea la asociación y se elimina
                    // el stroke de la lista de no reconocidos)
                    bool belongs_n1 = BelongsToRelation(s, n1, 0);
                    bool belongs_n2 = BelongsToRelation(s, n2, s.GetPoints().Length - 1);

                    if (belongs_n1 == false && belongs_n2 == false)
                    {
                        MessageBox.Show("Asociacion por no belongs");
                        CreateAssociation(s);
                        i -= 1;
                    }
                    else
                    {
                        // Si no tenemos una asociación, se miran los strokes más cercanos
                        // a los dos extremos del stroke que estaba más cerca del inicial.
                        if (belongs_n1 == true)
                        {
                            n = n1;
                        }
                        if (belongs_n2 == true)
                        {
                            n = n2;
                        }

                        // Se miran los strokes mas cercanos a los extremos de "n" (nn1 para
                        // el primer extremo y nn2 para el segundo)
                        NearbyStrokes(n, ref nn1, ref nn2, Facade.strokes_without_recognize, 0);

                        // Si esos dos strokes son paralelos: ----<> (Se crea relación
                        // y se eliminan strokes de no reconocidos)
                        if (ExtraMath.AreParallels(nn1, nn2))
                        {
                            MessageBox.Show("agregacion");
                            CreateAgregation(s, n, nn1, nn2);
                            i -= 5;
                        }
                        else
                        {
                            // Si no son paralelos y si nn1 o nn2 coinciden con s: ---->
                            if (FormManager.CompareStrokes(s, nn1) || FormManager.CompareStrokes(s, nn2))
                            {
                                MessageBox.Show("asociacion direc");
                                CreateAssociationDirectional(s, n, nn1, nn2);
                                i -= 3;
                            }
                            else
                            {
                                MessageBox.Show("herencia");
                                // Si no son paralelos y ni nn1 ni nn2 coinciden con s:
                                // ----|> (Crear relación y eliminar strokes)
                                CreateGeneralization(s, n, nn1, nn2);
                                i -= 4;
                            }
                        }
                    }
                }
            } while (i > 0);
        }