Exemple #1
0
        private void BuildInner()
        {
            var tri       = D.LastTri;
            var dIdxsDone = new HashSet <int>();

            var hullIdxs = new HashSet <int>(D.HullEdges.Select(_edge => _edge.OriginIdx));

            var progState  = "Voronoi Build Inner Sites...";
            var prog       = 0f;
            var trisTotal  = D.Triangles().Length; //TODO not fast
            var triProgCnt = 0;

            //Build Inner Sites
            while (tri.PrevTri != null)
            {
                prog      = (float)triProgCnt++ / trisTotal;
                progState = "Voronoi Inner Tri " + triProgCnt + " of " + trisTotal;
                D.Prog.Update(prog, progState);

                var edges = new[] { tri.Edge0, tri.Edge1, tri.Edge2 };
                for (var eIdx = 0; eIdx < 3; ++eIdx)
                {
                    var edge     = edges[eIdx];
                    var edgeOIdx = edge.OriginIdx;
                    if (dIdxsDone.Contains(edgeOIdx))
                    {
                        continue;
                    }
                    dIdxsDone.Add(edgeOIdx);
                    if (hullIdxs.Contains(edgeOIdx))
                    {
                        continue;
                    }

                    var ptsCW    = new List <Vector2>();
                    var twins    = new List <Site.HalfEdge>();
                    var scanEdge = edge;
                    do
                    {
                        var cc = new Vector2(scanEdge.Triangle.CCX, scanEdge.Triangle.CCY);
                        ptsCW.Add(cc);
                        Bounds.Encapsulate(cc);
                        //Get and set twin
                        scanEdge = scanEdge.NextEdge.NextEdge;
                        Site.HalfEdge nbrScan = null;
                        if (SitesByDIdx.ContainsKey(scanEdge.OriginIdx))
                        {
                            var nbrSite = SitesByDIdx[scanEdge.OriginIdx];
                            //Get nbr Origin match
                            nbrScan = nbrSite.FirstEdge;
                            while (nbrScan.NextEdge.Origin != cc)
                            {
                                nbrScan = nbrScan.NextEdge;
                            }
                        }

                        twins.Add(nbrScan);
                        scanEdge = scanEdge.Twin;
                    } while (scanEdge != edge);


                    var site = new Site(ptsCW, twins, true);
                    SitesByDIdx.Add(edgeOIdx, site);
                }

                tri = tri.PrevTri;
            }
        }
Exemple #2
0
        private void BuildOuter()
        {
            var progState  = "Voronoi Build Outer...";
            var prog       = 0f;
            var infEdgeLen = (D.BoundsRect.width + D.BoundsRect.height) / 4f; //TODO
            var hullEdges  = D.HullEdges;

            Site.HalfEdge lastTwin = null;
            for (var heIdx = 0; heIdx < hullEdges.Count; ++heIdx)
            {
                prog = (float)heIdx / hullEdges.Count;
                D.Prog.Update(prog, progState);

                var edge = hullEdges[heIdx];
                var nextEdgeOriginPos = edge.NextEdge.OriginPos;
                var edgeOIdx          = edge.OriginIdx;

                var ptsCW = new List <Vector2>();
                var twins = new List <Site.HalfEdge> {
                    null
                };
                var scanEdge = edge;

                //Project first edge perpendicular to hull edge
                var perpHullVec = GetPerpendicularLeft(edge.OriginPos, nextEdgeOriginPos).normalized;
                perpHullVec *= infEdgeLen;

                var cc1          = new Vector2(scanEdge.Triangle.CCX, scanEdge.Triangle.CCY);
                var firstEdgePos = cc1 + perpHullVec;
                Bounds.Encapsulate(firstEdgePos);
                ptsCW.Add(firstEdgePos);

                //Build middle edges

                while (true)
                {
                    var cc = new Vector2(scanEdge.Triangle.CCX, scanEdge.Triangle.CCY);
                    ptsCW.Add(cc);
                    Bounds.Encapsulate(cc);
                    //Get and set twin
                    scanEdge = scanEdge.NextEdge.NextEdge;
                    if (scanEdge.Twin == null)
                    {
                        break;
                    }
                    Site.HalfEdge nbrScan = null;
                    if (SitesByDIdx.ContainsKey(scanEdge.OriginIdx))
                    {
                        var nbrSite = SitesByDIdx[scanEdge.OriginIdx];
                        //Get nbr Origin match
                        nbrScan = nbrSite.FirstEdge;
                        while (nbrScan.NextEdge.Origin != cc)
                        {
                            nbrScan = nbrScan.NextEdge;
                        }
                    }

                    twins.Add(nbrScan);
                    scanEdge = scanEdge.Twin;
                }

                //Add last twin
                twins.Add(lastTwin);

                //Project last edge perpendicular to hull edge
                perpHullVec  = GetPerpendicularLeft(scanEdge.OriginPos, scanEdge.NextEdge.OriginPos).normalized;
                perpHullVec *= infEdgeLen;

                var ccLast      = new Vector2(scanEdge.Triangle.CCX, scanEdge.Triangle.CCY);
                var lastEdgePos = ccLast + perpHullVec;
                Bounds.Encapsulate(lastEdgePos);
                ptsCW.Add(lastEdgePos);
                twins.Add(null);

                var site = new Site(ptsCW, twins, false); //TODO store dIDX?
                lastTwin = twins[0];
                SitesByDIdx.Add(edgeOIdx, site);
            }
        }
Exemple #3
0
        public void TrimSitesToBndry(Rect _bndry, bool _closeAtTrim = true)
        {
            var trimBnds = _bndry;

            //Scan for sites needing trim and for removal
            var sitesToTrim   = new HashSet <int>();
            var sitesToRemove = new HashSet <int>();

            //Progress
            var idxCnt    = 0;
            var idxCntTot = SitesByDIdx.Keys.Count;
            var progState = "Voronoi Trimming Sites - Scanning";
            var prog      = 0f;

            foreach (var dIdx in SitesByDIdx.Keys)
            {
                prog      = (float)idxCnt++ / idxCntTot;
                progState = "Voronoi Trimming Sites - Scanning " + idxCnt + " of " + idxCntTot;
                D.Prog.Update(prog, progState);

                var site      = SitesByDIdx[dIdx];
                var wasClosed = site.Closed;
                site.Closed = true;

                var scanEdge = site.FirstEdge;
                var hasIn    = false;
                var hasOut   = false;
                do
                {
                    if (trimBnds.Contains(scanEdge.Origin))
                    {
                        hasIn = true;
                    }
                    else
                    {
                        hasOut = true;
                    }
                    scanEdge = scanEdge.NextEdge;
                } while (scanEdge != site.FirstEdge);

                if (hasIn && hasOut)
                {
                    sitesToTrim.Add(dIdx);
                }
                else if (hasOut && !hasIn)
                {
                    sitesToRemove.Add(dIdx);
                }

                site.Closed = wasClosed;
            }

            var bndyOrigin = new Dictionary <BndSide, Vector2>
            {
                { BndSide.Up, trimBnds.min },
                { BndSide.Right, new Vector2(trimBnds.xMin, trimBnds.yMax) },
                { BndSide.Down, trimBnds.max },
                { BndSide.Left, new Vector2(trimBnds.xMax, trimBnds.yMin) }
            };

            //Trim Sites

            //Progress
            var idxTrimCur = 0;
            var idxTrimTot = sitesToTrim.Count;

            foreach (var dIdx in sitesToTrim)
            {
                prog      = (float)idxTrimCur / idxTrimTot;
                progState = "Voronoi Trimming Sites - Trimming " + idxTrimCur + " of " + idxTrimTot;
                D.Prog.Update(prog, progState);

                var site = SitesByDIdx[dIdx];
                site.Closed = true;

                var scanEdge = site.FirstEdge;
                while (!trimBnds.Contains(scanEdge.Origin))
                {
                    scanEdge = scanEdge.NextEdge;
                }

                //Find exit bnds intersection
                while (trimBnds.Contains(scanEdge.NextEdge.Origin))
                {
                    scanEdge = scanEdge.NextEdge;
                }

                var     exitEdge = scanEdge;
                var     intFrom  = exitEdge.Origin;
                var     intVec   = exitEdge.NextEdge.Origin - intFrom;
                BndSide exitSide;

                var exitIntPt = GetIntersectionToBndy(intFrom, intVec, trimBnds, out exitSide);

                //Find enter bnds interection
                while (!trimBnds.Contains(scanEdge.NextEdge.Origin))
                {
                    scanEdge = scanEdge.NextEdge;
                }

                var enterEdge = scanEdge;
                intFrom = enterEdge.NextEdge.Origin;
                intVec  = enterEdge.Origin - intFrom;
                BndSide enterSide;

                var enterIntPt = GetIntersectionToBndy(intFrom, intVec, trimBnds, out enterSide);

                if (exitSide == enterSide || !_closeAtTrim)
                {
                    var newBndEdge = new Site.HalfEdge(exitIntPt);
                    exitEdge.NextEdge   = newBndEdge;
                    newBndEdge.NextEdge = enterEdge;
                    enterEdge.Origin    = enterIntPt;
                    site.FirstEdge      = enterEdge;
                }
                else
                {
                    var newBndEdgeA = new Site.HalfEdge(exitIntPt);
                    var newBndEdgeB = new Site.HalfEdge(bndyOrigin[enterSide]);
                    exitEdge.NextEdge    = newBndEdgeA;
                    newBndEdgeA.NextEdge = newBndEdgeB;
                    enterEdge.Origin     = enterIntPt;
                    newBndEdgeB.NextEdge = enterEdge;
                    site.FirstEdge       = enterEdge;
                }


                site.Closed = _closeAtTrim;
            }

            //Clean up sites outside of boundary
            foreach (var dIdx in sitesToRemove) //TODO need to do more than remove from sites list? (Memory)
            {
                var site = SitesByDIdx[dIdx];

                foreach (var edge in site.Edges)
                {
                    edge.NextEdge = null;
                    edge.Twin     = null;
                }

                site.FirstEdge = null;

                SitesByDIdx.Remove(dIdx);
            }
        }