/// <summary> /// Returns the boolean result (e.g. union) of 2 shapes. Boolean Operation defined by /// the inside / outside flags. /// </summary> /// <param name="Other">Other polygon.</param> /// <param name="HoledPolys">Set of polygons to recieve the result.</param> /// <param name="bThisInside">Does the operation require elements of this INSIDE the other.</param> /// <param name="bOtherInside">Does the operation require elements of the other INSIDE this.</param> /// <param name="grid">The grid with the degenerate settings.</param> public void GetBoolean(C2DHoledPolyBase Other, List<C2DHoledPolyBase> HoledPolys, bool bThisInside, bool bOtherInside, CGrid grid) { if (_Rim.Lines.Count == 0 || Other.Rim.Lines.Count == 0) return; if (_Rim.BoundingRect.Overlaps(Other.Rim.BoundingRect)) { switch (grid.DegenerateHandling) { case CGrid.eDegenerateHandling.None: { List<C2DPolyBase> CompleteHoles1 = new List<C2DPolyBase>(); List<C2DPolyBase> CompleteHoles2 = new List<C2DPolyBase>(); C2DLineBaseSetSet Routes1 = new C2DLineBaseSetSet(); C2DLineBaseSetSet Routes2 = new C2DLineBaseSetSet(); GetRoutes( this, bThisInside, Other, bOtherInside, Routes1, Routes2, CompleteHoles1, CompleteHoles2, grid); Routes1.ExtractAllOf(Routes2); if (Routes1.Count > 0) { Routes1.MergeJoining(); List<C2DPolyBase> Polygons = new List<C2DPolyBase>(); for (int i = Routes1.Count - 1; i >= 0; i--) { C2DLineBaseSet pRoute = Routes1[i]; if (pRoute.IsClosed(true) ) { Polygons.Add(new C2DPolyBase()); Polygons[Polygons.Count - 1].CreateDirect(pRoute); } else { // Debug.Assert(false); grid.LogDegenerateError(); } } C2DHoledPolyBaseSet NewComPolys = new C2DHoledPolyBaseSet(); PolygonsToHoledPolygons(NewComPolys, Polygons); NewComPolys.AddKnownHoles( CompleteHoles1 ); NewComPolys.AddKnownHoles( CompleteHoles2 ); if ( !bThisInside && !bOtherInside && NewComPolys.Count != 1) { // Debug.Assert(false); grid.LogDegenerateError(); } HoledPolys.AddRange(NewComPolys); NewComPolys.Clear(); } } break; case CGrid.eDegenerateHandling.RandomPerturbation: { C2DHoledPolyBase OtherCopy = new C2DHoledPolyBase(Other); OtherCopy.RandomPerturb(); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; GetBoolean( OtherCopy, HoledPolys, bThisInside, bOtherInside , grid ); grid.DegenerateHandling = CGrid.eDegenerateHandling.RandomPerturbation; } break; case CGrid.eDegenerateHandling.DynamicGrid: { C2DRect Rect = new C2DRect(); if (_Rim.BoundingRect.Overlaps(Other.Rim.BoundingRect, Rect)) { //double dOldGrid = CGrid::GetGridSize(); grid.SetToMinGridSize(Rect, false); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; GetBoolean( Other, HoledPolys, bThisInside, bOtherInside , grid ); grid.DegenerateHandling = CGrid.eDegenerateHandling.DynamicGrid; } } break; case CGrid.eDegenerateHandling.PreDefinedGrid: { C2DHoledPolyBase P1 = new C2DHoledPolyBase(this); C2DHoledPolyBase P2 = new C2DHoledPolyBase(Other); P1.SnapToGrid(grid); P2.SnapToGrid(grid); C2DVector V1 = new C2DVector( P1.Rim.BoundingRect.TopLeft, P2.Rim.BoundingRect.TopLeft); double dPerturbation = grid.GridSize; // ensure it snaps back to original grid positions. if (V1.i > 0) V1.i = dPerturbation; else V1.i = -dPerturbation; // move away slightly if possible if (V1.j > 0) V1.j = dPerturbation; else V1.j = -dPerturbation; // move away slightly if possible V1.i *= 0.411923;// ensure it snaps back to original grid positions. V1.j *= 0.313131;// ensure it snaps back to original grid positions. P2.Move( V1 ); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; P1.GetBoolean( P2, HoledPolys, bThisInside, bOtherInside , grid ); for (int i = 0 ; i < HoledPolys.Count ; i++) HoledPolys[i].SnapToGrid(grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; } break; case CGrid.eDegenerateHandling.PreDefinedGridPreSnapped: { C2DHoledPolyBase P2 = new C2DHoledPolyBase(Other); C2DVector V1 = new C2DVector(_Rim.BoundingRect.TopLeft, P2.Rim.BoundingRect.TopLeft); double dPerturbation = grid.GridSize; if (V1.i > 0) V1.i = dPerturbation; else V1.i = -dPerturbation; // move away slightly if possible if (V1.j > 0) V1.j = dPerturbation; else V1.j = -dPerturbation; // move away slightly if possible V1.i *= 0.411923; // ensure it snaps back to original grid positions. V1.j *= 0.313131;// ensure it snaps back to original grid positions. P2.Move( V1 ); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; GetBoolean(P2, HoledPolys, bThisInside, bOtherInside, grid); for (int i = 0; i < HoledPolys.Count; i++) HoledPolys[i].SnapToGrid(grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGridPreSnapped; } break; }// switch } }
/// <summary> /// Gets the boolean operation with the other. e.g. union / intersection. /// </summary> /// <param name="Other">The other polygon.</param> /// <param name="HoledPolys">The set to recieve the result.</param> /// <param name="bThisInside">The flag to indicate routes inside.</param> /// <param name="bOtherInside">The flag to indicate routes inside for the other.</param> /// <param name="grid">The degenerate settings.</param> public void GetBoolean(C2DPolyBase Other, List<C2DHoledPolyBase> HoledPolys, bool bThisInside, bool bOtherInside, CGrid grid) { if (BoundingRect.Overlaps(Other.BoundingRect )) { switch (grid.DegenerateHandling) { case CGrid.eDegenerateHandling.None: { C2DLineBaseSetSet Routes1 = new C2DLineBaseSetSet(); C2DLineBaseSetSet Routes2 = new C2DLineBaseSetSet(); C2DPolyBase.GetRoutes( this, bThisInside, Other, bOtherInside, Routes1, Routes2); Routes1.ExtractAllOf(Routes2); if (Routes1.Count > 0) { // Add all the joining routes together to form closed routes Routes1.MergeJoining(); // Set up some temporary polygons. List<C2DPolyBase> Polygons = new List<C2DPolyBase>(); // Turn the routes into polygons. for (int i = Routes1.Count - 1; i >= 0; i--) { if (Routes1[i].IsClosed(true) && Routes1[i].Count > 2) { Polygons.Add(new C2DPolyBase()); Polygons[Polygons.Count - 1].CreateDirect( Routes1[i]); } else { // Debug.Assert(false); grid.LogDegenerateError(); } } // Set up some temporary holed polygons C2DHoledPolyBaseSet NewComPolys = new C2DHoledPolyBaseSet(); // Turn the set of polygons into holed polygons. Not needed for intersection. if (!(bThisInside && bOtherInside)) { C2DHoledPolyBase.PolygonsToHoledPolygons(NewComPolys, Polygons); if (NewComPolys.Count != 1) { // Debug.Assert(false); grid.LogDegenerateError(); } } else { for (int i = 0; i < Polygons.Count; i++) HoledPolys.Add(new C2DHoledPolyBase(Polygons[i])); } // Now add them all to the provided set. for (int i = 0 ; i < NewComPolys.Count; i++) HoledPolys.Add(NewComPolys[i]); } } break; case CGrid.eDegenerateHandling.RandomPerturbation: { C2DPolyBase OtherCopy = new C2DPolyBase(Other); OtherCopy.RandomPerturb(); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; GetBoolean( OtherCopy, HoledPolys, bThisInside, bOtherInside, grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.RandomPerturbation; } break; case CGrid.eDegenerateHandling.DynamicGrid: { C2DRect Rect = new C2DRect(); if (this.BoundingRect.Overlaps(Other.BoundingRect, Rect)) { double dOldGrid = grid.GridSize; grid.SetToMinGridSize(Rect, false); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; GetBoolean( Other, HoledPolys, bThisInside, bOtherInside, grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.DynamicGrid; } } break; case CGrid.eDegenerateHandling.PreDefinedGrid: { C2DPolyBase P1 = new C2DPolyBase(this); C2DPolyBase P2 = new C2DPolyBase(Other); P1.SnapToGrid(grid); P2.SnapToGrid(grid); C2DVector V1 = new C2DVector( P1.BoundingRect.TopLeft, P2.BoundingRect.TopLeft); double dPerturbation = grid.GridSize; // ensure it snaps back to original grid positions. if(V1.i > 0) V1.i = dPerturbation; else V1.i = -dPerturbation; // move away slightly if possible if(V1.j > 0) V1.j = dPerturbation; else V1.j = -dPerturbation; // move away slightly if possible V1.i *= 0.411923;// ensure it snaps back to original grid positions. V1.j *= 0.313131;// ensure it snaps back to original grid positions. P2.Move( V1 ); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; P1.GetBoolean( P2, HoledPolys, bThisInside, bOtherInside, grid); for (int i = 0; i < HoledPolys.Count; i++) HoledPolys[i].SnapToGrid(grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; } break; case CGrid.eDegenerateHandling.PreDefinedGridPreSnapped: { C2DPolyBase P2 = new C2DPolyBase(Other); C2DVector V1 = new C2DVector( this.BoundingRect.TopLeft, P2.BoundingRect.TopLeft); double dPerturbation = grid.GridSize; // ensure it snaps back to original grid positions. if (V1.i > 0) V1.i = dPerturbation; else V1.i = -dPerturbation; // move away slightly if possible if (V1.j > 0) V1.j = dPerturbation; else V1.j = -dPerturbation; // move away slightly if possible V1.i *= 0.411923;// ensure it snaps back to original grid positions. V1.j *= 0.313131;// ensure it snaps back to original grid positions. P2.Move( V1 ); grid.DegenerateHandling = CGrid.eDegenerateHandling.None; GetBoolean( P2, HoledPolys, bThisInside, bOtherInside, grid); for (int i = 0; i < HoledPolys.Count; i++) HoledPolys[i].SnapToGrid(grid); grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGridPreSnapped; } break; } } }