/// <summary> /// Purpose: insert right-going edges into the edge dictionary, and update /// winding numbers and mesh connectivity appropriately. All right-going /// edges share a common origin vOrg. Edges are inserted CCW starting at /// eFirst; the last edge inserted is eLast.Oprev. If vOrg has any /// left-going edges already processed, then eTopLeft must be the edge /// such that an imaginary upward vertical segment from vOrg would be /// contained between eTopLeft.Oprev and eTopLeft; otherwise eTopLeft /// should be null. /// </summary> private void AddRightEdges(ActiveRegion regUp, MeshUtils.Edge eFirst, MeshUtils.Edge eLast, MeshUtils.Edge eTopLeft, bool cleanUp) { bool firstTime = true; MeshUtils.Edge e = eFirst; do { Debug.Assert(Geom.VertLeq(e._Org, e._Dst)); AddRegionBelow(regUp, e._Sym); e = e._Onext; } while (e != eLast); eTopLeft = eTopLeft switch { // Walk *all* right-going edges from e.Org, in the dictionary order, // updating the winding numbers of each region, and re-linking the mesh // edges to match the dictionary ordering (if necessary). null => RegionBelow(regUp)._eUp._Rprev, _ => eTopLeft }; ActiveRegion regPrev = regUp, reg; MeshUtils.Edge ePrev = eTopLeft; while (true) { reg = RegionBelow(regPrev); e = reg._eUp._Sym; if (e._Org != ePrev._Org) { break; } if (e._Onext != ePrev) { // Unlink e from its current position, and relink below ePrev Mesh.Splice(_pool, e._Oprev, e); Mesh.Splice(_pool, ePrev._Oprev, e); } // Compute the winding number and "inside" flag for the new regions reg._windingNumber = regPrev._windingNumber - e._winding; reg._inside = Geom.IsWindingInside(_windingRule, reg._windingNumber); // Check for two outgoing edges with same slope -- process these // before any intersection tests (see example in tessComputeInterior). regPrev._dirty = true; switch (firstTime) { case false when CheckForRightSplice(regPrev): Geom.AddWinding(e, ePrev); DeleteRegion(regPrev); Mesh.Delete(_pool, ePrev); break; } firstTime = false; regPrev = reg; ePrev = e; } regPrev._dirty = true; Debug.Assert(regPrev._windingNumber - e._winding == reg._windingNumber); switch (cleanUp) { case true: // Check for intersections between newly adjacent edges. WalkDirtyRegions(regPrev); break; } }
private void ComputeWinding(ActiveRegion reg) { reg._windingNumber = RegionAbove(reg)._windingNumber + reg._eUp._winding; reg._inside = Geom.IsWindingInside(_windingRule, reg._windingNumber); }