Beispiel #1
0
        private static List <LineD2DAnnotated> setConcave(LineD2DAnnotated line, List <PointD2DAnnotated> nearbyPoints, List <LineD2DAnnotated> concave_hull, double concavity, bool isSquareGrid)
        {
            /* Adds a middlepoint to a line (if there can be one) to make it concave */
            var               concave = new List <LineD2DAnnotated>();
            double            cos1, cos2;
            double            sumCos       = -2;
            PointD2DAnnotated?middle_point = null;
            bool              edgeIntersects;
            var               count      = 0;
            var               count_line = 0;

            while (count < nearbyPoints.Count)
            {
                edgeIntersects = false;
                cos1           = getCos(nearbyPoints[count], line.P0, line.P1);
                cos2           = getCos(nearbyPoints[count], line.P1, line.P0);
                if (cos1 + cos2 >= sumCos && (cos1 > concavity && cos2 > concavity))
                {
                    count_line = 0;
                    while (!edgeIntersects && count_line < concave_hull.Count)
                    {
                        edgeIntersects = (intersection(concave_hull[count_line], new LineD2DAnnotated(nearbyPoints[count], line.P0)) ||
                                          (intersection(concave_hull[count_line], new LineD2DAnnotated(nearbyPoints[count], line.P1))));
                        count_line++;
                    }
                    if (!edgeIntersects)
                    {
                        // Prevents from getting sharp angles between middlepoints
                        var nearNodes = getHullNearbyNodes(line, concave_hull);
                        if ((getCos(nearbyPoints[count], nearNodes[0], line.P0) < -concavity) &&
                            (getCos(nearbyPoints[count], nearNodes[1], line.P1) < -concavity))
                        {
                            // Prevents inner tangent lines to the concave hull
                            if (!(tangentToHull(line, nearbyPoints[count], cos1, cos2, concave_hull) && isSquareGrid))
                            {
                                sumCos       = cos1 + cos2;
                                middle_point = nearbyPoints[count];
                            }
                        }
                    }
                }
                count++;
            }
            if (middle_point == null)
            {
                concave.Add(line);
            }
            else
            {
                concave.Add(new LineD2DAnnotated(middle_point.Value, line.P0));
                concave.Add(new LineD2DAnnotated(middle_point.Value, line.P1));
            }
            return(concave);
        }
Beispiel #2
0
        private static (int minx, int miny, int maxx, int maxy) getBoundary(LineD2DAnnotated line, int scaleFactor)
        {
            /* Giving a scaleFactor it returns an area around the line
             * where we will search for nearby points
             * */
            var aNode          = line.P0;
            var bNode          = line.P1;
            var min_x_position = (int)Math.Floor(Math.Min(aNode.X, bNode.X) / scaleFactor);
            var min_y_position = (int)Math.Floor(Math.Min(aNode.Y, bNode.Y) / scaleFactor);
            var max_x_position = (int)Math.Floor(Math.Max(aNode.X, bNode.X) / scaleFactor);
            var max_y_position = (int)Math.Floor(Math.Max(aNode.Y, bNode.Y) / scaleFactor);

            return(min_x_position, min_y_position, max_x_position, max_y_position);
        }
Beispiel #3
0
        private static bool verticalIntersection(LineD2DAnnotated lineA, LineD2DAnnotated lineB)
        {
            /* lineA is vertical */
            double y_intersection;

            if ((lineB.P0.X > lineA.P0.X) && (lineA.P0.X > lineB.P1.X) ||
                ((lineB.P1.X > lineA.P0.X) && (lineA.P0.X > lineB.P0.X)))
            {
                y_intersection = (((lineB.P1.Y - lineB.P0.Y) * (lineA.P0.X - lineB.P0.X)) / (lineB.P1.X - lineB.P0.X)) + lineB.P0.Y;
                return(((lineA.P0.Y > y_intersection) && (y_intersection > lineA.P1.Y)) ||
                       ((lineA.P1.Y > y_intersection) && (y_intersection > lineA.P0.Y)));
            }
            else
            {
                return(false);
            }
        }
Beispiel #4
0
        private static bool tangentToHull(LineD2DAnnotated line_treated, PointD2DAnnotated node, double cos1, double cos2, List <LineD2DAnnotated> concave_hull)
        {
            /* A new middlepoint could (rarely) make a segment that's tangent to the hull.
             * This method detects these situations
             * I suggest turning this method of if you are not using square grids or if you have a high dot density
             * */
            var               isTangent = false;
            double            current_cos1;
            double            current_cos2;
            double            edge_length;
            var               nodes_searched = new List <int>();
            LineD2DAnnotated  line;
            PointD2DAnnotated node_in_hull;
            var               count_line = 0;
            var               count_node = 0;

            edge_length = LineD2DAnnotated.GetDistance(node, line_treated.P0) + LineD2DAnnotated.GetDistance(node, line_treated.P1);


            while (!isTangent && count_line < concave_hull.Count)
            {
                line = concave_hull[count_line];
                while (!isTangent && count_node < 2)
                {
                    node_in_hull = line[count_node];
                    if (!nodes_searched.Contains(node_in_hull.ID))
                    {
                        if (node_in_hull.ID != line_treated.P0.ID && node_in_hull.ID != line_treated.P1.ID)
                        {
                            current_cos1 = getCos(node_in_hull, line_treated.P0, line_treated.P1);
                            current_cos2 = getCos(node_in_hull, line_treated.P1, line_treated.P0);
                            if (current_cos1 == cos1 || current_cos2 == cos2)
                            {
                                isTangent = (LineD2DAnnotated.GetDistance(node_in_hull, line_treated.P0) + LineD2DAnnotated.GetDistance(node_in_hull, line_treated.P1) < edge_length);
                            }
                        }
                    }
                    nodes_searched.Add(node_in_hull.ID);
                    count_node++;
                }
                count_node = 0;
                count_line++;
            }
            return(isTangent);
        }
Beispiel #5
0
        private static PointD2DAnnotated[] getHullNearbyNodes(LineD2DAnnotated line, List <LineD2DAnnotated> concave_hull)
        {
            /* Return previous and next nodes to a line in the hull */
            var nearbyHullNodes = new PointD2DAnnotated[2];
            var leftNodeID      = line.P0.ID;
            var rightNodeID     = line.P1.ID;
            int currentID;
            var nodesFound        = 0;
            var line_count        = 0;
            var position          = 0;
            var opposite_position = 1;

            while (nodesFound < 2)
            {
                position          = 0;
                opposite_position = 1;
                while (position < 2)
                {
                    currentID = concave_hull[line_count][position].ID;
                    if (currentID == leftNodeID &&
                        concave_hull[line_count][opposite_position].ID != rightNodeID)
                    {
                        nearbyHullNodes[0] = concave_hull[line_count][opposite_position];
                        nodesFound++;
                    }
                    else if (currentID == rightNodeID &&
                             concave_hull[line_count][opposite_position].ID != leftNodeID)
                    {
                        nearbyHullNodes[1] = concave_hull[line_count][opposite_position];
                        nodesFound++;
                    }
                    position++;
                    opposite_position--;
                }
                line_count++;
            }
            return(nearbyHullNodes);
        }
Beispiel #6
0
        private static List <PointD2DAnnotated> getNearbyPoints(LineD2DAnnotated line, List <PointD2DAnnotated> nodeList, int scaleFactor)
        {
            /* The bigger the scaleFactor the more points it will return
             * Inspired by this precious algorithm:
             * http://www.it.uu.se/edu/course/homepage/projektTDB/ht13/project10/Project-10-report.pdf
             * Be carefull: if it's too small it will return very little points (or non!),
             * if it's too big it will add points that will not be used and will consume time
             * */
            var nearbyPoints = new List <PointD2DAnnotated>();
            var tries        = 0;
            int node_x_rel_pos;
            int node_y_rel_pos;

            while (tries < 2 && nearbyPoints.Count == 0)
            {
                var boundary = getBoundary(line, scaleFactor);
                foreach (var node in nodeList)
                {
                    //Not part of the line
                    if (!(node.X == line.P0.X && node.Y == line.P0.Y ||
                          node.X == line.P1.X && node.Y == line.P1.Y))
                    {
                        node_x_rel_pos = (int)Math.Floor(node.X / scaleFactor);
                        node_y_rel_pos = (int)Math.Floor(node.Y / scaleFactor);
                        //Inside the boundary
                        if (node_x_rel_pos >= boundary.minx && node_x_rel_pos <= boundary.maxx &&
                            node_y_rel_pos >= boundary.miny && node_y_rel_pos <= boundary.maxy)
                        {
                            nearbyPoints.Add(node);
                        }
                    }
                }
                //if no points are found we increase the area
                scaleFactor = scaleFactor * 4 / 3;
                tries++;
            }
            return(nearbyPoints);
        }
Beispiel #7
0
        /// <summary>
        /// Sets a concave hull with parameters that could be different from those provided in the constructor.
        /// </summary>
        /// <param name="concavity">The concavity.</param>
        /// <param name="scaleFactor">The scale factor.</param>
        /// <param name="isSquareGrid"></param>
        public void SetConcaveHull(double concavity, int scaleFactor, bool isSquareGrid)
        {
            var unused_nodes       = new List <PointD2DAnnotated>(PointsNotOnConvexHull);
            var hull_concave_edges = new List <LineD2DAnnotated>(_hull_convex_edges.OrderByDescending(a => LineD2DAnnotated.GetDistance(a.P0, a.P1)).ToList());
            LineD2DAnnotated selected_edge;
            var aux = new List <LineD2DAnnotated>();
            int list_original_size;
            var count          = 0;
            var listIsModified = false;

            do
            {
                listIsModified     = false;
                count              = 0;
                list_original_size = hull_concave_edges.Count;
                while (count < list_original_size)
                {
                    selected_edge = hull_concave_edges[0];
                    hull_concave_edges.RemoveAt(0);
                    aux = new List <LineD2DAnnotated>();
                    if (!selected_edge.IsChecked)
                    {
                        var nearby_points = getNearbyPoints(selected_edge, unused_nodes, scaleFactor);
                        aux.AddRange(setConcave(selected_edge, nearby_points, hull_concave_edges, concavity, isSquareGrid));
                        listIsModified = listIsModified || (aux.Count > 1);

                        if (aux.Count > 1)
                        {
                            foreach (var node in aux[0].Points)
                            {
                                for (var i = unused_nodes.Count - 1; i >= 0; --i)
                                {
                                    if (unused_nodes[i].ID == node.ID)
                                    {
                                        unused_nodes.RemoveAt(i);
                                    }
                                }
                            }
                        }
                        else
                        {
                            aux[0].IsChecked = true;
                        }
                    }
                    else
                    {
                        aux.Add(selected_edge);
                    }
                    hull_concave_edges.AddRange(aux);
                    count++;
                }
                hull_concave_edges = hull_concave_edges.OrderByDescending(a => LineD2DAnnotated.GetDistance(a.P0, a.P1)).ToList();
                list_original_size = hull_concave_edges.Count;
            } while (listIsModified);


            ConcaveHullPoints = GetHullPoints(hull_concave_edges);

            // free temporary allocations
            unused_nodes       = null;
            hull_concave_edges = null; // no longer needed
        }
Beispiel #8
0
        private static bool intersection(LineD2DAnnotated lineA, LineD2DAnnotated lineB)
        {
            /* Returns true if segments collide
             * If they have in common a segment edge returns false
             * Algorithm obtained from:
             * http://stackoverflow.com/questions/3838329/how-can-i-check-if-two-segments-intersect
             * Thanks OMG_peanuts !
             * */
            double dif;
            double A1, A2;
            double b1, b2;
            double X;

            if (Math.Max(lineA.P0.X, lineA.P1.X) < Math.Min(lineB.P0.X, lineB.P1.X))
            {
                return(false); //Not a chance of intersection
            }

            dif = lineA.P0.X - lineA.P1.X;
            if (dif != 0)
            { //Avoids dividing by 0
                A1 = (lineA.P0.Y - lineA.P1.Y) / dif;
            }
            else
            {
                //Segment is vertical
                A1 = 9999999;
            }

            dif = lineB.P0.X - lineB.P1.X;
            if (dif != 0)
            { //Avoids dividing by 0
                A2 = (lineB.P0.Y - lineB.P1.Y) / dif;
            }
            else
            {
                //Segment is vertical
                A2 = 9999999;
            }

            if (A1 == A2)
            {
                return(false); //Parallel
            }
            else if (A1 == 9999999)
            {
                return(verticalIntersection(lineA, lineB));
            }
            else if (A2 == 9999999)
            {
                return(verticalIntersection(lineB, lineA));
            }

            b1 = lineA.P0.Y - (A1 * lineA.P0.X);
            b2 = lineB.P0.Y - (A2 * lineB.P0.X);
            X  = Math.Round((b2 - b1) / (A1 - A2), 4);
            if ((X <= Math.Max(Math.Min(lineA.P0.X, lineA.P1.X), Math.Min(lineB.P0.X, lineB.P1.X))) ||
                (X >= Math.Min(Math.Max(lineA.P0.X, lineA.P1.X), Math.Max(lineB.P0.X, lineB.P1.X))))
            {
                return(false); //Out of bound
            }
            else
            {
                return(true);
            }
        }