// Construct the region between a circle and circle: // __ // ( ( // ( ( // ( ( // ( ( // ( ( // -- private Atomizer.AtomicRegion ConstructBasicCircleCircleRegion(Segment chord, Circle smaller, Circle larger) { AtomicRegion region = new AtomicRegion(); Arc arc1 = null; if (smaller.DefinesDiameter(chord)) { Point midpt = smaller.Midpoint(chord.Point1, chord.Point2, larger.Midpoint(chord.Point1, chord.Point2)); arc1 = new Semicircle(smaller, chord.Point1, chord.Point2, midpt, chord); } else { arc1 = new MinorArc(smaller, chord.Point1, chord.Point2); } MinorArc arc2 = new MinorArc(larger, chord.Point1, chord.Point2); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, arc1); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, arc2); return(region); }
private List <Atomizer.AtomicRegion> ConvertToTruncation(Segment chord, MinorArc arc) { AtomicRegion atom = new AtomicRegion(); atom.AddConnection(new Connection(chord.Point1, chord.Point2, ConnectionType.SEGMENT, chord)); atom.AddConnection(new Connection(chord.Point1, chord.Point2, ConnectionType.ARC, arc)); return(Utilities.MakeList <AtomicRegion>(atom)); }
// Construct the region between a chord and the circle arc: // (| // ( | // ( | // ( | // (| // private List <AtomicRegion> ConstructBasicLineCircleRegion(Segment chord, Circle circle) { // // Standard // if (!circle.DefinesDiameter(chord)) { AtomicRegion region = new AtomicRegion(); Arc theArc = new MinorArc(circle, chord.Point1, chord.Point2); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, theArc); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.SEGMENT, chord); return(Utilities.MakeList <AtomicRegion>(region)); } // // Semi-circles // Point midpt = circle.Midpoint(chord.Point1, chord.Point2); Arc semi1 = new Semicircle(circle, chord.Point1, chord.Point2, midpt, chord); ShapeAtomicRegion region1 = new ShapeAtomicRegion(new Sector(semi1)); Point opp = circle.OppositePoint(midpt); Arc semi2 = new Semicircle(circle, chord.Point1, chord.Point2, opp, chord); ShapeAtomicRegion region2 = new ShapeAtomicRegion(new Sector(semi2)); List <AtomicRegion> regions = new List <AtomicRegion>(); regions.Add(region1); regions.Add(region2); return(regions); }
// // Determine if this is a true polygon situation or if it is a sequence of segments and arcs. // private List <AtomicRegion> GeneralAtomicRegion(Segment[] segments, Arc[] arcs) { List <AtomicRegion> regions = new List <AtomicRegion>(); // // Determine if the parts are all segments. // Concurrently determine the proper starting point in the sequence to construct the atomic region. // bool hasArc = false; bool hasSegment = false; int startIndex = 0; for (int i = 0; i < segments.Length && i < arcs.Length; i++) { // Both an arc and a segment. if (segments[i] != null && arcs[i] != null) { return(regions); } // Determine if we have an arc and/or a segment. if (segments[i] != null) { hasSegment = true; } if (arcs[i] != null) { hasArc = true; } // A solid starting point is an arc right after a null. if (arcs[i] == null && arcs[(i + 1) % arcs.Length] != null) { // Assign only once to the startIndex if (startIndex == 0) { startIndex = (i + 1) % arcs.Length; } } } // If only segments, we have a polygon. if (hasSegment && !hasArc) { return(regions); } // // If the set ONLY consists of arcs, ensure we have a good starting point. // if (hasArc && !hasSegment) { // Seek the first index where a change among arcs occurs. for (int i = 0; i < arcs.Length; i++) { // A solid starting point is an arc right after a null. if (!arcs[i].theCircle.StructurallyEquals(arcs[(i + 1) % arcs.Length].theCircle)) { startIndex = (i + 1) % arcs.Length; break; } } } AtomicRegion theRegion = new AtomicRegion(); for (int i = 0; i < segments.Length && i < arcs.Length; i++) { int currIndex = (i + startIndex) % arcs.Length; if (segments[currIndex] == null && arcs[currIndex] == null) /* No-Op */ } { if (segments[currIndex] != null) { theRegion.AddConnection(new Connection(segments[currIndex].Point1, segments[currIndex].Point2, ConnectionType.SEGMENT, segments[currIndex])); } else if (arcs[currIndex] != null) { // // Compose the arcs (from a single circle) together. // List <MinorArc> sequentialArcs = new List <MinorArc>(); sequentialArcs.Add(arcs[currIndex] as MinorArc); int seqIndex; for (seqIndex = (currIndex + 1) % arcs.Length; ; seqIndex = (seqIndex + 1) % arcs.Length, i++) { if (arcs[seqIndex] == null) { break; } if (arcs[currIndex].theCircle.StructurallyEquals(arcs[seqIndex].theCircle)) { sequentialArcs.Add(arcs[seqIndex] as MinorArc); } else { break; } } Arc composed; if (sequentialArcs.Count > 1) { composed = this.ComposeArcsIntoArc(sequentialArcs); } else { composed = arcs[currIndex]; } // // Add the connection. // theRegion.AddConnection(new Connection(composed.endpoint1, composed.endpoint2, ConnectionType.ARC, composed)); } } return(Utilities.MakeList <AtomicRegion>(theRegion)); }
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); }
// // 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); }
// // 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)); }
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; }
// // Determine if this is a true polygon situation or if it is a sequence of segments and arcs. // private List<AtomicRegion> GeneralAtomicRegion(Segment[] segments, Arc[] arcs) { List<AtomicRegion> regions = new List<AtomicRegion>(); // // Determine if the parts are all segments. // Concurrently determine the proper starting point in the sequence to construct the atomic region. // bool hasArc = false; bool hasSegment = false; int startIndex = 0; for (int i = 0; i < segments.Length && i < arcs.Length; i++) { // Both an arc and a segment. if (segments[i] != null && arcs[i] != null) return regions; // Determine if we have an arc and/or a segment. if (segments[i] != null) hasSegment = true; if (arcs[i] != null) hasArc = true; // A solid starting point is an arc right after a null. if (arcs[i] == null && arcs[(i + 1) % arcs.Length] != null) { // Assign only once to the startIndex if (startIndex == 0) startIndex = (i + 1) % arcs.Length; } } // If only segments, we have a polygon. if (hasSegment && !hasArc) return regions; // // If the set ONLY consists of arcs, ensure we have a good starting point. // if (hasArc && !hasSegment) { // Seek the first index where a change among arcs occurs. for (int i = 0; i < arcs.Length; i++) { // A solid starting point is an arc right after a null. if (!arcs[i].theCircle.StructurallyEquals(arcs[(i + 1) % arcs.Length].theCircle)) { startIndex = (i + 1) % arcs.Length; break; } } } AtomicRegion theRegion = new AtomicRegion(); for (int i = 0; i < segments.Length && i < arcs.Length; i++) { int currIndex = (i + startIndex) % arcs.Length; if (segments[currIndex] == null && arcs[currIndex] == null) { /* No-Op */ } if (segments[currIndex] != null) { theRegion.AddConnection(new Connection(segments[currIndex].Point1, segments[currIndex].Point2, ConnectionType.SEGMENT, segments[currIndex])); } else if (arcs[currIndex] != null) { // // Compose the arcs (from a single circle) together. // List<MinorArc> sequentialArcs = new List<MinorArc>(); sequentialArcs.Add(arcs[currIndex] as MinorArc); int seqIndex; for (seqIndex = (currIndex + 1) % arcs.Length; ; seqIndex = (seqIndex + 1) % arcs.Length, i++) { if (arcs[seqIndex] == null) break; if (arcs[currIndex].theCircle.StructurallyEquals(arcs[seqIndex].theCircle)) { sequentialArcs.Add(arcs[seqIndex] as MinorArc); } else break; } Arc composed; if (sequentialArcs.Count > 1) composed = this.ComposeArcsIntoArc(sequentialArcs); else composed = arcs[currIndex]; // // Add the connection. // theRegion.AddConnection(new Connection(composed.endpoint1, composed.endpoint2, ConnectionType.ARC, composed)); } } return Utilities.MakeList<AtomicRegion>(theRegion); }
private List<Atomizer.AtomicRegion> ConvertToTruncation(Segment chord, MinorArc arc) { AtomicRegion atom = new AtomicRegion(); atom.AddConnection(new Connection(chord.Point1, chord.Point2, ConnectionType.SEGMENT, chord)); atom.AddConnection(new Connection(chord.Point1, chord.Point2, ConnectionType.ARC, arc)); return Utilities.MakeList<AtomicRegion>(atom); }
// Construct the region between a chord and the circle arc: // (| // ( | // ( | // ( | // (| // private List<AtomicRegion> ConstructBasicLineCircleRegion(Segment chord, Circle circle) { // // Standard // if (!circle.DefinesDiameter(chord)) { AtomicRegion region = new AtomicRegion(); Arc theArc = new MinorArc(circle, chord.Point1, chord.Point2); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, theArc); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.SEGMENT, chord); return Utilities.MakeList<AtomicRegion>(region); } // // Semi-circles // Point midpt = circle.Midpoint(chord.Point1, chord.Point2); Arc semi1 = new Semicircle(circle, chord.Point1, chord.Point2, midpt, chord); ShapeAtomicRegion region1 = new ShapeAtomicRegion(new Sector(semi1)); Point opp = circle.OppositePoint(midpt); Arc semi2 = new Semicircle(circle, chord.Point1, chord.Point2, opp, chord); ShapeAtomicRegion region2 = new ShapeAtomicRegion(new Sector(semi2)); List<AtomicRegion> regions = new List<AtomicRegion>(); regions.Add(region1); regions.Add(region2); return regions; }
// Construct the region between a circle and circle: // __ // ( ( // ( ( // ( ( // ( ( // ( ( // -- private Atomizer.AtomicRegion ConstructBasicCircleCircleRegion(Segment chord, Circle smaller, Circle larger) { AtomicRegion region = new AtomicRegion(); Arc arc1 = null; if (smaller.DefinesDiameter(chord)) { Point midpt = smaller.Midpoint(chord.Point1, chord.Point2, larger.Midpoint(chord.Point1, chord.Point2)); arc1 = new Semicircle(smaller, chord.Point1, chord.Point2, midpt, chord); } else { arc1 = new MinorArc(smaller, chord.Point1, chord.Point2); } MinorArc arc2 = new MinorArc(larger, chord.Point1, chord.Point2); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, arc1); region.AddConnection(chord.Point1, chord.Point2, ConnectionType.ARC, arc2); return region; }