コード例 #1
0
        // split edges longer than fMinLen
        // NOTE: basically the same as DGraph2Resampler.SplitToMaxEdgeLength, but updates
        // our internal caches. Could we merge somehow?
        protected void SplitToMaxEdgeLength(DGraph2 graph, double fMaxLen)
        {
            List <int> queue = new List <int>();
            int        NE    = graph.MaxEdgeID;

            for (int eid = 0; eid < NE; ++eid)
            {
                if (!graph.IsEdge(eid))
                {
                    continue;
                }
                Index2i ev   = graph.GetEdgeV(eid);
                double  dist = graph.GetVertex(ev.a).Distance(graph.GetVertex(ev.b));
                if (dist > fMaxLen)
                {
                    DGraph2.EdgeSplitInfo splitInfo;
                    if (graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok)
                    {
                        if (graph_cache != null)
                        {
                            graph_cache.InsertPointUnsafe(splitInfo.vNew, graph.GetVertex(splitInfo.vNew));
                        }
                        if (dist > 2 * fMaxLen)
                        {
                            queue.Add(eid);
                            queue.Add(splitInfo.eNewBN);
                        }
                    }
                }
            }
            while (queue.Count > 0)
            {
                int eid = queue[queue.Count - 1];
                queue.RemoveAt(queue.Count - 1);
                if (!graph.IsEdge(eid))
                {
                    continue;
                }
                Index2i ev   = graph.GetEdgeV(eid);
                double  dist = graph.GetVertex(ev.a).Distance(graph.GetVertex(ev.b));
                if (dist > fMaxLen)
                {
                    DGraph2.EdgeSplitInfo splitInfo;
                    if (graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok)
                    {
                        if (graph_cache != null)
                        {
                            graph_cache.InsertPointUnsafe(splitInfo.vNew, graph.GetVertex(splitInfo.vNew));
                        }
                        if (dist > 2 * fMaxLen)
                        {
                            queue.Add(eid);
                            queue.Add(splitInfo.eNewBN);
                        }
                    }
                }
            }
        }
コード例 #2
0
        public static DGraph2 perturb_fill_2(DGraph2 graphIn, GeneralPolygon2d bounds, double waveWidth, double stepSize)
        {
            DGraph2Util.Curves curves = DGraph2Util.ExtractCurves(graphIn);
            Polygon2d          poly   = curves.Loops[0];

            GeneralPolygon2dBoxTree gpTree    = new GeneralPolygon2dBoxTree(bounds);
            Polygon2dBoxTree        outerTree = new Polygon2dBoxTree(bounds.Outer);
            Polygon2dBoxTree        innerTree = new Polygon2dBoxTree(bounds.Holes[0]);

            DGraph2 graph = new DGraph2();

            graph.EnableVertexColors(Vector3f.Zero);

            graph.AppendPolygon(poly);

            DGraph2Resampler resampler = new DGraph2Resampler(graph);

            resampler.CollapseToMinEdgeLength(waveWidth);
            if (graph.VertexCount % 2 != 0)
            {
                // TODO smallest edge
                Index2i ev = graph.GetEdgeV(graph.EdgeIndices().First());
                DGraph2.EdgeCollapseInfo cinfo;
                graph.CollapseEdge(ev.a, ev.b, out cinfo);
            }


            // move to borders
            int  startv = graph.VertexIndices().First();
            int  eid    = graph.VtxEdgesItr(startv).First();
            int  curv   = startv;
            bool outer  = true;

            do
            {
                Polygon2dBoxTree use_tree = (outer) ? outerTree : innerTree;
                outer = !outer;
                graph.SetVertex(curv, use_tree.NearestPoint(graph.GetVertex(curv)));

                Index2i next = DGraph2Util.NextEdgeAndVtx(eid, curv, graph);
                eid  = next.a;
                curv = next.b;
            } while (curv != startv);



            return(graph);
        }
コード例 #3
0
        /// <summary>
        /// find nearest point to vertex in collision graph
        /// </summary>
        double MinCollisionConstraintDistance(int vid, double collision_radius)
        {
            if (collision_edge_hash == null)
            {
                return(double.MaxValue);
            }

            Vector2d pos = Graph.GetVertex(vid);
            Vector2d a = Vector2d.Zero, b = Vector2d.Zero;
            var      result = collision_edge_hash.FindNearestInSquaredRadius(pos, collision_radius * collision_radius,
                                                                             (eid) => {
                CollisionGraph.GetEdgeV(eid, ref a, ref b);
                return(Segment2d.FastDistanceSquared(ref a, ref b, ref pos));
            }
                                                                             );

            return((result.Key == -1) ? double.MaxValue : Math.Sqrt(result.Value));
        }
コード例 #4
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");
        }
コード例 #5
0
        private static DGraph2 CreateMinGraph(DGraph2 input, int NV, out Dictionary <int, List <int> > minEdgePaths, out DVector <double> edgeWeights)
        {
            /*
             * OK, as input we have a graph of our original polygon and a bunch of inserted
             * segments ("spans"). Orig polygon segments have gid < 0, and span segments >= 0.
             * However between polygon/span junctions, we have an arbitrary # of polygon edges.
             * So first step is to simplify these to single-edge "connectors", in new graph MinGraph.
             * the [connector-edge, path] mappings (if pathlen > 1) are stored in MinEdgePaths
             * We also store a weight for each connector edge in EdgeWeights (just distance for now)
             */

            var minGraph = new DGraph2();

            minEdgePaths = new Dictionary <int, List <int> >();
            edgeWeights  = new DVector <double>();
            edgeWeights.resize(NV);
            BitArray done_edge = new BitArray(input.MaxEdgeID);  // we should see each edge twice, this avoids repetition

            // vertex map from input graph to MinGraph
            int[] MapV = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                MapV[i] = -1;
            }

            for (int a = 0; a < NV; ++a)
            {
                if (input.IsVertex(a) == false || input.IsJunctionVertex(a) == false)
                {
                    continue;
                }

                if (MapV[a] == -1)
                {
                    MapV[a] = minGraph.AppendVertex(input.GetVertex(a));
                }

                foreach (int eid in input.VtxEdgesItr(a))
                {
                    if (done_edge[eid])
                    {
                        continue;
                    }

                    Index2i ev = input.GetEdgeV(eid);
                    int     b  = (ev.a == a) ? ev.b : ev.a;

                    if (input.IsJunctionVertex(b))
                    {
                        // if we have junction/juntion connection, we can just copy this edge to MinGraph

                        if (MapV[b] == -1)
                        {
                            MapV[b] = minGraph.AppendVertex(input.GetVertex(b));
                        }

                        int gid      = input.GetEdgeGroup(eid);
                        int existing = minGraph.FindEdge(MapV[a], MapV[b]);
                        if (existing == DMesh3.InvalidID)
                        {
                            int    new_eid  = minGraph.AppendEdge(MapV[a], MapV[b], gid);
                            double path_len = input.GetEdgeSegment(eid).Length;
                            edgeWeights.insertAt(path_len, new_eid);
                        }
                        else
                        {
                            // we may have inserted this edge already in the simplify branch, this happens eg at the
                            // edge of a circle where the minimal path is between the same vertices as the segment.
                            // But if this is also a fill edge, we want to treat it that way (determind via positive gid)
                            if (gid >= 0)
                            {
                                minGraph.SetEdgeGroup(existing, gid);
                            }
                        }
                    }
                    else
                    {
                        // not a junction - walk until we find other vtx, and add single edge to MinGraph
                        List <int> path = DGraph2Util.WalkToNextNonRegularVtx(input, a, eid);
                        if (path == null || path.Count < 2)
                        {
                            throw new Exception("build_min_graph: invalid walk!");
                        }

                        int c = path[path.Count - 1];

                        // it is somehow possible to get loops...
                        if (c == a)
                        {
                            goto skip_this_edge;
                        }

                        if (MapV[c] == -1)
                        {
                            MapV[c] = minGraph.AppendVertex(input.GetVertex(c));
                        }

                        if (minGraph.FindEdge(MapV[a], MapV[c]) == DMesh3.InvalidID)
                        {
                            int new_eid = minGraph.AppendEdge(MapV[a], MapV[c], -2);
                            path.Add(MapV[a]); path.Add(MapV[c]);
                            minEdgePaths[new_eid] = path;
                            double path_len = DGraph2Util.PathLength(input, path);
                            edgeWeights.insertAt(path_len, new_eid);
                        }
                    }

skip_this_edge:
                    done_edge[eid] = true;
                }
            }
            return(minGraph);
        }
コード例 #6
0
        /// <summary>
        /// Assumption is that input graph is a polygon with inserted ray-spans. We want to
        /// find a set of paths (ie no junctions) that cover all the spans, and travel between
        /// adjacent spans along edges of the input polygon.
        /// </summary>
        protected DGraph2 BuildPathGraph(DGraph2 input)
        {
            int NV = input.MaxVertexID;

            /*
             * OK, as input we have a graph of our original polygon and a bunch of inserted
             * segments ("spans"). Orig polygon segments have gid < 0, and span segments >= 0.
             * However between polygon/span junctions, we have an arbitrary # of polygon edges.
             * So first step is to simplify these to single-edge "connectors", in new graph MinGraph.
             * the [connector-edge, path] mappings (if pathlen > 1) are stored in MinEdgePaths
             * We also store a weight for each connector edge in EdgeWeights (just distance for now)
             */

            DGraph2 MinGraph = new DGraph2();
            Dictionary <int, List <int> > MinEdgePaths = new Dictionary <int, List <int> >();
            DVector <double> EdgeWeights = new DVector <double>(); EdgeWeights.resize(NV);
            BitArray         done_edge   = new BitArray(input.MaxEdgeID); // we should see each edge twice, this avoids repetition

            // vertex map from input graph to MinGraph
            int[] MapV = new int[NV];
            for (int i = 0; i < NV; ++i)
            {
                MapV[i] = -1;
            }

            for (int a = 0; a < NV; ++a)
            {
                if (input.IsVertex(a) == false || input.IsJunctionVertex(a) == false)
                {
                    continue;
                }

                if (MapV[a] == -1)
                {
                    MapV[a] = MinGraph.AppendVertex(input.GetVertex(a));
                }

                foreach (int eid in input.VtxEdgesItr(a))
                {
                    if (done_edge[eid])
                    {
                        continue;
                    }

                    Index2i ev = input.GetEdgeV(eid);
                    int     b  = (ev.a == a) ? ev.b : ev.a;

                    if (input.IsJunctionVertex(b))
                    {
                        // if we have junction/juntion connection, we can just copy this edge to MinGraph

                        if (MapV[b] == -1)
                        {
                            MapV[b] = MinGraph.AppendVertex(input.GetVertex(b));
                        }

                        int gid      = input.GetEdgeGroup(eid);
                        int existing = MinGraph.FindEdge(MapV[a], MapV[b]);
                        if (existing == DMesh3.InvalidID)
                        {
                            int    new_eid  = MinGraph.AppendEdge(MapV[a], MapV[b], gid);
                            double path_len = input.GetEdgeSegment(eid).Length;
                            EdgeWeights.insertAt(path_len, new_eid);
                        }
                        else
                        {
                            // we may have inserted this edge already in the simplify branch, this happens eg at the
                            // edge of a circle where the minimal path is between the same vertices as the segment.
                            // But if this is also a fill edge, we want to treat it that way (determind via positive gid)
                            if (gid >= 0)
                            {
                                MinGraph.SetEdgeGroup(existing, gid);
                            }
                        }
                    }
                    else
                    {
                        // not a junction - walk until we find other vtx, and add single edge to MinGraph
                        List <int> path = DGraph2Util.WalkToNextNonRegularVtx(input, a, eid);
                        if (path == null || path.Count < 2)
                        {
                            throw new Exception("build_min_graph: invalid walk!");
                        }

                        int c = path[path.Count - 1];

                        // it is somehow possible to get loops...
                        if (c == a)
                        {
                            goto skip_this_edge;
                        }

                        if (MapV[c] == -1)
                        {
                            MapV[c] = MinGraph.AppendVertex(input.GetVertex(c));
                        }

                        if (MinGraph.FindEdge(MapV[a], MapV[c]) == DMesh3.InvalidID)
                        {
                            int new_eid = MinGraph.AppendEdge(MapV[a], MapV[c], -2);
                            path.Add(MapV[a]); path.Add(MapV[c]);
                            MinEdgePaths[new_eid] = path;
                            double path_len = DGraph2Util.PathLength(input, path);
                            EdgeWeights.insertAt(path_len, new_eid);
                        }
                    }

skip_this_edge:
                    done_edge[eid] = true;
                }
            }


            // [TODO] filter MinGraph to remove invalid connectors
            //    - can a connector between two connectors happen? that would be bad.
            ///   - connector that is too close to paths should be ignored (ie avoid collisions)


            /*
             * Now that we have MinGraph, we can easily walk between the spans because
             * they are connected by at most one edge. To find a sequence of spans, we
             * pick one to start, then walk along connectors, discarding as we go,
             * so that we don't pass through these vertices again. Repeat until
             * there are no remaining spans.
             */

            // [TODO]
            //  do we actually have to delete from MinGraph? this prevents us from doing
            //  certain things, like trying different options. Maybe could use a hash for
            //  remaining vertices and edges instead?

            DGraph2  PathGraph = new DGraph2();
            Vector2d sortAxis  = Vector2d.FromAngleDeg(AngleDeg).Perp;

            while (true)
            {
                // find most extreme edge to start at
                // [TODO] could use segment gid here as we set them based on insertion span!
                // [TODO] could use a smarter metric? like, closest to previous last endpoint? Using
                //   extrema like this tends to produce longest spans, though...
                double min_dot   = double.MaxValue;
                int    start_eid = -1;
                foreach (int eid in MinGraph.EdgeIndices())
                {
                    Index3i evg = MinGraph.GetEdge(eid);
                    if (evg.c >= 0)
                    {
                        double dot = MinGraph.GetVertex(evg.a).Dot(sortAxis);
                        if (dot < min_dot)
                        {
                            min_dot   = dot;
                            start_eid = eid;
                        }
                    }
                }
                if (start_eid == -1)
                {
                    break;   // if we could not find a start edge, we must be done!
                }
                // ok now walk forward through connectors and spans. We do this in
                // connector/span pairs - we are always at an end-of-span point, and
                // we pick a next-connector and then a next-span.
                // We need to keep track of vertices in both the pathgraph and mingraph,
                // these are the "new" and "old" vertices
                Index3i start_evg = MinGraph.GetEdge(start_eid);
                int     new_start = PathGraph.AppendVertex(MinGraph.GetVertex(start_evg.a));
                int     new_prev  = PathGraph.AppendVertex(MinGraph.GetVertex(start_evg.b));
                int     old_prev  = start_evg.b;
                PathGraph.AppendEdge(new_start, new_prev, start_evg.c);
                MinGraph.RemoveVertex(start_evg.a, true);
                while (true)
                {
                    // choose next connector edge, outgoing from current vtx
                    int connector_e = -1;
                    foreach (int eid in MinGraph.VtxEdgesItr(old_prev))
                    {
                        Index3i evg = MinGraph.GetEdge(eid);
                        if (evg.c >= 0)
                        {
                            continue;  // what??
                        }
                        if (connector_e == -1 || EdgeWeights[connector_e] > EdgeWeights[eid])
                        {
                            connector_e = eid;
                        }
                    }
                    if (connector_e == -1)
                    {
                        break;
                    }

                    // find the vertex at end of connector
                    Index3i conn_evg   = MinGraph.GetEdge(connector_e);
                    int     old_conn_v = (conn_evg.a == old_prev) ? conn_evg.b : conn_evg.a;

                    // can never look at prev vertex again, or any edges connected to it
                    // [TODO] are we sure none of these edges are unused spans?!?
                    MinGraph.RemoveVertex(old_prev, true);

                    // now find outgoing span edge
                    int span_e = -1;
                    foreach (int eid in MinGraph.VtxEdgesItr(old_conn_v))
                    {
                        Index3i evg = MinGraph.GetEdge(eid);
                        if (evg.c >= 0)
                        {
                            span_e = eid;
                            break;
                        }
                    }
                    if (span_e == -1)
                    {
                        break;   // disaster!
                    }
                    // find vertex at far end of span
                    Index3i span_evg   = MinGraph.GetEdge(span_e);
                    int     old_span_v = (span_evg.a == old_conn_v) ? span_evg.b : span_evg.a;

                    // ok we want to insert the connectr to the path graph, however the
                    // connector might actually have come from a more complex path in the input graph.
                    int new_conn_next = -1;
                    if (MinEdgePaths.ContainsKey(connector_e))
                    {
                        // complex path case. Note that the order [old_prev, old_conn_v] may be the opposite
                        // of the order in the pathv. But above, we appended the [a,b] edge order to the pathv.
                        // So we can check if we need to flip, but this means we need to be a bit clever w/ indices...
                        List <int> pathv     = MinEdgePaths[connector_e];
                        int        N         = pathv.Count;
                        int        path_prev = new_prev;
                        int        k         = 1;
                        if (pathv[N - 2] != old_prev)     // case where order flipped
                        {
                            pathv.Reverse();
                            k = 3;
                        }
                        else
                        {
                            N = N - 2;
                        }
                        while (k < N)
                        {
                            int path_next = PathGraph.AppendVertex(input.GetVertex(pathv[k]));
                            PathGraph.AppendEdge(path_prev, path_next);
                            path_prev = path_next;
                            k++;
                        }
                        new_conn_next = path_prev;
                    }
                    else
                    {
                        new_conn_next = PathGraph.AppendVertex(MinGraph.GetVertex(old_conn_v));
                        PathGraph.AppendEdge(new_prev, new_conn_next, conn_evg.c);
                    }

                    // add span to path
                    int new_fill_next = PathGraph.AppendVertex(MinGraph.GetVertex(old_span_v));
                    PathGraph.AppendEdge(new_conn_next, new_fill_next, span_evg.c);

                    // remove the connector vertex
                    MinGraph.RemoveVertex(old_conn_v, true);

                    // next iter starts at far end of span
                    new_prev = new_fill_next;
                    old_prev = old_span_v;
                }

                sortAxis = -sortAxis;
            }


            // for testing/debugging
            //SVGWriter writer = new SVGWriter();
            ////writer.AddGraph(input, SVGWriter.Style.Outline("blue", 0.1f));
            //writer.AddGraph(MinGraph, SVGWriter.Style.Outline("red", 0.1f));
            ////foreach ( int eid in MinGraph.EdgeIndices() ) {
            ////    if ( MinGraph.GetEdgeGroup(eid) >= 0 )  writer.AddLine(MinGraph.GetEdgeSegment(eid), SVGWriter.Style.Outline("green", 0.07f));
            ////}
            ////writer.AddGraph(MinGraph, SVGWriter.Style.Outline("black", 0.03f));
            //writer.AddGraph(PathGraph, SVGWriter.Style.Outline("black", 0.03f));
            //foreach (int vid in PathGraph.VertexIndices()) {
            //    if (PathGraph.IsBoundaryVertex(vid))
            //        writer.AddCircle(new Circle2d(PathGraph.GetVertex(vid), 0.5f), SVGWriter.Style.Outline("blue", 0.03f));
            //}
            ////writer.AddGraph(IntervalGraph, SVGWriter.Style.Outline("black", 0.03f));
            //writer.Write("c:\\scratch\\MIN_GRAPH.svg");


            return(PathGraph);
        }
コード例 #7
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);
            }
        }