Ejemplo n.º 1
0
        private void FilterSelfOverlaps(double overlapRadius, bool bResample = true)
        {
            // [RMS] this tolerance business is not workign properly right now. The problem is
            //  that decimator loses corners!

            // To simplify the computation we are going to resample the curve so that no adjacent
            // are within a given distance. Then we can use distance-to-segments, with the two adjacent
            // segments filtered out, to measure self-distance

            double dist_thresh      = overlapRadius;
            double sharp_thresh_deg = 45;

            //Profiler.Start("InitialResample");

            // resample graph. the degenerate-edge thing is necessary to
            // filter out tiny segments that are functionally sharp corners,
            // but geometrically are made of multiple angles < threshold
            // (maybe there is a better way to do this?)
            DGraph2Resampler r = new DGraph2Resampler(Graph);

            r.CollapseDegenerateEdges(overlapRadius / 10);
            if (bResample)
            {
                r.SplitToMaxEdgeLength(overlapRadius / 2);
                r.CollapseToMinEdgeLength(overlapRadius / 3);
            }
            r.CollapseDegenerateEdges(overlapRadius / 10);

            //Profiler.StopAndAccumulate("InitialResample");
            //Profiler.Start("SharpCorners");

            // find sharp corners
            List <int> sharp_corners = new List <int>();

            foreach (int vid in Graph.VertexIndices())
            {
                if (is_fixed_v(vid))
                {
                    continue;
                }
                double open_angle = Graph.OpeningAngle(vid);
                if (open_angle < sharp_thresh_deg)
                {
                    sharp_corners.Add(vid);
                }
            }

            // disconnect at sharp corners
            foreach (int vid in sharp_corners)
            {
                if (Graph.IsVertex(vid) == false)
                {
                    continue;
                }
                int      e0     = Graph.GetVtxEdges(vid)[0];
                Index2i  ev     = Graph.GetEdgeV(e0);
                int      otherv = (ev.a == vid) ? ev.b : ev.a;
                Vector2d newpos = Graph.GetVertex(vid);  //0.5 * (Graph.GetVertex(vid) + Graph.GetVertex(otherv));
                Graph.RemoveEdge(e0, false);
                int newvid = Graph.AppendVertex(newpos);
                Graph.AppendEdge(newvid, otherv);
            }

            //Profiler.StopAndAccumulate("SharpCorners");
            //Profiler.Start("HashTable");

            // build edge hash table  (cell size is just a ballpark guess here...)
            edge_hash = new SegmentHashGrid2d <int>(3 * overlapRadius, -1);
            foreach (int eid in Graph.EdgeIndices())
            {
                Segment2d seg = Graph.GetEdgeSegment(eid);
                edge_hash.InsertSegment(eid, seg.Center, seg.Extent);
            }

            if (CollisionGraph.EdgeCount > 0)
            {
                collision_edge_hash = new SegmentHashGrid2d <int>(3 * CollisionRadius, -1);
                foreach (int eid in CollisionGraph.EdgeIndices())
                {
                    Segment2d seg = CollisionGraph.GetEdgeSegment(eid);
                    collision_edge_hash.InsertSegment(eid, seg.Center, seg.Extent);
                }
            }

            //Profiler.StopAndAccumulate("HashTable");
            //Profiler.Start("Erode1");

            // Step 1: erode from boundary vertices
            List <int> boundaries = new List <int>();

            foreach (int vid in Graph.VertexIndices())
            {
                if (Graph.GetVtxEdgeCount(vid) == 1)
                {
                    boundaries.Add(vid);
                }
            }
            foreach (int vid in boundaries)
            {
                if (Graph.IsVertex(vid) == false)
                {
                    continue;
                }
                double dist           = MinSelfSegDistance(vid, 2 * dist_thresh);
                double collision_dist = MinCollisionConstraintDistance(vid, CollisionRadius);
                if (dist < dist_thresh || collision_dist < CollisionRadius)
                {
                    int eid = Graph.GetVtxEdges(vid)[0];
                    decimate_forward(vid, eid, dist_thresh);
                }
            }

            //Profiler.StopAndAccumulate("Erode1");
            //Profiler.Start("OpenAngleSort");

            //
            // Step 2: find any other possible self-overlaps and erode them.
            //

            // sort all vertices by opening angle. For any overlap, we can erode
            // on either side. Prefer to erode on side with higher curvature.
            List <Vector2d> remaining_v = new List <Vector2d>(Graph.MaxVertexID);

            foreach (int vid in Graph.VertexIndices())
            {
                if (is_fixed_v(vid))
                {
                    continue;
                }
                double open_angle = Graph.OpeningAngle(vid);
                if (open_angle == double.MaxValue)
                {
                    continue;
                }
                remaining_v.Add(new Vector2d(vid, open_angle));
            }
            remaining_v.Sort((a, b) => { return((a.y < b.y) ? -1 : (a.y > b.y ? 1 : 0)); });

            //Profiler.StopAndAccumulate("OpenAngleSort");
            //Profiler.Start("Erode2");

            // look for overlap vertices. When we find one, erode on both sides.
            foreach (Vector2d vinfo in remaining_v)
            {
                int vid = (int)vinfo.x;
                if (Graph.IsVertex(vid) == false)
                {
                    continue;
                }
                double dist = MinSelfSegDistance(vid, 2 * dist_thresh);
                if (dist < dist_thresh)
                {
                    List <int> nbrs = new List <int>(Graph.GetVtxEdges(vid));
                    foreach (int eid in nbrs)
                    {
                        if (Graph.IsEdge(eid))    // may have been decimated!
                        {
                            decimate_forward(vid, eid, dist_thresh);
                        }
                    }
                }
            }

            //Profiler.StopAndAccumulate("Erode2");
            //Profiler.Start("FlatCollapse");

            // get rid of extra vertices
            r.CollapseFlatVertices(FinalFlatCollapseAngleThreshDeg);

            //Profiler.StopAndAccumulate("FlatCollapse");
        }
Ejemplo n.º 2
0
        // collapse edges shorter than fMinLen
        // NOTE: basically the same as DGraph2Resampler.CollapseToMinEdgeLength, but updates
        // our internal caches. Could we merge somehow?
        protected void CollapseToMinEdgeLength(DGraph2 graph, double fMinLen)
        {
            double sharp_threshold_deg = 140.0f;

            double minLenSqr  = fMinLen * fMinLen;
            bool   done       = false;
            int    max_passes = 100;
            int    pass_count = 0;

            while (done == false && pass_count++ < max_passes)
            {
                done = true;

                // [RMS] do modulo-indexing here to avoid pathological cases where we do things like
                // continually collapse a short edge adjacent to a long edge (which will result in crazy over-collapse)
                int       N       = graph.MaxEdgeID;
                const int nPrime  = 31337;    // any prime will do...
                int       cur_eid = 0;
                do
                {
                    int eid = cur_eid;
                    cur_eid = (cur_eid + nPrime) % N;

                    if (!graph.IsEdge(eid))
                    {
                        continue;
                    }
                    Index2i ev = graph.GetEdgeV(eid);

                    Vector2d va      = graph.GetVertex(ev.a);
                    Vector2d vb      = graph.GetVertex(ev.b);
                    double   distSqr = va.DistanceSquared(vb);
                    if (distSqr < minLenSqr)
                    {
                        int vtx_idx = -1;    // collapse to this vertex

                        // check valences. want to preserve positions of non-valence-2
                        int na = graph.GetVtxEdgeCount(ev.a);
                        int nb = graph.GetVtxEdgeCount(ev.b);
                        if (na != 2 && nb != 2)
                        {
                            continue;
                        }
                        if (na != 2)
                        {
                            vtx_idx = 0;
                        }
                        else if (nb != 2)
                        {
                            vtx_idx = 1;
                        }

                        // check opening angles. want to preserve sharp(er) angles
                        if (vtx_idx == -1)
                        {
                            double opena = Math.Abs(graph.OpeningAngle(ev.a));
                            double openb = Math.Abs(graph.OpeningAngle(ev.b));
                            if (opena < sharp_threshold_deg && openb < sharp_threshold_deg)
                            {
                                continue;
                            }
                            else if (opena < sharp_threshold_deg)
                            {
                                vtx_idx = 0;
                            }
                            else if (openb < sharp_threshold_deg)
                            {
                                vtx_idx = 1;
                            }
                        }

                        Vector2d newPos = (vtx_idx == -1) ? 0.5 * (va + vb) : ((vtx_idx == 0) ? va : vb);

                        int keep = ev.a, remove = ev.b;
                        if (vtx_idx == 1)
                        {
                            remove = ev.a; keep = ev.b;
                        }

                        Vector2d remove_pos = graph.GetVertex(remove);
                        Vector2d keep_pos   = graph.GetVertex(keep);

                        DGraph2.EdgeCollapseInfo collapseInfo;
                        if (graph.CollapseEdge(keep, remove, out collapseInfo) == MeshResult.Ok)
                        {
                            graph_cache.RemovePointUnsafe(collapseInfo.vRemoved, remove_pos);
                            last_step_size[collapseInfo.vRemoved] = 0;
                            graph_cache.UpdatePointUnsafe(collapseInfo.vKept, keep_pos, newPos);
                            graph.SetVertex(collapseInfo.vKept, newPos);
                            done = false;
                        }
                    }
                } while (cur_eid != 0);
            }
        }