예제 #1
0
        /// <summary>
        /// build polygons from given list of segments
        /// if want to represent arcs, add them as dummy lines to segs
        /// polys returned are ordered anticlockwise
        /// </summary>
        public static IEnumerable <IReadOnlyList <Vector3D> > ClosedPolys2D(this IEnumerable <Line3D> segs, double tolLen,
                                                                            int polyMaxPoints = 0)
        {
            var minCoord = new BBox3D(segs.SelectMany(r => new[] { r.From, r.To })).Min;

            var vcmp         = new Vector3DEqualityComparer(tolLen);
            var lcmp         = new Line3DEqualityComparer(tolLen);
            var segsDict     = segs.ToDictionary(k => k.ToString(tolLen), v => v);
            var segsFromDict = segs.GroupBy(g => g.From, v => v, vcmp).ToDictionary(k => k.Key, v => v.ToList(), vcmp);
            var segsToDict   = segs.GroupBy(g => g.To, v => v, vcmp).ToDictionary(k => k.Key, v => v.ToList(), vcmp);

            var segsLeft         = segs.OrderBy(w => w.MidPoint.Distance(minCoord)).ToList();
            var polys            = new List <List <Vector3D> >();
            var polyCentroidDone = new HashSet <Vector3D>(vcmp);

            while (segsLeft.Count > 0)
            {
                Console.WriteLine($"segsLeft: {segsLeft.Count} polys:{polys.Count}");

                var seg = segsLeft.First();
                segsLeft.Remove(seg);
                var poly = new List <Vector3D>()
                {
                    seg.From, seg.To
                };
                var rotDir = 1.0; // 1=+Z, -1=-Z
                while (true)
                {
                    List <Line3D> segsNext = null;
                    {
                        var hs = new HashSet <Line3D>(lcmp);
                        {
                            List <Line3D> tmp = null;
                            if (segsFromDict.TryGetValue(seg.To, out tmp))
                            {
                                foreach (var x in tmp.Where(r => !r.EqualsTol(tolLen, seg)))
                                {
                                    hs.Add(x);
                                }
                            }
                            if (segsToDict.TryGetValue(seg.To, out tmp))
                            {
                                foreach (var x in tmp.Where(r => !r.EqualsTol(tolLen, seg)))
                                {
                                    hs.Add(x);
                                }
                            }
                        }
                        segsNext = hs.Select(w => w.EnsureFrom(tolLen, seg.To)).ToList();
                    }

                    Line3D segNext          = null;
                    var    force_close_poly = false;

                    if (polyMaxPoints > 0 && poly.Count > polyMaxPoints)
                    {
                        throw new Exception($"polygon [{poly.PolygonSegments(tolLen).ToCadScript()}] max point exceeded");
                    }

                    //#if DEBUG

                    //                    if (//poly.Count >= 2 &&
                    //                        poly.Any(r => r.EqualsTol(1e-2, 31.0626,-0.0018))
                    //                        //&&
                    //                        //poly.Any(r => r.EqualsTol(tolLen, -42.9561, 0))
                    //                        )
                    //                        ;
                    //#endif

                    if (poly.Count == 2)
                    {
                        if (segsNext.Count == 0)
                        {
                            throw new Exception($"check singular segment [{seg}] cadscript [{seg.CadScript}]");
                        }

                        segNext = segsNext
                                  .OrderBy(w => (-seg.V).AngleRad(tolLen, w.V))
                                  .First();
                        rotDir = seg.V.CrossProduct(segNext.V).Z > 0 ? 1 : -1;
                    }
                    else
                    {
                        var qSegsNext = segsNext
                                        .Select(w => new
                        {
                            arad = (seg.V).AngleToward(tolLen, w.V, Vector3D.ZAxis * rotDir),
                            seg  = w
                        })
                                        .Where(r => r.arad <= PI).ToList();

                        if (qSegsNext.Count == 0)
                        {
                            force_close_poly = true;
                        }
                        else
                        {
                            // retrieve next segment with current rotation direction w/acutest angle
                            segNext = qSegsNext
                                      .OrderByDescending(r => r.arad)
                                      .First().seg;
                        }
                    }

                    if (force_close_poly)
                    {
                        break;
                    }

                    segsLeft.Remove(segNext);
                    if (segNext.To.EqualsTol(tolLen, poly[0]))
                    {
                        break;
                    }
                    poly.Add(segNext.To);

                    seg = segNext;
                }

                if (poly.Count > 2)
                {
                    poly = poly.SortPoly(tolLen, Vector3D.ZAxis).ToList();

                    var polyCentroid = poly.Centroid(tolLen);
                    if (!polyCentroidDone.Contains(polyCentroid))
                    {
                        polys.Add(poly);
                        polyCentroidDone.Add(polyCentroid);
                    }
                }
                else
                {
                    // todo warning
                }
            }

            return(polys.OrderByDescending(w => w.Count));
        }
예제 #2
0
파일: Line3D.cs 프로젝트: nangs/netcore-sci
        /// <summary>
        /// autointersect given list of segments
        /// ( duplicates and overlapping are removed )
        /// TODO : dummy function, optimize
        /// </summary>
        public static IReadOnlyList <Line3D> AutoIntersect(this IReadOnlyList <Line3D> segs, double tolLen,
                                                           bool mergeColinearSegments = true, IEnumerable <Vector3D> addictionalSplitPoints = null)
        {
            segs = segs.MergeColinearSegments(tolLen).ToList();

            var segCmp = new Line3DEqualityComparer(tolLen);
            var vecCmp = new Vector3DEqualityComparer(tolLen);

            // line_hs -> split points
            var splitPts = new Dictionary <Line3D, HashSet <Vector3D> >(segCmp);

            // fill splitPts dictionary with list of segments split points
            for (int i = 0; i < segs.Count; ++i)
            {
                for (int j = 0; j < segs.Count; ++j)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    var seg_i = segs[i];
                    var seg_j = segs[j];

                    var q = seg_i.Intersect(tolLen, seg_j, true, true);
                    if (q != null)
                    {
                        HashSet <Vector3D> i_hs = null;
                        HashSet <Vector3D> j_hs = null;

                        if (!q.EqualsTol(tolLen, seg_i.From) && !q.EqualsTol(tolLen, seg_i.To))
                        {
                            if (!splitPts.TryGetValue(seg_i, out i_hs))
                            {
                                i_hs = new HashSet <Vector3D>(vecCmp);
                                splitPts.Add(seg_i, i_hs);
                            }
                            i_hs.Add(q);
                        }

                        if (!q.EqualsTol(tolLen, seg_j.From) && !q.EqualsTol(tolLen, seg_j.To))
                        {
                            if (!splitPts.TryGetValue(seg_j, out j_hs))
                            {
                                j_hs = new HashSet <Vector3D>(vecCmp);
                                splitPts.Add(seg_j, j_hs);
                            }
                            j_hs.Add(q);
                        }
                    }
                }
            }

            // process addictional split points
            if (addictionalSplitPoints != null)
            {
                foreach (var pt in addictionalSplitPoints)
                {
                    foreach (var seg in segs)
                    {
                        if (seg.SegmentContainsPoint(tolLen, pt, excludeExtreme: true))
                        {
                            HashSet <Vector3D> hs = null;
                            if (!splitPts.TryGetValue(seg, out hs))
                            {
                                hs = new HashSet <Vector3D>(vecCmp);
                                splitPts.Add(seg, hs);
                            }
                            hs.Add(pt);
                        }
                    }
                }
            }

            // split segment by split points and rebuild res list
            if (splitPts.Count > 0)
            {
                HashSet <Vector3D> qSplitPts = null;
                var res = new List <Line3D>();
                for (int i = 0; i < segs.Count; ++i)
                {
                    if (splitPts.TryGetValue(segs[i], out qSplitPts))
                    {
                        res.AddRange(segs[i].Split(tolLen, qSplitPts.ToList()));
                    }
                    else
                    {
                        res.Add(segs[i]);
                    }
                }
                segs = res;
            }

            return(segs);
        }