// // Based on the two points, extract the circle which results in the connection (if the connection exists). // private List <AtomicRegion> HandleConnection(UndirectedPlanarGraph.PlanarGraph graph, List <Circle> circles, Point pt1, Point pt2) { List <AtomicRegion> atoms = new List <AtomicRegion>(); UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(pt1, pt2); if (edge == null) { return(atoms); } // // Find the one circle that applies to this set of points. // Circle theCircle = null; foreach (Circle circle in circles) { if (circle.PointLiesOn(pt1) && circle.PointLiesOn(pt2)) { theCircle = circle; } } switch (edge.edgeType) { case UndirectedPlanarGraph.EdgeType.REAL_ARC: case UndirectedPlanarGraph.EdgeType.REAL_DUAL: atoms.AddRange(CreateSectors(theCircle, pt1, pt2)); // atoms.AddRange(CreateSemiCircleRegions()); break; } return(atoms); }
// // Collect all arcs attributed to this this cycle; // private List <MinorArc> CollectStrictArcs(List <Circle> circles, UndirectedPlanarGraph.PlanarGraph graph) { List <MinorArc> minors = new List <MinorArc>(); for (int p = 0; p < points.Count; p++) { UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]); if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC) { // Find the applicable circle. Circle theCircle = null; foreach (Circle circle in circles) { if (circle.HasArc(points[p], points[(p + 1) % points.Count])) { theCircle = circle; break; } } minors.Add(new MinorArc(theCircle, points[p], points[(p + 1) % points.Count])); } } return(minors); }
// // Extract the atomic regions. // public List <AtomicRegion> ExtractAtomicRegions(UndirectedPlanarGraph.PlanarGraph graph, List <Circle> circles) { memoized = new Agg[points.Count, points.Count]; // Recursively construct. return(MakeRegions(graph, circles, 0, points.Count - 1).atoms); }
// // Take the cycle-based representation and convert in into AtomicRegion objects. // public static List <AtomicRegion> Convert(UndirectedPlanarGraph.PlanarGraph graph, List <Primitive> primitives, List <Circle> circles) { List <MinimalCycle> cycles = new List <MinimalCycle>(); List <Filament> filaments = new List <Filament>(); foreach (Primitive primitive in primitives) { if (primitive is MinimalCycle) { cycles.Add(primitive as MinimalCycle); } if (primitive is Filament) { filaments.Add(primitive as Filament); } } // // Convert the filaments to atomic regions. // List <AtomicRegion> regions = new List <AtomicRegion>(); if (filaments.Any()) { throw new Exception("A filament occurred in conversion to atomic regions."); } // regions.AddRange(HandleFilaments(graph, circles, filaments)); ComposeCycles(graph, cycles); if (GeometryTutorLib.Utilities.ATOMIC_REGION_GEN_DEBUG) { Debug.WriteLine("Composed:"); foreach (MinimalCycle cycle in cycles) { Debug.WriteLine("\t" + cycle.ToString()); } } // // Convert all cycles (perimeters) to atomic regions // foreach (MinimalCycle cycle in cycles) { List <AtomicRegion> temp = cycle.ConstructAtomicRegions(circles, graph); foreach (AtomicRegion atom in temp) { if (!regions.Contains(atom)) { regions.Add(atom); } } } return(regions); }
// // Shallow copy constructor // public PlanarGraph(PlanarGraph thatG) : this() { foreach (PlanarGraphNode node in thatG.nodes) { nodes.Add(new PlanarGraphNode(node)); } }
// // A filament is a path from one node to another; it does not invoke a cycle. // In shaded-area problems this can only be accomplished with arcs of circles. // private static List <AtomicRegion> HandleFilaments(UndirectedPlanarGraph.PlanarGraph graph, List <Circle> circles, List <Filament> filaments) { List <AtomicRegion> atoms = new List <AtomicRegion>(); foreach (Filament filament in filaments) { atoms.AddRange(filament.ExtractAtomicRegions(graph, circles)); } return(atoms); }
private static int HasComposableCycle(UndirectedPlanarGraph.PlanarGraph graph, List <MinimalCycle> cycles) { for (int c = 0; c < cycles.Count; c++) { if (cycles[c].HasExtendedSegment(graph)) { return(c); } } return(-1); }
public Segment GetExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph) { for (int p = 0; p < points.Count; p++) { if (graph.GetEdgeType(points[p], points[(p + 1) % points.Count]) == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT) { return(new Segment(points[p], points[p + 1 < points.Count ? p + 1 : 0])); } } return(null); }
public FacetCalculator(UndirectedPlanarGraph.PlanarGraph g) { graph = g; if (Utilities.ATOMIC_REGION_GEN_DEBUG) { Debug.WriteLine(graph); } primitives = new List<Primitive>(); ExtractPrimitives(); }
public FacetCalculator(UndirectedPlanarGraph.PlanarGraph g) { graph = g; if (Utilities.ATOMIC_REGION_GEN_DEBUG) { Debug.WriteLine(graph); } primitives = new List <Primitive>(); ExtractPrimitives(); }
public bool HasThisExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph, Segment segment) { if (!points.Contains(segment.Point1)) { return(false); } if (!points.Contains(segment.Point2)) { return(false); } return(graph.GetEdgeType(segment.Point1, segment.Point2) == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT); }
private Atomizer.AtomicRegion PolygonDefinesRegion(UndirectedPlanarGraph.PlanarGraph graph) { List <Segment> sides = new List <Segment>(); // // All connections between adjacent connections MUST be segments. // for (int p = 0; p < points.Count; p++) { Segment segment = new Segment(points[p], points[(p + 1) % points.Count]); sides.Add(segment); if (graph.GetEdge(points[p], points[(p + 1) % points.Count]).edgeType != UndirectedPlanarGraph.EdgeType.REAL_SEGMENT) { return(null); } } // // All iterative connections cannot be arcs. // for (int p1 = 0; p1 < points.Count - 1; p1++) { // We want to check for a direct cycle, therefore, p2 starts at p1 not p1 + 1 for (int p2 = p1; p2 < points.Count; p2++) { UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p1], points[(p2 + 1) % points.Count]); if (edge != null) { if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC) { return(null); } } } } // // Make the Polygon // Polygon poly = Polygon.MakePolygon(sides); if (poly == null) { throw new ArgumentException("Real segments should define a polygon; they did not."); } return(new ShapeAtomicRegion(poly)); }
private static int GetComposableCycleWithSegment(UndirectedPlanarGraph.PlanarGraph graph, List <MinimalCycle> cycles, GeometryTutorLib.ConcreteAST.Segment segment) { for (int c = 0; c < cycles.Count; c++) { if (cycles[c].HasThisExtendedSegment(graph, segment)) { return(c); } } return(-1); }
// // Collect all segments attributed to this this cycle // private List <Segment> CollectSegments(UndirectedPlanarGraph.PlanarGraph graph) { List <Segment> segments = new List <Segment>(); for (int p = 0; p < points.Count; p++) { UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]); if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_SEGMENT) { segments.Add(new Segment(points[p], points[(p + 1) % points.Count])); } } return(segments); }
//// //// Determine the number of intersection points between this atomic region and a segment. //// //public List<KeyValuePair<Point, Connection>> GetIntersections(Circle circle, Point endpt1, Point endp12) //{ // List<KeyValuePair<Point, Connection>> intersections = new List<KeyValuePair<Point, Connection>>(); // Point pt1 = null; // Point pt2 = null; // foreach (Connection conn in connections) // { // conn.FindIntersection(that, out pt1, out pt2); // if (pt1 != null) intersections.Add(new KeyValuePair<Point, Connection>(pt1, conn)); // if (pt2 != null) intersections.Add(new KeyValuePair<Point, Connection>(pt2, conn)); // // A segment should only intersect an atomic region in 2 places. // if (intersections.Count >= 2) break; // } // return intersections; //} // // Convert an atomic region to a planar graph. // public UndirectedPlanarGraph.PlanarGraph ConvertToPlanarGraph() { UndirectedPlanarGraph.PlanarGraph graph = new UndirectedPlanarGraph.PlanarGraph(); if (!ordered) { OrderConnections(); } // // Traverse the connections and add vertices / edges // foreach (Connection conn in connections) { graph.AddNode(conn.endpoint1); graph.AddNode(conn.endpoint2); graph.AddUndirectedEdge(conn.endpoint1, conn.endpoint2, new Segment(conn.endpoint1, conn.endpoint2).Length, conn.type == ConnectionType.ARC ? UndirectedPlanarGraph.EdgeType.REAL_ARC : UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } return(graph); }
// // If a cycle has an edge that is EXTENDED, there exist two regions, one on each side of the segment; compose the two segments. // // Fixed point algorithm: while there exists a cycle with an extended segment, compose. private static void ComposeCycles(UndirectedPlanarGraph.PlanarGraph graph, List <MinimalCycle> cycles) { for (int cycleIndex = HasComposableCycle(graph, cycles); cycleIndex != -1; cycleIndex = HasComposableCycle(graph, cycles)) { // Get the cycle and remove it from the list. MinimalCycle thisCycle = cycles[cycleIndex]; cycles.RemoveAt(cycleIndex); // Get the extended segment which is the focal segment of composition. GeometryTutorLib.ConcreteAST.Segment extendedSeg = thisCycle.GetExtendedSegment(graph); // Find the matching cycle that has the same Extended segment int otherIndex = GetComposableCycleWithSegment(graph, cycles, extendedSeg); MinimalCycle otherCycle = cycles[otherIndex]; cycles.RemoveAt(otherIndex); // Compose the two cycles into a single cycle. MinimalCycle composed = thisCycle.Compose(otherCycle, extendedSeg); // Add the new, composed cycle cycles.Add(composed); } }
private List <Atomizer.AtomicRegion> MixedArcChordedRegion(List <Circle> thatCircles, UndirectedPlanarGraph.PlanarGraph graph) { List <AtomicRegion> regions = new List <AtomicRegion>(); // Every segment may be have a set of circles. (on each side) surrounding it. // Keep parallel lists of: (1) segments, (2) (real) arcs, (3) left outer circles, and (4) right outer circles Segment[] regionsSegments = new Segment[points.Count]; Arc[] arcSegments = new Arc[points.Count]; Circle[] leftOuterCircles = new Circle[points.Count]; Circle[] rightOuterCircles = new Circle[points.Count]; // // Populate the parallel arrays. // int currCounter = 0; for (int p = 0; p < points.Count;) { UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]); Segment currSegment = new Segment(points[p], points[(p + 1) % points.Count]); // // If a known segment, seek a sequence of collinear segments. // if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_SEGMENT) { Segment actualSeg = currSegment; bool collinearExists = false; int prevPtIndex; for (prevPtIndex = p + 1; prevPtIndex < points.Count; prevPtIndex++) { // Make another segment with the next point. Segment nextSeg = new Segment(points[p], points[(prevPtIndex + 1) % points.Count]); // CTA: This criteria seems invalid in some cases....; may not have collinearity // We hit the end of the line of collinear segments. if (!currSegment.IsCollinearWith(nextSeg)) { break; } collinearExists = true; actualSeg = nextSeg; } // If there exists an arc over the actual segment, we have an embedded circle to consider. regionsSegments[currCounter] = actualSeg; if (collinearExists) { UndirectedPlanarGraph.PlanarGraphEdge collEdge = graph.GetEdge(actualSeg.Point1, actualSeg.Point2); if (collEdge != null) { if (collEdge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC) { // Find all applicable circles List <Circle> circles = GetAllApplicableCircles(thatCircles, actualSeg.Point1, actualSeg.Point2); // Get the exact outer circles for this segment (and create any embedded regions). regions.AddRange(ConvertToCircleCircle(actualSeg, circles, out leftOuterCircles[currCounter], out rightOuterCircles[currCounter])); } } } currCounter++; p = prevPtIndex; } else if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_DUAL) { regionsSegments[currCounter] = new Segment(points[p], points[(p + 1) % points.Count]); // Get the exact chord and set of circles Segment chord = regionsSegments[currCounter]; // Find all applicable circles List <Circle> circles = GetAllApplicableCircles(thatCircles, points[p], points[(p + 1) % points.Count]); // Get the exact outer circles for this segment (and create any embedded regions). regions.AddRange(ConvertToCircleCircle(chord, circles, out leftOuterCircles[currCounter], out rightOuterCircles[currCounter])); currCounter++; p++; } else if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC) { // // Find the unique circle that contains these two points. // (if more than one circle has these points, we would have had more intersections and it would be a direct chorded region) // List <Circle> circles = GetAllApplicableCircles(thatCircles, points[p], points[(p + 1) % points.Count]); if (circles.Count != 1) { throw new Exception("Need ONLY 1 circle for REAL_ARC atom id; found (" + circles.Count + ")"); } arcSegments[currCounter++] = new MinorArc(circles[0], points[p], points[(p + 1) % points.Count]); p++; } } // // Check to see if this is a region in which some connections are segments and some are arcs. // This means there were no REAL_DUAL edges. // List <AtomicRegion> generalRegions = GeneralAtomicRegion(regionsSegments, arcSegments); if (generalRegions.Any()) { return(generalRegions); } // Copy the segments into a list (ensuring no nulls) List <Segment> actSegments = new List <Segment>(); foreach (Segment side in regionsSegments) { if (side != null) { actSegments.Add(side); } } // Construct a polygon out of the straight-up segments // This might be a polygon that defines a pathological region. Polygon poly = Polygon.MakePolygon(actSegments); // Determine which outermost circles apply inside of this polygon. Circle[] circlesCutInsidePoly = new Circle[actSegments.Count]; for (int p = 0; p < actSegments.Count; p++) { if (leftOuterCircles[p] != null && rightOuterCircles[p] == null) { circlesCutInsidePoly[p] = CheckCircleCutInsidePolygon(poly, leftOuterCircles[p], actSegments[p].Point1, actSegments[p].Point2); } else if (leftOuterCircles[p] == null && rightOuterCircles[p] != null) { circlesCutInsidePoly[p] = CheckCircleCutInsidePolygon(poly, rightOuterCircles[p], actSegments[p].Point1, actSegments[p].Point2); } else if (leftOuterCircles[p] != null && rightOuterCircles[p] != null) { circlesCutInsidePoly[p] = CheckCircleCutInsidePolygon(poly, leftOuterCircles[p], actSegments[p].Point1, actSegments[p].Point2); if (circlesCutInsidePoly[p] == null) { circlesCutInsidePoly[p] = rightOuterCircles[p]; } } else { circlesCutInsidePoly[p] = null; } } bool isStrictPoly = true; for (int p = 0; p < actSegments.Count; p++) { if (circlesCutInsidePoly[p] != null || arcSegments[p] != null) { isStrictPoly = false; break; } } // This is just a normal shape region: polygon. if (isStrictPoly) { regions.Add(new ShapeAtomicRegion(poly)); } // A circle cuts into the polygon. else { // // Now that all interior arcs have been identified, construct the atomic (probably pathological) region // AtomicRegion pathological = new AtomicRegion(); for (int p = 0; p < actSegments.Count; p++) { // // A circle cutting inside the polygon // if (circlesCutInsidePoly[p] != null) { Arc theArc = null; if (circlesCutInsidePoly[p].DefinesDiameter(regionsSegments[p])) { Point midpt = circlesCutInsidePoly[p].Midpoint(regionsSegments[p].Point1, regionsSegments[p].Point2); if (!poly.IsInPolygon(midpt)) { midpt = circlesCutInsidePoly[p].OppositePoint(midpt); } theArc = new Semicircle(circlesCutInsidePoly[p], regionsSegments[p].Point1, regionsSegments[p].Point2, midpt, regionsSegments[p]); } else { theArc = new MinorArc(circlesCutInsidePoly[p], regionsSegments[p].Point1, regionsSegments[p].Point2); } pathological.AddConnection(regionsSegments[p].Point1, regionsSegments[p].Point2, ConnectionType.ARC, theArc); } // else { // We have a direct arc if (arcSegments[p] != null) { pathological.AddConnection(regionsSegments[p].Point1, regionsSegments[p].Point2, ConnectionType.ARC, arcSegments[p]); } // Use the segment else { pathological.AddConnection(regionsSegments[p].Point1, regionsSegments[p].Point2, ConnectionType.SEGMENT, regionsSegments[p]); } } } regions.Add(pathological); } return(regions); }
public bool HasExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph) { return(GetExtendedSegment(graph) != null); }
private List <Atomizer.AtomicRegion> SectorOrTruncationDefinesRegion(List <Circle> circles, UndirectedPlanarGraph.PlanarGraph graph) { // // Do there exist any real-dual edges or extended segments? If so, this is not a sector. // for (int p = 0; p < points.Count; p++) { UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]); if (edge.edgeType == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT) { return(null); } else if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_DUAL) { return(null); } } // // Collect all segments; split into two collinear lists. // List <Segment> segments = CollectSegments(graph); List <List <Segment> > collinearSegmentSet = SplitSegmentsIntoCollinearSequences(segments); // A sector requires one (semicircl) or two sets of segments ('normal' arc). if (collinearSegmentSet.Count > 2) { return(null); } // // Collect all arcs. // List <MinorArc> arcs = CollectStrictArcs(circles, graph); List <List <MinorArc> > collinearArcSet = SplitArcsIntoCollinearSequences(arcs); // A sector requires one set of arcs (no more, no less). if (collinearArcSet.Count != 1) { return(null); } // Semicircle has one set of sides if (collinearSegmentSet.Count == 1) { return(ConvertToTruncationOrSemicircle(collinearSegmentSet[0], collinearArcSet[0])); } // Pacman shape created with a circle results in Sector return(ConvertToGeneralSector(collinearSegmentSet[0], collinearSegmentSet[1], collinearArcSet[0])); }
// // // Create the actual set of atomic regions for this cycle. // // We need to check to see if any of the cycle segments are based on arcs. // We have to handle the degree of each segment: do many circles intersect at these points? // public List <Atomizer.AtomicRegion> ConstructAtomicRegions(List <Circle> circles, UndirectedPlanarGraph.PlanarGraph graph) { List <Atomizer.AtomicRegion> regions = new List <Atomizer.AtomicRegion>(); Atomizer.AtomicRegion region = null; // // Check for a direct polygon (no arcs). // region = PolygonDefinesRegion(graph); if (region != null) { regions.Add(region); return(regions); } // // Does this region define a sector? // List <AtomicRegion> sectors = SectorOrTruncationDefinesRegion(circles, graph); if (sectors != null && sectors.Any()) { regions.AddRange(sectors); return(regions); } // // Do we have a set of regions defined by a polygon in which circle(s) cut out some of that region? // regions.AddRange(MixedArcChordedRegion(circles, graph)); return(regions); }
//// //// Determine the number of intersection points between this atomic region and a segment. //// //public List<KeyValuePair<Point, Connection>> GetIntersections(Circle circle, Point endpt1, Point endp12) //{ // List<KeyValuePair<Point, Connection>> intersections = new List<KeyValuePair<Point, Connection>>(); // Point pt1 = null; // Point pt2 = null; // foreach (Connection conn in connections) // { // conn.FindIntersection(that, out pt1, out pt2); // if (pt1 != null) intersections.Add(new KeyValuePair<Point, Connection>(pt1, conn)); // if (pt2 != null) intersections.Add(new KeyValuePair<Point, Connection>(pt2, conn)); // // A segment should only intersect an atomic region in 2 places. // if (intersections.Count >= 2) break; // } // return intersections; //} // // Convert an atomic region to a planar graph. // public UndirectedPlanarGraph.PlanarGraph ConvertToPlanarGraph() { UndirectedPlanarGraph.PlanarGraph graph = new UndirectedPlanarGraph.PlanarGraph(); if (!ordered) OrderConnections(); // // Traverse the connections and add vertices / edges // foreach (Connection conn in connections) { graph.AddNode(conn.endpoint1); graph.AddNode(conn.endpoint2); graph.AddUndirectedEdge(conn.endpoint1, conn.endpoint2, new Segment(conn.endpoint1, conn.endpoint2).Length, conn.type == ConnectionType.ARC ? UndirectedPlanarGraph.EdgeType.REAL_ARC : UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } return graph; }
// // The order of the points in the filament were established by the algorithm // Recursively seek smaller and smaller circular regions. // // Returns the set of atomic regions characterized by the largest circle (containing all the other atoms). private Agg MakeRegions(UndirectedPlanarGraph.PlanarGraph graph, List <Circle> circles, int beginIndex, int endIndex) { if (memoized[beginIndex, endIndex] != null) { return(memoized[beginIndex, endIndex]); } // // Find the circle for these given points. // Circle outerCircle = null; foreach (Circle circle in circles) { if (circle.PointLiesOn(points[beginIndex]) && circle.PointLiesOn(points[endIndex])) { outerCircle = circle; } } // // Base Case: Gap between the given indices is 1. // if (endIndex - beginIndex == 1) { return(new Agg(beginIndex, endIndex, -1, outerCircle, HandleConnection(graph, circles, points[beginIndex], points[endIndex]))); } // // Look at all combinations of indices from beginIndex to endIndex; start with larger gaps between indices -> small gaps // Agg maxLeftCoveredAgg = null; Agg maxRightCoveredAgg = null; int maxCoveredNodes = 0; for (int gap = endIndex - beginIndex - 1; gap > 0; gap--) { for (int index = beginIndex; index < endIndex; index++) { Agg left = MakeRegions(graph, circles, index, index + gap); Agg right = MakeRegions(graph, circles, index + gap, endIndex); // Check for new maxmimum coverage. if (left.coveredPoints + right.coveredPoints > maxCoveredNodes) { maxLeftCoveredAgg = left; maxRightCoveredAgg = right; } // Found complete coverage if (left.coveredPoints + right.coveredPoints == endIndex - beginIndex + 1) { maxCoveredNodes = endIndex - beginIndex + 1; break; } } } // // We have the two maximal circles: create the new regions. // // The atoms from the left / right. List <AtomicRegion> atoms = new List <AtomicRegion>(); atoms.AddRange(maxLeftCoveredAgg.atoms); atoms.AddRange(maxRightCoveredAgg.atoms); // New regions are based on this outer circle minus the left / right outer circles. AtomicRegion newAtomTop = new AtomicRegion(); AtomicRegion newAtomBottom = new AtomicRegion(); // The outer circle. newAtomTop.AddConnection(points[beginIndex], points[endIndex], ConnectionType.ARC, outerCircle); newAtomBottom.AddConnection(points[beginIndex], points[endIndex], ConnectionType.ARC, outerCircle); // The left / right maximal circles. newAtomTop.AddConnection(points[maxLeftCoveredAgg.beginPointIndex], points[maxLeftCoveredAgg.endPointIndex], ConnectionType.ARC, maxLeftCoveredAgg.outerCircle); newAtomBottom.AddConnection(points[maxLeftCoveredAgg.beginPointIndex], points[maxLeftCoveredAgg.endPointIndex], ConnectionType.ARC, maxLeftCoveredAgg.outerCircle); newAtomTop.AddConnection(points[maxRightCoveredAgg.beginPointIndex], points[maxRightCoveredAgg.endPointIndex], ConnectionType.ARC, maxRightCoveredAgg.outerCircle); newAtomBottom.AddConnection(points[maxRightCoveredAgg.beginPointIndex], points[maxRightCoveredAgg.endPointIndex], ConnectionType.ARC, maxRightCoveredAgg.outerCircle); atoms.Add(newAtomTop); atoms.Add(newAtomBottom); // // Make / return the new aggregator // return(new Agg(beginIndex, endIndex, maxCoveredNodes, outerCircle, atoms)); }