public static List<AtomicRegion> AcquireAtomicRegionsFromGraph(List<Point> points, List<Segment> segments, List<Arc> arcs, List<Circle> circles, Dictionary<Circle, int> circGranularity) { // // Construct the Planar graph for atomic region identification. // GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph graph = new GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(); // Add the points as nodes in the graph. foreach (Point pt in points) { graph.AddNode(pt); } // // Edges are based on all the collinear relationships. // foreach (Segment segment in segments) { for (int p = 0; p < segment.collinear.Count - 1; p++) { graph.AddUndirectedEdge(segment.collinear[p], segment.collinear[p + 1], new Segment(segment.collinear[p], segment.collinear[p + 1]).Length, GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } } foreach (Arc arc in arcs) { List<Point> applicWithMidpoints = GetArcPoints(arc, circGranularity); // Add the points to the graph foreach (Point pt in applicWithMidpoints) { graph.AddNode(pt); } for (int p = 0; p < applicWithMidpoints.Count - 1; p++) { graph.AddUndirectedEdge(applicWithMidpoints[p], applicWithMidpoints[p + 1], new Segment(applicWithMidpoints[p], applicWithMidpoints[p + 1]).Length, GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_ARC); } } // // Convert the planar graph to atomic regions. // GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph copy = new GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(graph); FacetCalculator atomFinder = new FacetCalculator(copy); List<Primitive> primitives = atomFinder.GetPrimitives(); return PrimitiveToRegionConverter.Convert(graph, primitives, circles); }
// // Using a single atomic region as a set of bounds: // (1) Find all interesting regions (contained and intersecting) // (2) Recursively compose all contained regions. // (3) Combine all into the original boundary region. // private static List<AtomicRegion> ComposeSingleRegion(List<Point> figurePoints, AtomicRegion outerBounds, List<AtomicRegion> allRegions, List<AtomicRegion> knownAtomicRegions, List<AtomicRegion> knownNonAtomicRegions, List<List<AtomicRegion>> setsForNonAtomicRegions, Dictionary<Circle, int> circGranularity) { // // Base cases: we have already processed this atom as a sub-atom in a previous iteration. // if (knownAtomicRegions.Contains(outerBounds)) return Utilities.MakeList<AtomicRegion>(outerBounds); // We've processed this atom already. int index = knownNonAtomicRegions.IndexOf(outerBounds); if (index != -1) return setsForNonAtomicRegions[index]; // // Acquire the current set of regions under consideration. // List<AtomicRegion> currentAtoms = new List<AtomicRegion>(allRegions); AddRange(currentAtoms, knownAtomicRegions); // // Collect all interesting regions for this region: those that intersect with it and those that are contained inside. // List<AtomicRegion> intersectingSet = null; List<AtomicRegion> containedSet = null; GetInterestingRegions(currentAtoms, outerBounds, out intersectingSet, out containedSet); // If we have have no interactions, this is a truly atomic region. if (!intersectingSet.Any() && !containedSet.Any()) return Utilities.MakeList<AtomicRegion>(outerBounds); // // Recur on all containing regions. // List<AtomicRegion> newContainedAtoms = new List<AtomicRegion>(); foreach (AtomicRegion containedAtom in containedSet) { if (knownAtomicRegions.Contains(containedAtom)) AddAtom(newContainedAtoms, containedAtom); else if (knownNonAtomicRegions.Contains(containedAtom)) { AddRange(newContainedAtoms, setsForNonAtomicRegions[knownNonAtomicRegions.IndexOf(containedAtom)]); } else { // Get all regions using containedAtom as the boundary region. List<AtomicRegion> newContainedBoundedAtoms = ComposeSingleRegion(figurePoints, containedAtom, currentAtoms, knownAtomicRegions, knownNonAtomicRegions, setsForNonAtomicRegions, circGranularity); AddRange(newContainedAtoms, newContainedBoundedAtoms); // // This is a true atomic region that cannot be split. // if (newContainedBoundedAtoms.Count == 1) AddAtom(knownAtomicRegions, containedAtom); // // The boundary atom is replaced by all of the newAtoms else { // Save all of the contained atomic regions for this atom. if (AddAtom(knownNonAtomicRegions, containedAtom)) { setsForNonAtomicRegions.Add(newContainedBoundedAtoms); } // Indicate all found regions are truly atomic AddRange(knownAtomicRegions, newContainedBoundedAtoms); } } } // // Now that all contained regions are atomized, combine ALL intersections and atomic regions. // // Collect all segments and arcs (with explicit endpoints). // Extend only if they do not touch the sides of the boundaries. // // inside of the boundaries; determine all intersection points. // // (1) All intersecting regions. // (a) For all vertices inside the boundaries, extend to the closest atom. // (b) For all sides that pass through determine any intersections. // (2) All contained atoms // (a) For each side of a region, extend to the closest region. // (b) If a single circle or concentric circles, extend a diameter from the closest point inside the region, through the center. // (c) If several non-intersecting circles, extend diameters through the centers of each pair. // List<Point> points = new List<Point>(); List<Segment> segments = new List<Segment>(); List<Arc> arcs = new List<Arc>(); // // Add the outer boundaries. // points.AddRange(outerBounds.GetVertices()); foreach (Connection boundaryConn in outerBounds.connections) { if (boundaryConn.type == ConnectionType.ARC) { arcs.Add(boundaryConn.segmentOrArc as Arc); } if (boundaryConn.type == ConnectionType.SEGMENT) { segments.Add(boundaryConn.segmentOrArc as Segment); } } // // Regions that intersect the boundaries; selectively take connections. // foreach (AtomicRegion intersecting in intersectingSet) { List<AtomicRegion.IntersectionAgg> intersections = outerBounds.GetIntersections(figurePoints, intersecting); // Determine which intersections are interior to the boundaries. foreach (AtomicRegion.IntersectionAgg agg in intersections) { if (agg.overlap) { /* No-op */ } else { if (agg.intersection1 != null) { if (outerBounds.PointLiesOnOrInside(agg.intersection1)) { if (!outerBounds.NotInteriorTo(agg.thatConn)) { if (agg.thatConn.type == ConnectionType.ARC) GeometryTutorLib.Utilities.AddUnique<Arc>(arcs, agg.thatConn.segmentOrArc as Arc); if (agg.thatConn.type == ConnectionType.SEGMENT) GeometryTutorLib.Utilities.AddUnique<Segment>(segments, agg.thatConn.segmentOrArc as Segment); } GeometryTutorLib.Utilities.AddUnique<Point>(points, agg.intersection1); } } if (agg.intersection2 != null) { if (outerBounds.PointLiesOnOrInside(agg.intersection2)) { GeometryTutorLib.Utilities.AddUnique<Point>(points, agg.intersection2); } } } } } // // Deal with contained regions. // // TO BE COMPLETED: Deal with isolated circles. foreach (AtomicRegion contained in newContainedAtoms) { List<Point> verts = contained.GetVertices(); GeometryTutorLib.Utilities.AddUniqueList<Point>(points, verts); foreach (Connection conn in contained.connections) { if (conn.type == ConnectionType.ARC) Utilities.AddUnique<Arc>(arcs, conn.segmentOrArc as Arc); if (conn.type == ConnectionType.SEGMENT) { Utilities.AddUnique<Segment>(segments, conn.segmentOrArc as Segment); } } } // // Find all intersections...among segments and arcs. // foreach (Segment segment in segments) { segment.ClearCollinear(); } foreach (Arc arc in arcs) { arc.ClearCollinear(); } HandleSegmentSegmentIntersections(figurePoints, points, segments, outerBounds); HandleSegmentArcIntersections(figurePoints, points, segments, arcs, outerBounds); HandleArcArcIntersections(figurePoints, points, arcs, outerBounds); // Returns the list of maximal segments. segments = HandleCollinearSubSegments(segments); // HandleCollinearSubArcs(arcs); // // Construct the Planar graph for atomic region identification. // GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph graph = new GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(); // Add the points as nodes in the graph. foreach (Point pt in points) { graph.AddNode(pt); } // // Edges are based on all the collinear relationships. // To ensure we are taking ONLY the closest extended intersections, choose ONLY the 1 point around the actual endpoints of the arc or segment. // foreach (Segment segment in segments) { for (int p = 0; p < segment.collinear.Count - 1; p++) { if (outerBounds.PointLiesInOrOn(segment.collinear[p]) && outerBounds.PointLiesInOrOn(segment.collinear[p + 1])) { graph.AddUndirectedEdge(segment.collinear[p], segment.collinear[p + 1], new Segment(segment.collinear[p], segment.collinear[p + 1]).Length, GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } } } foreach (Arc arc in arcs) { List<Point> applicWithMidpoints = GetArcPoints(arc, circGranularity); // Add the points to the graph; preprocess to see if all points are inside the region. bool[] inOrOn = new bool[applicWithMidpoints.Count]; for (int p = 0; p < applicWithMidpoints.Count; p++) { if (outerBounds.PointLiesInOrOn(applicWithMidpoints[p])) { graph.AddNode(applicWithMidpoints[p]); inOrOn[p] = true; } } for (int p = 0; p < applicWithMidpoints.Count - 1; p++) { if (inOrOn[p] && inOrOn[p + 1]) { graph.AddUndirectedEdge(applicWithMidpoints[p], applicWithMidpoints[p + 1], new Segment(applicWithMidpoints[p], applicWithMidpoints[p + 1]).Length, GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_ARC); } } } // // Collect the circles from the arcs. // List<Circle> circles = new List<Circle>(); foreach (Arc arc in arcs) { GeometryTutorLib.Utilities.AddStructurallyUnique<Circle>(circles, arc.theCircle); } // // Convert the planar graph to atomic regions. // GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph copy = new GeometryTutorLib.Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(graph); FacetCalculator atomFinder = new FacetCalculator(copy); List<Primitive> primitives = atomFinder.GetPrimitives(); List<AtomicRegion> boundedAtoms = PrimitiveToRegionConverter.Convert(graph, primitives, circles); //// //// Realign this set of atoms with the current set of working atoms; this guarantees we are looking at the same atom objects. //// //List<AtomicRegion> finalBoundedAtoms = new List<AtomicRegion>(); //foreach (AtomicRegion boundedAtom in boundedAtoms) //{ // int tempIndex = currentAtoms.IndexOf(boundedAtom); // if (tempIndex == -1) finalBoundedAtoms.Add(boundedAtom); // else finalBoundedAtoms.Add(currentAtoms[tempIndex]); //} // // Determine ownership of the atomic regions. // foreach (AtomicRegion boundedAtom in boundedAtoms) { boundedAtom.AddOwners(outerBounds.owners); // Indicate that the given boundary shape owns all of the new regions within. ShapeAtomicRegion shapeAtom = outerBounds as ShapeAtomicRegion; if (shapeAtom != null) { shapeAtom.shape.AddAtomicRegion(boundedAtom); } } return boundedAtoms; }