public List<Area_Based_Analyses.Atomizer.AtomicRegion> Atomize(List<Point> figurePoints) { List<Segment> constructedChords = new List<Segment>(); List<Segment> constructedRadii = new List<Segment>(); List<Point> imagPoints = new List<Point>(); List<Point> interPts = GetIntersectingPoints(); // // Construct the radii // switch (interPts.Count) { // If there are no points of interest, the circle is the atomic region. case 0: return Utilities.MakeList<AtomicRegion>(new ShapeAtomicRegion(this)); // If only 1 intersection point, create the diameter. case 1: Point opp = Utilities.AcquirePoint(figurePoints, this.OppositePoint(interPts[0])); constructedRadii.Add(new Segment(center, interPts[0])); constructedRadii.Add(new Segment(center, opp)); imagPoints.Add(opp); interPts.Add(opp); break; default: foreach (Point interPt in interPts) { constructedRadii.Add(new Segment(center, interPt)); } break; } // // Construct the chords // List<Segment> chords = new List<Segment>(); for (int p1 = 0; p1 < interPts.Count - 1; p1++) { for (int p2 = p1 + 1; p2 < interPts.Count; p2++) { Segment chord = new Segment(interPts[p1], interPts[p2]); if (!DefinesDiameter(chord)) constructedChords.Add(chord); } } // // Do any of the created segments result in imaginary intersection points. // foreach (Segment chord in constructedChords) { foreach (Segment radius in constructedRadii) { Point inter = Utilities.AcquireRestrictedPoint(figurePoints, chord.FindIntersection(radius), chord, radius); if (inter != null) { chord.AddCollinearPoint(inter); radius.AddCollinearPoint(inter); // if (!Utilities.HasStructurally<Point>(figurePoints, inter)) imagPoints.Add(inter); Utilities.AddUnique<Point>(imagPoints, inter); } } } for (int c1 = 0; c1 < constructedChords.Count - 1; c1++) { for (int c2 = c1 + 1; c2 < constructedChords.Count; c2++) { Point inter = constructedChords[c1].FindIntersection(constructedChords[c2]); inter = Utilities.AcquireRestrictedPoint(figurePoints, inter, constructedChords[c1], constructedChords[c2]); if (inter != null) { constructedChords[c1].AddCollinearPoint(inter); constructedChords[c2].AddCollinearPoint(inter); //if (!Utilities.HasStructurally<Point>(figurePoints, inter)) imagPoints.Add(inter); Utilities.AddUnique<Point>(imagPoints, inter); } } } // // Add all imaginary points to the list of figure points. // Utilities.AddUniqueList<Point>(figurePoints, imagPoints); // // Construct the Planar graph for atomic region identification. // Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph graph = new Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(); // // Add all imaginary points, intersection points, and center. // foreach (Point pt in imagPoints) { graph.AddNode(pt); } foreach (Point pt in interPts) { graph.AddNode(pt); } graph.AddNode(this.center); // // Add all chords and radii as edges. // foreach (Segment chord in constructedChords) { for (int p = 0; p < chord.collinear.Count - 1; p++) { graph.AddUndirectedEdge(chord.collinear[p], chord.collinear[p + 1], new Segment(chord.collinear[p], chord.collinear[p + 1]).Length, Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } } foreach (Segment radius in constructedRadii) { for (int p = 0; p < radius.collinear.Count - 1; p++) { graph.AddUndirectedEdge(radius.collinear[p], radius.collinear[p + 1], new Segment(radius.collinear[p], radius.collinear[p + 1]).Length, Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } } // // Add all arcs // List<Point> arcPts = this.ConstructAllMidpoints(interPts); for (int p = 0; p < arcPts.Count; p++) { graph.AddNode(arcPts[p]); graph.AddNode(arcPts[(p + 1) % arcPts.Count]); graph.AddUndirectedEdge(arcPts[p], arcPts[(p + 1) % arcPts.Count], new Segment(arcPts[p], arcPts[(p + 1) % interPts.Count]).Length, Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_ARC); } // // Convert the planar graph to atomic regions. // Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph copy = new Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(graph); FacetCalculator atomFinder = new FacetCalculator(copy); List<Primitive> primitives = atomFinder.GetPrimitives(); List<AtomicRegion> atoms = PrimitiveToRegionConverter.Convert(graph, primitives, Utilities.MakeList<Circle>(this)); // // A filament may result in the creation of a major AND minor arc; both are not required. // Figure out which one to omit. // Multiple semi-circles may arise as well; omit if they can be broken into constituent elements. // List <AtomicRegion> trueAtoms = new List<AtomicRegion>(); for (int a1 = 0; a1 < atoms.Count; a1++) { bool trueAtom = true; for (int a2 = 0; a2 < atoms.Count; a2++) { if (a1 != a2) { if (atoms[a1].Contains(atoms[a2])) { trueAtom = false; break; } } } if (trueAtom) trueAtoms.Add(atoms[a1]); } atoms = trueAtoms; return trueAtoms; }
// // This is a complex situation because we need to identify situations where circles intersect with the resultant regions: // (| (|) // ( | ( | ) // ( | ( | ) // ( | ( | ) // (| (|) // // Note: There will always be a chord because of our implied construction. // We are interested in only minor arcs of the given circles. // private List<Atomizer.AtomicRegion> ConvertToCircleCircle(Segment chord, List<Circle> circles, out Circle leftOuterCircle, out Circle rightOuterCircle) { List<Atomizer.AtomicRegion> regions = new List<Atomizer.AtomicRegion>(); leftOuterCircle = null; rightOuterCircle = null; // // Simple cases that require no special attention. // if (!circles.Any()) return null; if (circles.Count == 1) { leftOuterCircle = circles[0]; regions.AddRange(ConstructBasicLineCircleRegion(chord, circles[0])); return regions; } // All circles that are on each side of the chord List<Circle> leftSide = new List<Circle>(); List<Circle> rightSide = new List<Circle>(); // For now, assume max, one circle per side. // Construct a collinear list of points that includes all circle centers as well as the single intersection point between the chord and the line passing through all circle centers. // This orders the sides and provides implied sizes. Segment centerLine = new Segment(circles[0].center, circles[1].center); for (int c = 2; c < circles.Count; c++) { centerLine.AddCollinearPoint(circles[c].center); } // Find the intersection between the center-line and the chord; add that to the list. Point intersection = centerLine.FindIntersection(chord); centerLine.AddCollinearPoint(intersection); List<Point> collPoints = centerLine.collinear; int interIndex = collPoints.IndexOf(intersection); for (int i = 0; i < collPoints.Count; i++) { // find the circle based on center int c; for (c = 0; c < circles.Count; c++) { if (circles[c].center.StructurallyEquals(collPoints[i])) break; } // Add the circle in order if (i < interIndex) leftSide.Add(circles[c]); else if (i > interIndex) rightSide.Add(circles[c]); } // the outermost circle is first in the left list and last in the right list. if (leftSide.Any()) leftOuterCircle = leftSide[0]; if (rightSide.Any()) rightOuterCircle = rightSide[rightSide.Count - 1]; // // Main combining algorithm: // Assume: Increasing Arc sequence A \in A_1, A_2, ..., A_n and the single chord C // // Construct region B = (C, A_1) // For the increasing Arc sequence (k subscript) A_2, A_3, ..., A_n // B = Construct ((C, A_k) \ B) // // Alternatively: // Construct(C, A_1) // for each pair Construct (A_k, A_{k+1}) // // // Handle each side: left and right. // if (leftSide.Any()) regions.AddRange(ConstructBasicLineCircleRegion(chord, leftSide[leftSide.Count - 1])); for (int ell = 0; ell < leftSide.Count - 2; ell++) { regions.Add(ConstructBasicCircleCircleRegion(chord, leftSide[ell], leftSide[ell + 1])); } if (rightSide.Any()) regions.AddRange(ConstructBasicLineCircleRegion(chord, rightSide[0])); for (int r = 1; r < rightSide.Count - 1; r++) { regions.Add(ConstructBasicCircleCircleRegion(chord, rightSide[r], rightSide[r + 1])); } return regions; }