/// <summary> /// Snaps this to the conceptual grid. /// </summary> public abstract void SnapToGrid(CGrid grid);
/// <summary> /// Snaps this to the conceptual grid. /// </summary> /// <param name="grid">Grid to snap to.</param> public override void SnapToGrid(CGrid grid) { P1.SnapToGrid(grid); P2.SnapToGrid(grid); P3.SnapToGrid(grid); }
/// <summary> /// Gets the union of the 2 shapes. /// </summary> /// <param name="Other">The other shape.</param> /// <param name="Polygons">The set to recieve the result.</param> /// <param name="grid">The degenerate settings.</param> public void GetUnion(C2DHoledPolygon Other, List<C2DHoledPolygon> Polygons, CGrid grid) { List<C2DHoledPolyBase> NewPolys = new List<C2DHoledPolyBase>(); base.GetUnion(Other, NewPolys, grid); for (int i = 0; i < NewPolys.Count; i++) Polygons.Add(new C2DHoledPolygon(NewPolys[i])); }
/// <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> /// Snaps this to the conceptual grid. /// </summary> /// <param name="grid">Grid to snap to.</param> public override void SnapToGrid(CGrid grid) { TopLeft.SnapToGrid(grid); BottomRight.SnapToGrid(grid); }
/// <summary> /// Returns the difference between this and the other polygon. /// </summary> /// <param name="Other">Other polygon.</param> /// <param name="HoledPolys">Set to receieve all the resulting polygons.</param> /// <param name="grid">Grid containing the degenerate handling settings.</param> public void GetNonOverlaps(C2DHoledPolyBase Other, List<C2DHoledPolyBase> HoledPolys, CGrid grid) { GetBoolean(Other, HoledPolys, false, true, grid); }
/// <summary> /// Returns the routes (multiple lines or part polygons) either inside or /// outside the polygons provided. These are based on the intersections /// of the 2 polygons e.g. the routes / part polygons of one inside or /// outside the other. /// </summary> /// <param name="Poly1">The first polygon.</param> /// <param name="bP1RoutesInside">True if routes inside the second polygon are /// required for the first polygon.</param> /// <param name="Poly2">The second polygon.</param> /// <param name="bP2RoutesInside">True if routes inside the first polygon are /// required for the second polygon.</param> /// <param name="Routes1">Output. Set of lines for the first polygon.</param> /// <param name="Routes2">Output. Set of lines for the second polygon.</param> /// <param name="CompleteHoles1">Output. Complete holes for the first polygon.</param> /// <param name="CompleteHoles2">Output. Complete holes for the second polygon.</param> /// <param name="grid">Contains the degenerate handling settings.</param> public static void GetRoutes(C2DHoledPolyBase Poly1, bool bP1RoutesInside, C2DHoledPolyBase Poly2, bool bP2RoutesInside, C2DLineBaseSetSet Routes1, C2DLineBaseSetSet Routes2, List<C2DPolyBase> CompleteHoles1, List<C2DPolyBase> CompleteHoles2, CGrid grid) { if (Poly1.Rim.Lines.Count == 0 || Poly2.Rim.Lines.Count == 0) { Debug.Assert(false, "Polygon with no lines" ); return; } C2DPointSet IntPointsTemp = new C2DPointSet(); C2DPointSet IntPointsRim1 = new C2DPointSet(); C2DPointSet IntPointsRim2 = new C2DPointSet(); List<int> IndexesRim1 = new List<int>(); List<int> IndexesRim2 = new List<int>(); List<C2DPointSet> IntPoints1AllHoles = new List<C2DPointSet>(); List<C2DPointSet> IntPoints2AllHoles = new List<C2DPointSet>(); List<List<int>> Indexes1AllHoles = new List<List<int>>(); List<List<int>> Indexes2AllHoles = new List<List<int>>(); // std::vector<C2DPointSet* > IntPoints1AllHoles, IntPoints2AllHoles; // std::vector<CIndexSet*> Indexes1AllHoles, Indexes2AllHoles; int usP1Holes = Poly1.HoleCount; int usP2Holes = Poly2.HoleCount; // *** Rim Rim Intersections Poly1.Rim.Lines.GetIntersections( Poly2.Rim.Lines, IntPointsTemp, IndexesRim1, IndexesRim2, Poly1.Rim.BoundingRect, Poly2.Rim.BoundingRect ); IntPointsRim1.AddCopy( IntPointsTemp ); IntPointsRim2.ExtractAllOf(IntPointsTemp); // *** Rim Hole Intersections for ( int i = 0 ; i < usP2Holes; i++) { Debug.Assert(IntPointsTemp.Count == 0); IntPoints2AllHoles.Add(new C2DPointSet()); Indexes2AllHoles.Add( new List<int>() ); if (Poly1.Rim.BoundingRect.Overlaps( Poly2.GetHole(i).BoundingRect )) { Poly1.Rim.Lines.GetIntersections( Poly2.GetHole(i).Lines, IntPointsTemp, IndexesRim1, Indexes2AllHoles[i], Poly1.Rim.BoundingRect, Poly2.GetHole(i).BoundingRect); IntPointsRim1.AddCopy( IntPointsTemp); IntPoints2AllHoles[i].ExtractAllOf(IntPointsTemp); } } // *** Rim Hole Intersections for ( int j = 0 ; j < usP1Holes; j++) { Debug.Assert(IntPointsTemp.Count == 0); IntPoints1AllHoles.Add( new C2DPointSet()); Indexes1AllHoles.Add( new List<int>()); if (Poly2.Rim.BoundingRect.Overlaps(Poly1.GetHole(j).BoundingRect)) { Poly2.Rim.Lines.GetIntersections( Poly1.GetHole(j).Lines, IntPointsTemp, IndexesRim2, Indexes1AllHoles[j], Poly2.Rim.BoundingRect, Poly1.GetHole(j).BoundingRect); IntPointsRim2.AddCopy( IntPointsTemp); IntPoints1AllHoles[j].ExtractAllOf(IntPointsTemp); } } // *** Quick Escape bool bRim1StartInPoly2 = Poly2.Contains( Poly1.Rim.Lines[0].GetPointFrom() ); bool bRim2StartInPoly1 = Poly1.Contains( Poly2.Rim.Lines[0].GetPointFrom() ); if (IntPointsRim1.Count != 0 || IntPointsRim2.Count != 0 || bRim1StartInPoly2 || bRim2StartInPoly1 ) // pos no interaction { // *** Rim Routes Poly1.Rim.GetRoutes( IntPointsRim1, IndexesRim1, Routes1, bRim1StartInPoly2, bP1RoutesInside); Poly2.Rim.GetRoutes( IntPointsRim2, IndexesRim2, Routes2, bRim2StartInPoly1, bP2RoutesInside); if( IntPointsRim1.Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if( IntPointsRim2.Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } // *** Hole Hole Intersections for (int h = 0 ; h < usP1Holes; h++) { for ( int k = 0 ; k < usP2Holes; k++) { Debug.Assert(IntPointsTemp.Count == 0); C2DPolyBase pHole1 = Poly1.GetHole(h); C2DPolyBase pHole2 = Poly2.GetHole(k); if ( pHole1.BoundingRect.Overlaps( pHole2.BoundingRect) ) { pHole1.Lines.GetIntersections( pHole2.Lines, IntPointsTemp, Indexes1AllHoles[h], Indexes2AllHoles[k], pHole1.BoundingRect, pHole2.BoundingRect); IntPoints1AllHoles[h].AddCopy( IntPointsTemp); IntPoints2AllHoles[k].ExtractAllOf(IntPointsTemp); } } } // *** Hole Routes for (int a = 0 ; a < usP1Holes; a++) { C2DPolyBase pHole = Poly1.GetHole(a); if ( IntPoints1AllHoles[a].Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if (pHole.Lines.Count != 0) { bool bHole1StartInside = Poly2.Contains( pHole.Lines[0].GetPointFrom() ); if ( IntPoints1AllHoles[a].Count == 0) { if ( bHole1StartInside == bP1RoutesInside) CompleteHoles1.Add( new C2DPolyBase(pHole) ); } else { pHole.GetRoutes( IntPoints1AllHoles[a], Indexes1AllHoles[a], Routes1, bHole1StartInside, bP1RoutesInside); } } } // *** Hole Routes for (int b = 0 ; b < usP2Holes; b++) { C2DPolyBase pHole = Poly2.GetHole(b); if ( IntPoints2AllHoles[b].Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if (pHole.Lines.Count != 0) { bool bHole2StartInside = Poly1.Contains( pHole.Lines[0].GetPointFrom() ); if ( IntPoints2AllHoles[b].Count == 0) { if ( bHole2StartInside == bP2RoutesInside) CompleteHoles2.Add( new C2DPolyBase( pHole) ); } else { pHole.GetRoutes( IntPoints2AllHoles[b], Indexes2AllHoles[b], Routes2, bHole2StartInside, bP2RoutesInside); } } } } //for (unsigned int i = 0 ; i < IntPoints1AllHoles.size(); i++) // delete IntPoints1AllHoles[i]; //for (unsigned int i = 0 ; i < IntPoints2AllHoles.size(); i++) // delete IntPoints2AllHoles[i]; //for (unsigned int i = 0 ; i < Indexes1AllHoles.size(); i++) // delete Indexes1AllHoles[i]; //for (unsigned int i = 0 ; i < Indexes2AllHoles.size(); i++) // delete Indexes2AllHoles[i]; }
/// <summary> /// Unification by growing shapes of fairly equal size (fastest for large groups). /// </summary> /// <param name="grid">The CGrid with the degenerate settings.</param> public void UnifyProgressive(CGrid grid) { // Record the degenerate handling so we can reset. CGrid.eDegenerateHandling DegenerateHandling = grid.DegenerateHandling; switch (grid.DegenerateHandling) { case CGrid.eDegenerateHandling.RandomPerturbation: for (var i = 0; i < Count; i++) { this[i].RandomPerturb(); } grid.DegenerateHandling = CGrid.eDegenerateHandling.None; break; case CGrid.eDegenerateHandling.DynamicGrid: break; case CGrid.eDegenerateHandling.PreDefinedGrid: for (var i = 0; i < Count; i++) { this[i].SnapToGrid(grid); } grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGridPreSnapped; break; case CGrid.eDegenerateHandling.PreDefinedGridPreSnapped: break; } var NoUnionSet = new C2DHoledPolyBaseSet(); var PossUnionSet = new C2DHoledPolyBaseSet(); var SizeHoldSet = new C2DHoledPolyBaseSet(); var UnionSet = new C2DHoledPolyBaseSet(); var TempSet = new C2DHoledPolyBaseSet(); var nThreshold = GetMinLineCount(); if (nThreshold == 0) { nThreshold = 10; // avoid infinate loop. } // Assumed all are size held to start SizeHoldSet.AddRange(this); this.Clear(); do { // double the threshold nThreshold *= 3; // Put all the possible intersects back in this. this.AddRange(PossUnionSet); PossUnionSet.Clear(); // Put all the size held that are small enough back (or in to start with) while (SizeHoldSet.Count > 0) { var pLast = SizeHoldSet[SizeHoldSet.Count - 1]; SizeHoldSet.RemoveAt(SizeHoldSet.Count - 1); if (pLast.GetLineCount() > nThreshold) { TempSet.Add(pLast); } else { this.Add(pLast); } } SizeHoldSet.AddRange(TempSet); TempSet.Clear(); // Cycle through all popping the last and finding a union while (Count > 0) { var pLast = this[Count - 1]; this.RemoveAt(Count - 1); var bIntersect = false; var i = 0; while (i < Count && !bIntersect) { this[i].GetUnion(pLast, UnionSet, grid); if (UnionSet.Count == 1) { var pUnion = UnionSet[UnionSet.Count - 1]; UnionSet.RemoveAt(UnionSet.Count - 1); if (pUnion.GetLineCount() > nThreshold) { RemoveAt(i); SizeHoldSet.Add(pUnion); } else { this[i] = pUnion; i++; } bIntersect = true; } else { if (UnionSet.Count != 0) { grid.LogDegenerateError(); } UnionSet.Clear(); i++; } } if (!bIntersect) { var bPosInterSect = false; for (var j = 0; j < SizeHoldSet.Count; j++) { if (pLast.Rim.BoundingRect.Overlaps( SizeHoldSet[j].Rim.BoundingRect)) { bPosInterSect = true; break; } } if (bPosInterSect) { PossUnionSet.Add(pLast); } else { NoUnionSet.Add(pLast); } } } }while (SizeHoldSet.Count != 0); this.AddRange(NoUnionSet); NoUnionSet.Clear(); grid.DegenerateHandling = DegenerateHandling; }
/// <summary> /// Returns the difference between this and the other polygon. /// </summary> /// <param name="Other">Other polygon.</param> /// <param name="HoledPolys">Set to receieve all the resulting polygons.</param> /// <param name="grid">Grid containing the degenerate handling settings.</param> public void GetNonOverlaps(C2DHoledPolyBase Other, List <C2DHoledPolyBase> HoledPolys, CGrid grid) { GetBoolean(Other, HoledPolys, false, true, grid); }
/// <summary> /// Returns the routes (multiple lines or part polygons) either inside or /// outside the polygons provided. These are based on the intersections /// of the 2 polygons e.g. the routes / part polygons of one inside or /// outside the other. /// </summary> /// <param name="Poly1">The first polygon.</param> /// <param name="bP1RoutesInside">True if routes inside the second polygon are /// required for the first polygon.</param> /// <param name="Poly2">The second polygon.</param> /// <param name="bP2RoutesInside">True if routes inside the first polygon are /// required for the second polygon.</param> /// <param name="Routes1">Output. Set of lines for the first polygon.</param> /// <param name="Routes2">Output. Set of lines for the second polygon.</param> /// <param name="CompleteHoles1">Output. Complete holes for the first polygon.</param> /// <param name="CompleteHoles2">Output. Complete holes for the second polygon.</param> /// <param name="grid">Contains the degenerate handling settings.</param> public static void GetRoutes(C2DHoledPolyBase Poly1, bool bP1RoutesInside, C2DHoledPolyBase Poly2, bool bP2RoutesInside, C2DLineBaseSetSet Routes1, C2DLineBaseSetSet Routes2, List <C2DPolyBase> CompleteHoles1, List <C2DPolyBase> CompleteHoles2, CGrid grid) { if (Poly1.Rim.Lines.Count == 0 || Poly2.Rim.Lines.Count == 0) { Debug.Assert(false, "Polygon with no lines"); return; } var IntPointsTemp = new C2DPointSet(); var IntPointsRim1 = new C2DPointSet(); var IntPointsRim2 = new C2DPointSet(); var IndexesRim1 = new List <int>(); var IndexesRim2 = new List <int>(); var IntPoints1AllHoles = new List <C2DPointSet>(); var IntPoints2AllHoles = new List <C2DPointSet>(); var Indexes1AllHoles = new List <List <int> >(); var Indexes2AllHoles = new List <List <int> >(); // std::vector<C2DPointSet* > IntPoints1AllHoles, IntPoints2AllHoles; // std::vector<CIndexSet*> Indexes1AllHoles, Indexes2AllHoles; var usP1Holes = Poly1.HoleCount; var usP2Holes = Poly2.HoleCount; // *** Rim Rim Intersections Poly1.Rim.Lines.GetIntersections(Poly2.Rim.Lines, IntPointsTemp, IndexesRim1, IndexesRim2, Poly1.Rim.BoundingRect, Poly2.Rim.BoundingRect); IntPointsRim1.AddCopy(IntPointsTemp); IntPointsRim2.ExtractAllOf(IntPointsTemp); // *** Rim Hole Intersections for (var i = 0; i < usP2Holes; i++) { Debug.Assert(IntPointsTemp.Count == 0); IntPoints2AllHoles.Add(new C2DPointSet()); Indexes2AllHoles.Add(new List <int>()); if (Poly1.Rim.BoundingRect.Overlaps(Poly2.GetHole(i).BoundingRect)) { Poly1.Rim.Lines.GetIntersections(Poly2.GetHole(i).Lines, IntPointsTemp, IndexesRim1, Indexes2AllHoles[i], Poly1.Rim.BoundingRect, Poly2.GetHole(i).BoundingRect); IntPointsRim1.AddCopy(IntPointsTemp); IntPoints2AllHoles[i].ExtractAllOf(IntPointsTemp); } } // *** Rim Hole Intersections for (var j = 0; j < usP1Holes; j++) { Debug.Assert(IntPointsTemp.Count == 0); IntPoints1AllHoles.Add(new C2DPointSet()); Indexes1AllHoles.Add(new List <int>()); if (Poly2.Rim.BoundingRect.Overlaps(Poly1.GetHole(j).BoundingRect)) { Poly2.Rim.Lines.GetIntersections(Poly1.GetHole(j).Lines, IntPointsTemp, IndexesRim2, Indexes1AllHoles[j], Poly2.Rim.BoundingRect, Poly1.GetHole(j).BoundingRect); IntPointsRim2.AddCopy(IntPointsTemp); IntPoints1AllHoles[j].ExtractAllOf(IntPointsTemp); } } // *** Quick Escape bool bRim1StartInPoly2 = Poly2.Contains(Poly1.Rim.Lines[0].GetPointFrom()); bool bRim2StartInPoly1 = Poly1.Contains(Poly2.Rim.Lines[0].GetPointFrom()); if (IntPointsRim1.Count != 0 || IntPointsRim2.Count != 0 || bRim1StartInPoly2 || bRim2StartInPoly1) // pos no interaction { // *** Rim Routes Poly1.Rim.GetRoutes(IntPointsRim1, IndexesRim1, Routes1, bRim1StartInPoly2, bP1RoutesInside); Poly2.Rim.GetRoutes(IntPointsRim2, IndexesRim2, Routes2, bRim2StartInPoly1, bP2RoutesInside); if (IntPointsRim1.Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if (IntPointsRim2.Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } // *** Hole Hole Intersections for (var h = 0; h < usP1Holes; h++) { for (var k = 0; k < usP2Holes; k++) { Debug.Assert(IntPointsTemp.Count == 0); var pHole1 = Poly1.GetHole(h); var pHole2 = Poly2.GetHole(k); if (pHole1.BoundingRect.Overlaps(pHole2.BoundingRect)) { pHole1.Lines.GetIntersections(pHole2.Lines, IntPointsTemp, Indexes1AllHoles[h], Indexes2AllHoles[k], pHole1.BoundingRect, pHole2.BoundingRect); IntPoints1AllHoles[h].AddCopy(IntPointsTemp); IntPoints2AllHoles[k].ExtractAllOf(IntPointsTemp); } } } // *** Hole Routes for (var a = 0; a < usP1Holes; a++) { var pHole = Poly1.GetHole(a); if (IntPoints1AllHoles[a].Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if (pHole.Lines.Count != 0) { bool bHole1StartInside = Poly2.Contains(pHole.Lines[0].GetPointFrom()); if (IntPoints1AllHoles[a].Count == 0) { if (bHole1StartInside == bP1RoutesInside) { CompleteHoles1.Add(new C2DPolyBase(pHole)); } } else { pHole.GetRoutes(IntPoints1AllHoles[a], Indexes1AllHoles[a], Routes1, bHole1StartInside, bP1RoutesInside); } } } // *** Hole Routes for (var b = 0; b < usP2Holes; b++) { var pHole = Poly2.GetHole(b); if (IntPoints2AllHoles[b].Count % 2 != 0) // Must be even { grid.LogDegenerateError(); // Debug.Assert(false); } if (pHole.Lines.Count != 0) { bool bHole2StartInside = Poly1.Contains(pHole.Lines[0].GetPointFrom()); if (IntPoints2AllHoles[b].Count == 0) { if (bHole2StartInside == bP2RoutesInside) { CompleteHoles2.Add(new C2DPolyBase(pHole)); } } else { pHole.GetRoutes(IntPoints2AllHoles[b], Indexes2AllHoles[b], Routes2, bHole2StartInside, bP2RoutesInside); } } } } //for (unsigned int i = 0 ; i < IntPoints1AllHoles.size(); i++) // delete IntPoints1AllHoles[i]; //for (unsigned int i = 0 ; i < IntPoints2AllHoles.size(); i++) // delete IntPoints2AllHoles[i]; //for (unsigned int i = 0 ; i < Indexes1AllHoles.size(); i++) // delete Indexes1AllHoles[i]; //for (unsigned int i = 0 ; i < Indexes2AllHoles.size(); i++) // delete Indexes2AllHoles[i]; }
/// <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: { var CompleteHoles1 = new List <C2DPolyBase>(); var CompleteHoles2 = new List <C2DPolyBase>(); var Routes1 = new C2DLineBaseSetSet(); var Routes2 = new C2DLineBaseSetSet(); GetRoutes(this, bThisInside, Other, bOtherInside, Routes1, Routes2, CompleteHoles1, CompleteHoles2, grid); Routes1.ExtractAllOf(Routes2); if (Routes1.Count > 0) { Routes1.MergeJoining(); var Polygons = new List <C2DPolyBase>(); for (var 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(); } } var 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: { var 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: { var 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: { var P1 = new C2DHoledPolyBase(this); var P2 = new C2DHoledPolyBase(Other); P1.SnapToGrid(grid); P2.SnapToGrid(grid); var V1 = new C2DVector(P1.Rim.BoundingRect.TopLeft, P2.Rim.BoundingRect.TopLeft); var 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 (var i = 0; i < HoledPolys.Count; i++) { HoledPolys[i].SnapToGrid(grid); } grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; } break; case CGrid.eDegenerateHandling.PreDefinedGridPreSnapped: { var P2 = new C2DHoledPolyBase(Other); var V1 = new C2DVector(_Rim.BoundingRect.TopLeft, P2.Rim.BoundingRect.TopLeft); var 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 (var i = 0; i < HoledPolys.Count; i++) { HoledPolys[i].SnapToGrid(grid); } grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGridPreSnapped; } break; } // switch } }
/// <summary> /// Snaps to the conceptual grid /// </summary> /// <param name="grid">The grid.</param> public override void SnapToGrid(CGrid grid) { _Centre.SnapToGrid(grid); double dMultiple = Math.Abs(Radius / grid.GridSize) + 0.5; dMultiple = Math.Floor(dMultiple); if (Radius < 0) Radius = -dMultiple * grid.GridSize; else Radius = dMultiple * grid.GridSize; }
void merge(C2DHoledPolyArc stoneShape, List<C2DHoledPolyArc> shapesToMerge, List<C2DHoledPolyArc> ownShape) { List<C2DHoledPolyArc> acc = new List<C2DHoledPolyArc>(); CGrid grid = new CGrid (); grid.SetGridSize(0.01f); if (shapesToMerge.Count == 0) { ownShape.Add(stoneShape); return; } foreach (C2DHoledPolyArc shape in shapesToMerge) { ownShape.Remove(shape); } foreach (C2DHoledPolyArc shape in shapesToMerge) { shape.GetUnion(stoneShape, acc, grid); } ownShape.Add(acc[acc.Count-1]); }
/// <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; } } }
/// <summary> /// Snaps this to the conceptual grid. /// </summary> /// <param name="grid">The grid.</param> public override void SnapToGrid(CGrid grid) { Arc.SnapToGrid(grid); }
/// <summary> /// Returns the union of this and the other. /// </summary> /// <param name="Other">Other polygon.</param> /// <param name="HoledPolys">Set to receieve all the resulting polygons.</param> /// <param name="grid">Grid containing the degenerate handling settings.</param> public void GetUnion(C2DHoledPolyBase Other, List<C2DHoledPolyBase> HoledPolys, CGrid grid) { GetBoolean(Other, HoledPolys,false , false, grid); }
/// <summary> /// Returns the union of this with another. /// </summary> /// <param name="Other">The other polygon.</param> /// <param name="Polygons">The output polygons.</param> /// <param name="grid">The degenerate settings.</param> public void GetUnion(C2DPolyBase Other, List <C2DHoledPolyBase> Polygons, CGrid grid) { GetBoolean(Other, Polygons, false, false, grid); }
/// <summary> /// Snaps this to the conceptual grip. /// </summary> /// <param name="grid">The grid to snap to.</param> public void SnapToGrid(CGrid grid) { _Rim.SnapToGrid(grid); for (int i = 0 ; i < _Holes.Count; i++) { GetHole(i).SnapToGrid(grid); } }
/// <summary> /// Returns the overlaps of this with another. /// </summary> /// <param name="Other">The other polygon.</param> /// <param name="Polygons">The output polygons.</param> /// <param name="grid">The degenerate settings.</param> public void GetOverlaps(C2DPolyBase Other, List <C2DHoledPolyBase> Polygons, CGrid grid) { GetBoolean(Other, Polygons, true, true, grid); }
/// <summary> /// Snaps this to the grid. The x and y values can only be multiples or the grid size. /// </summary> /// <param name="grid">The grid to snap this to.</param> public override void SnapToGrid(CGrid grid) { double dxMultiple = Math.Abs(x / grid.GridSize) + 0.5; dxMultiple = Math.Floor(dxMultiple); if (x < 0) x = -dxMultiple * grid.GridSize; else x = dxMultiple * grid.GridSize; double dyMultiple = Math.Abs(y / grid.GridSize) + 0.5; dyMultiple = Math.Floor(dyMultiple); if (y < 0) y = -dyMultiple * grid.GridSize; else y = dyMultiple * grid.GridSize; }
/// <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: { var Routes1 = new C2DLineBaseSetSet(); var 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. var Polygons = new List <C2DPolyBase>(); // Turn the routes into polygons. for (var 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 var 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 (var i = 0; i < Polygons.Count; i++) { HoledPolys.Add(new C2DHoledPolyBase(Polygons[i])); } } // Now add them all to the provided set. for (var i = 0; i < NewComPolys.Count; i++) { HoledPolys.Add(NewComPolys[i]); } } } break; case CGrid.eDegenerateHandling.RandomPerturbation: { var 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: { var Rect = new C2DRect(); if (this.BoundingRect.Overlaps(Other.BoundingRect, Rect)) { var 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: { var P1 = new C2DPolyBase(this); var P2 = new C2DPolyBase(Other); P1.SnapToGrid(grid); P2.SnapToGrid(grid); var V1 = new C2DVector(P1.BoundingRect.TopLeft, P2.BoundingRect.TopLeft); var 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 (var i = 0; i < HoledPolys.Count; i++) { HoledPolys[i].SnapToGrid(grid); } grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGrid; } break; case CGrid.eDegenerateHandling.PreDefinedGridPreSnapped: { var P2 = new C2DPolyBase(Other); var V1 = new C2DVector(this.BoundingRect.TopLeft, P2.BoundingRect.TopLeft); var 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 (var i = 0; i < HoledPolys.Count; i++) { HoledPolys[i].SnapToGrid(grid); } grid.DegenerateHandling = CGrid.eDegenerateHandling.PreDefinedGridPreSnapped; } break; } } }
/// <summary> /// Snap to the conceptual grid. /// </summary> /// <param name="grid">The grid.</param> public override void SnapToGrid(CGrid grid) { for (int i = 0; i < _Lines.Count; i++) { _Lines[i].SnapToGrid(grid); } for(int i = 0; i < _LineRects.Count; i++) { _LineRects[i].SnapToGrid(grid); } BoundingRect.SnapToGrid(grid); }
/// <summary> /// Gets the overlaps of the 2 shapes. /// </summary> /// <param name="Other">The other shape.</param> /// <param name="Polygons">The set to recieve the result.</param> /// <param name="grid">The degenerate settings.</param> public void GetOverlaps(C2DPolyArc Other, List<C2DHoledPolyArc> Polygons, CGrid grid) { List<C2DHoledPolyBase> NewPolys = new List<C2DHoledPolyBase>(); base.GetOverlaps(Other, NewPolys, grid); for (int i = 0; i < NewPolys.Count; i++) Polygons.Add(new C2DHoledPolyArc(NewPolys[i])); }
/// <summary> /// Returns the overlaps of this with another. /// </summary> /// <param name="Other">The other polygon.</param> /// <param name="Polygons">The output polygons.</param> /// <param name="grid">The degenerate settings.</param> public void GetOverlaps(C2DPolyBase Other, List<C2DHoledPolyBase> Polygons, CGrid grid) { GetBoolean(Other, Polygons, true, true, grid); }
/// <summary> /// Snaps this to the conceptual grid. /// </summary> /// <param name="grid">The grid to snap to.</param> public override void SnapToGrid(CGrid grid) { C2DPoint pt = GetPointTo(); pt.SnapToGrid(grid); point.SnapToGrid(grid); SetPointTo(pt); }
/// <summary> /// Snaps this to the conceptual grid. /// </summary> /// <param name="grid">The grid object to snap this to.</param> public override void SnapToGrid(CGrid grid) { Line.SnapToGrid(grid); double dLength = Line.vector.GetLength(); if (dLength > (2 * Radius)) { Radius = dLength / 1.999999999999; // To ensure errors in the right way. } }