//// //// The given atomic region is the 'outside' perimeter. //// All information is based on intersection points inside or on the perimeter. //// //List<AtomicRegion> Compose(List<Point> figurePoints, AtomicRegion theAtom, // List<AtomicRegion> intersecting, List<AtomicRegion> contained) //{ // List<AtomicRegion> atoms = new List<AtomicRegion>(); // foreach (AtomicRegion // return atoms; //} // // Combine two atoms together into a set of atomic regions. // toadd refers to atomic regions that are new / modified. // toRemove is a subset of the atoms that may be removed from the worklist since they have been replaced as a non-atomic. // public static void Compose(List <Point> figurePoints, AtomicRegion thisAtom, AtomicRegion thatAtom, out List <AtomicRegion> toAdd, out List <AtomicRegion> toRemove) { toAdd = new List <AtomicRegion>(); toRemove = new List <AtomicRegion>(); // // Do these regions interact at all? // if (thisAtom.OnExteriorOf(thatAtom)) { return; } // // If there is a single inscribed node then this is containment. // If there are no intersections then the regions may be (1) disjoint or (2) containment. // if (thisAtom.StrictlyContains(thatAtom) || thisAtom.ContainsWithOneInscription(thatAtom)) { //AtomicRegion diff = GenerateDifferenceRegion(thisAtom, thatAtom); //toAdd(diff); //toRemove.Add(thisAtom); //return; } if (thatAtom.StrictlyContains(thisAtom) || thatAtom.ContainsWithOneInscription(thisAtom)) { // return GenerateDifferenceRegion(thatAtom, thisAtom); } // // The atoms overlap. // Overlap(figurePoints, thisAtom, thatAtom, out toAdd, out toRemove); }
public DifferenceAtomicRegion(AtomicRegion outer, AtomicRegion inner) : base() { outerShape = outer; innerShapes = new List<AtomicRegion>(); innerShapes.Add(inner); }
//// //// The given atomic region is the 'outside' perimeter. //// All information is based on intersection points inside or on the perimeter. //// //List<AtomicRegion> Compose(List<Point> figurePoints, AtomicRegion theAtom, // List<AtomicRegion> intersecting, List<AtomicRegion> contained) //{ // List<AtomicRegion> atoms = new List<AtomicRegion>(); // foreach (AtomicRegion // return atoms; //} // // Combine two atoms together into a set of atomic regions. // toadd refers to atomic regions that are new / modified. // toRemove is a subset of the atoms that may be removed from the worklist since they have been replaced as a non-atomic. // public static void Compose(List<Point> figurePoints, AtomicRegion thisAtom, AtomicRegion thatAtom, out List<AtomicRegion> toAdd, out List<AtomicRegion> toRemove) { toAdd = new List<AtomicRegion>(); toRemove = new List<AtomicRegion>(); // // Do these regions interact at all? // if (thisAtom.OnExteriorOf(thatAtom)) return; // // If there is a single inscribed node then this is containment. // If there are no intersections then the regions may be (1) disjoint or (2) containment. // if (thisAtom.StrictlyContains(thatAtom) || thisAtom.ContainsWithOneInscription(thatAtom)) { //AtomicRegion diff = GenerateDifferenceRegion(thisAtom, thatAtom); //toAdd(diff); //toRemove.Add(thisAtom); //return; } if (thatAtom.StrictlyContains(thisAtom) || thatAtom.ContainsWithOneInscription(thisAtom)) { // return GenerateDifferenceRegion(thatAtom, thisAtom); } // // The atoms overlap. // Overlap(figurePoints, thisAtom, thatAtom, out toAdd, out toRemove); }
// 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); }
public override bool CoordinateCongruent(AtomicRegion that) { ShapeAtomicRegion shapeAtom = that as ShapeAtomicRegion; if (shapeAtom == null) return false; return this.shape.CoordinateCongruent(shapeAtom.shape); }
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)); }
// // Do all the endpoints in that region lie within this region? // And, are all intersection points, if any, on this perimeter? // public virtual bool Contains(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List <Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOnOrInside(vertex)) { return(false); } } // // Check all midpoints of conenctions are on the interior. // foreach (Connection thatConn in that.connections) { if (!this.PointLiesOnOrInside(thatConn.Midpoint())) { return(false); } } // // For any intersections between the atomic regions, the resultant points of intersection must be on the perimeter. // List <IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { if (!this.PointLiesOn(agg.intersection1)) { return(false); } if (agg.intersection2 != null) { if (!this.PointLiesOn(agg.intersection2)) { return(false); } } } } return(true); }
public override bool CoordinateCongruent(AtomicRegion that) { ShapeAtomicRegion shapeAtom = that as ShapeAtomicRegion; if (shapeAtom == null) { return(false); } return(this.shape.CoordinateCongruent(shapeAtom.shape)); }
public void AddAtomicRegion(AtomicRegion atom) { // Avoid adding an atomic region which is itself //if (atom is ShapeAtomicRegion) //{ // if ((atom as ShapeAtomicRegion).shape.StructurallyEquals(this)) return; //} if (atoms.Contains(atom)) return; atoms.Add(atom); }
public bool HasInnerAtom(AtomicRegion that) { foreach (AtomicRegion inner in innerShapes) { if (inner.Equals(that)) { return(true); } } return(false); }
public override bool Contains(AtomicRegion that) { ShapeAtomicRegion thatAtom = that as ShapeAtomicRegion; if (thatAtom != null) { return(this.shape.Contains(thatAtom.shape)); } else { return(base.Contains(that)); } }
public override bool Contains(AtomicRegion that) { ShapeAtomicRegion thatAtom = that as ShapeAtomicRegion; if (thatAtom != null) { return this.shape.Contains(thatAtom.shape); } else { return base.Contains(that); } }
// // All vertices of that region on the perimeter of this. // Number of intersections must equate to the number of vertices. // public bool Inscribed(AtomicRegion that) { List <Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOn(vertex)) { return(false); } } return(this.GetIntersections(that).Count == thatVertices.Count); }
public bool HasVertexExteriorTo(AtomicRegion that) { List <IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (!agg.overlap) { if (!this.PointLiesOnOrInside(agg.intersection1)) { return(true); } } } return(false); }
// // Do all the endpoints in that region lie within this region? // There should be no intersection points. // public bool StrictlyContains(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List <Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesInside(vertex)) { return(false); } } // There should be no intersections return(!this.GetIntersections(that).Any()); }
// // A region (that) lies inside this with one intersection. // public bool ContainsWithGreaterOneInscription(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List <Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOnOrInside(vertex)) { return(false); } } // There should be only ONE intersection return(this.GetIntersections(that).Count > 1); }
private static void SplitConnections(AtomicRegion atom, out List <Segment> segs, out List <Arc> arcs) { segs = new List <Segment>(); arcs = new List <Arc>(); foreach (Connection conn in atom.connections) { if (conn.segmentOrArc != null) { if (conn.type == ConnectionType.SEGMENT) { segs.Add(conn.segmentOrArc as Segment); } if (conn.type == ConnectionType.ARC) { arcs.Add(conn.segmentOrArc as Arc); } } } }
public bool OverlapsWith(AtomicRegion that) { // Point based overlapping. if (Overlap(that.GetApproximatingPoints())) { return(true); } // Crossing-based overlap. List <IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.thisConn.Crosses(agg.thatConn)) { return(true); } } return(false); }
// // Imagine 2 equilateral triangles to make the Star of David: all // public bool OverlapWithSingleConnections(AtomicRegion that) { List <IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { if (agg.intersection1 == null || agg.intersection2 == null) { return(false); } } } return(true); }
// // If there is no interaction between these atomic regions OR just touching // public bool InteriorOfWithTouching(AtomicRegion that) { List <IntersectionAgg> intersections = this.GetIntersections(that); // All vertices cannot be interior to the region. List <Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (this.PointLiesOnOrInside(vertex)) { return(false); } } // All intersections must overlap; only point-based intersections which are on the perimeter. foreach (IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { if (PointLiesExterior(agg.intersection1)) { return(false); } if (agg.intersection2 != null) { if (PointLiesExterior(agg.intersection2)) { return(false); } } } } return(true); }
// 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); }
private List <IntersectionAgg> GetIntersections(AtomicRegion thatAtom) { List <IntersectionAgg> intersections = new List <IntersectionAgg>(); foreach (Connection thisConn in this.connections) { foreach (Connection thatConn in thatAtom.connections) { Point inter1 = null; Point inter2 = null; thisConn.FindIntersection(thatConn, out inter1, out inter2); if (thisConn.Overlap(thatConn)) { IntersectionAgg newAgg = new IntersectionAgg(); newAgg.thisConn = thisConn; newAgg.thatConn = thatConn; newAgg.intersection1 = null; newAgg.intersection2 = null; newAgg.overlap = true; AddIntersection(intersections, newAgg); } else if (inter1 != null) { IntersectionAgg newAgg = new IntersectionAgg(); newAgg.thisConn = thisConn; newAgg.thatConn = thatConn; newAgg.intersection1 = inter1; newAgg.intersection2 = inter2; newAgg.overlap = thisConn.Overlap(thatConn); AddIntersection(intersections, newAgg); } } } return(intersections); }
public override bool Equals(Object obj) { AtomicRegion thatAtom = obj as AtomicRegion; if (thatAtom == null) { return(false); } if (this.connections.Count != thatAtom.connections.Count) { return(false); } foreach (Connection conn in this.connections) { if (!thatAtom.HasConnection(conn)) { return(false); } } return(true); }
private List<IntersectionAgg> GetIntersections(AtomicRegion thatAtom) { List<IntersectionAgg> intersections = new List<IntersectionAgg>(); foreach (Connection thisConn in this.connections) { foreach (Connection thatConn in thatAtom.connections) { Point inter1 = null; Point inter2 = null; thisConn.FindIntersection(thatConn, out inter1, out inter2); if (thisConn.Overlap(thatConn)) { IntersectionAgg newAgg = new IntersectionAgg(); newAgg.thisConn = thisConn; newAgg.thatConn = thatConn; newAgg.intersection1 = null; newAgg.intersection2 = null; newAgg.overlap = true; AddIntersection(intersections, newAgg); } else if (inter1 != null) { IntersectionAgg newAgg = new IntersectionAgg(); newAgg.thisConn = thisConn; newAgg.thatConn = thatConn; newAgg.intersection1 = inter1; newAgg.intersection2 = inter2; newAgg.overlap = thisConn.Overlap(thatConn); AddIntersection(intersections, newAgg); } } } return intersections; }
private static void SplitConnections(AtomicRegion atom, out List<Segment> segs, out List<Arc> arcs) { segs = new List<Segment>(); arcs = new List<Arc>(); foreach (Connection conn in atom.connections) { if (conn.segmentOrArc != null) { if (conn.type == ConnectionType.SEGMENT) segs.Add(conn.segmentOrArc as Segment); if (conn.type == ConnectionType.ARC) arcs.Add(conn.segmentOrArc as Arc); } } }
// // Do all the endpoints in that region lie within this region? // There should be no intersection points. // public bool StrictlyContains(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List<Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesInside(vertex)) return false; } // There should be no intersections return !this.GetIntersections(that).Any(); }
// // Imagine 2 equilateral triangles to make the Star of David: all // public bool OverlapWithSingleConnections(AtomicRegion that) { List<IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { if (agg.intersection1 == null || agg.intersection2 == null) return false; } } return true; }
// // 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); }
public virtual bool CoordinateCongruent(AtomicRegion that) { throw new NotImplementedException(); }
private static bool AddAtom(List<AtomicRegion> atoms, AtomicRegion atom) { if (atoms.Contains(atom)) return false; atoms.Add(atom); return true; }
public Region(Atomizer.AtomicRegion atom) : this(Utilities.MakeList <Atomizer.AtomicRegion>(atom)) { }
private static List <AtomicRegion> GenerateDifferenceRegion(AtomicRegion outer, AtomicRegion inner) { return(Utilities.MakeList <AtomicRegion>(new DifferenceAtomicRegion(outer, inner))); }
// // 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; }
public bool Circumscribed(AtomicRegion that) { return that.Inscribed(this); }
// // 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)); }
/// <summary> /// Create a new ShadedRegion /// </summary> /// <param name="region">The region to shade</param> public ShadedRegion(AtomicRegion region) { Region = region; }
public bool Circumscribed(AtomicRegion that) { return(that.Inscribed(this)); }
public DifferenceAtomicRegion(AtomicRegion outer, AtomicRegion inner) : base() { outerShape = outer; innerShapes = new List <AtomicRegion>(); innerShapes.Add(inner); }
public bool HasAtom(Atomizer.AtomicRegion atom) { return(atoms.Contains(atom)); }
public virtual bool CoordinateCongruent(AtomicRegion that) { // // Collect segment and arc connections. // List <Segment> thisSegs = new List <Segment>(); List <Arc> thisArcs = new List <Arc>(); List <Segment> thatSegs = new List <Segment>(); List <Arc> thatArcs = new List <Arc>(); SplitConnections(this, out thisSegs, out thisArcs); SplitConnections(that, out thatSegs, out thatArcs); // // We must have the same number of each type of connections // if (thisSegs.Count != thatSegs.Count) { return(false); } if (thisArcs.Count != thatArcs.Count) { return(false); } // // This is a naive approach since a more formal approach should follow order of connections; should generally work // // // An atomic region must have the same number of segments, each of the same length. // bool[] marked = new bool[thisSegs.Count]; foreach (Segment thisSeg in thisSegs) { bool found = false; for (int c = 0; c < thatSegs.Count; c++) { if (!marked[c]) { if (thisSeg.CoordinateCongruent(thatSegs[c])) { marked[c] = true; found = true; break; } } } if (!found) { return(false); } } // Redundant: // if (marked.Contains(false)) return false; // Exit early if no arcs. if (!thisArcs.Any()) { return(true); } // // An atomic region must have the same number of arcs, each of the same length (using the radius of the circle). // marked = new bool[thisArcs.Count]; foreach (Arc thisArc in thisArcs) { bool found = false; for (int c = 0; c < thatArcs.Count; c++) { if (!marked[c]) { if (thisArc.CoordinateCongruent(thatArcs[c])) { marked[c] = true; found = true; break; } } } if (!found) { return(false); } } // Redundant: // if (marked.Contains(false)) return false; return(true); }
private static void HandleSegmentSegmentIntersections(List<Point> figurePoints, List<Point> points, List<Segment> segments, AtomicRegion outerBounds) { // Segment-Segment for (int s1 = 0; s1 < segments.Count - 1; s1++) { for (int s2 = s1 + 1; s2 < segments.Count; s2++) { Point intersection = segments[s1].FindIntersection(segments[s2]); intersection = GeometryTutorLib.Utilities.AcquirePoint(figurePoints, intersection); if (intersection != null) { if (outerBounds.PointLiesOnOrInside(intersection)) { segments[s1].AddCollinearPoint(intersection); segments[s2].AddCollinearPoint(intersection); // It may be the case that this intersection was due to a completely contained region. GeometryTutorLib.Utilities.AddUnique<Point>(points, intersection); } } } } }
private static void HandleArcArcIntersections(List<Point> figurePoints, List<Point> points, List<Arc> arcs, AtomicRegion outerBounds) { // Arc-Arc for (int a1 = 0; a1 < arcs.Count - 1; a1++) { for (int a2 = a1 + 1; a2 < arcs.Count; a2++) { Point pt1 = null; Point pt2 = null; arcs[a1].theCircle.FindIntersection(arcs[a2].theCircle, out pt1, out pt2); pt1 = GeometryTutorLib.Utilities.AcquirePoint(figurePoints, pt1); pt2 = GeometryTutorLib.Utilities.AcquirePoint(figurePoints, pt2); if (pt1 != null) { if (outerBounds.PointLiesOnOrInside(pt1)) { arcs[a1].AddCollinearPoint(pt1); arcs[a2].AddCollinearPoint(pt1); // It may be the case that this intersection was due to a completely contained region. GeometryTutorLib.Utilities.AddUnique<Point>(points, pt1); } } if (pt2 != null) { if (outerBounds.PointLiesOnOrInside(pt2)) { arcs[a1].AddCollinearPoint(pt2); arcs[a2].AddCollinearPoint(pt2); // It may be the case that this intersection was due to a completely contained region. GeometryTutorLib.Utilities.AddUnique<Point>(points, pt2); } } } } }
private static void HandleSegmentArcIntersections(List<Point> figurePoints, List<Point> points, List<Segment> segments, List<Arc> arcs, AtomicRegion outerBounds) { // Segment-Arc foreach (Segment segment in segments) { foreach (Arc arc in arcs) { Point pt1 = null; Point pt2 = null; arc.theCircle.FindIntersection(segment, out pt1, out pt2); pt1 = GeometryTutorLib.Utilities.AcquirePoint(figurePoints, pt1); pt2 = GeometryTutorLib.Utilities.AcquirePoint(figurePoints, pt2); if (pt1 != null) { if (outerBounds.PointLiesOnOrInside(pt1)) { segment.AddCollinearPoint(pt1); arc.AddCollinearPoint(pt1); // It may be the case that this intersection was due to a completely contained region. GeometryTutorLib.Utilities.AddUnique<Point>(points, pt1); } } if (pt2 != null) { if (outerBounds.PointLiesOnOrInside(pt2)) { segment.AddCollinearPoint(pt2); arc.AddCollinearPoint(pt2); // It may be the case that this intersection was due to a completely contained region. GeometryTutorLib.Utilities.AddUnique<Point>(points, pt2); } } } } }
public bool OverlapsWith(AtomicRegion that) { // Point based overlapping. if (Overlap(that.GetApproximatingPoints())) return true; // Crossing-based overlap. List<IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.thisConn.Crosses(agg.thatConn)) return true; } return false; }
public virtual bool Covers(AtomicRegion a) { throw new NotImplementedException(); }
// // 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; }
// // 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); }
// // All vertices of that region on the perimeter of this. // Number of intersections must equate to the number of vertices. // public bool Inscribed(AtomicRegion that) { List<Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOn(vertex)) return false; } return this.GetIntersections(that).Count == thatVertices.Count; }
// // Does the atom have a connection which intersects the sides of the polygon. // public override bool Covers(AtomicRegion atom) { foreach (Connection conn in atom.connections) { if (conn.type == ConnectionType.SEGMENT) { if (this.Covers(conn.segmentOrArc as Segment)) return true; } else if (conn.type == ConnectionType.ARC) { if (this.Covers(conn.segmentOrArc as Arc)) return true; } } return false; }
// // If there is no interaction between these atomic regions OR just touching // public bool OnExteriorOf(AtomicRegion that) { List<IntersectionAgg> intersections = this.GetIntersections(that); // All vertices cannot be interior to the region. List<Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (this.PointLiesInside(vertex)) return false; } // All intersections must be overlap; only point-based intersections which are on the perimeter. foreach (IntersectionAgg agg in intersections) { if (!agg.overlap) { if (agg.intersection2 != null) return false; if (!this.PointLiesOn(agg.intersection1)) return false; } else // agg.overlap { // No-Op } } return true; }
// // Do all the endpoints in that region lie within this region? // And, are all intersection points, if any, on this perimeter? // public virtual bool Contains(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List<Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOnOrInside(vertex)) return false; } // // Check all midpoints of conenctions are on the interior. // foreach (Connection thatConn in that.connections) { if (!this.PointLiesOnOrInside(thatConn.Midpoint())) return false; } // // For any intersections between the atomic regions, the resultant points of intersection must be on the perimeter. // List<IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { if (!this.PointLiesOn(agg.intersection1)) return false; if (agg.intersection2 != null) { if (!this.PointLiesOn(agg.intersection2)) return false; } } } return true; }
// // Find all regions that overlap this region. // private static void GetInterestingRegions(List<AtomicRegion> atoms, AtomicRegion theAtom, out List<AtomicRegion> intersecting, out List<AtomicRegion> contained) { intersecting = new List<AtomicRegion>(); contained = new List<AtomicRegion>(); foreach (AtomicRegion atom in atoms) { // An atom should not intersect itself. if (!theAtom.Equals(atom)) { if (theAtom.Contains(atom)) { contained.Add(atom); } //else if (theAtom.StrictlyContains(atom)) //{ // contained.Add(theAtom); //} else if (theAtom.OverlapsWith(atom)) { intersecting.Add(atom); } } } }
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); }
// // A region (that) lies inside this with one intersection. // public bool ContainsWithOneInscription(AtomicRegion that) { // // Do all vertices of that lie on the interior of this atomic region? // List<Point> thatVertices = that.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesOnOrInside(vertex)) return false; } // There should be only ONE intersection return this.GetIntersections(that).Count == 1; }
public virtual bool Contains(List<Point> figurePoints, AtomicRegion atom) { // A figure contains itself. ShapeAtomicRegion shapeAtom = atom as ShapeAtomicRegion; if (shapeAtom != null) { if (this.StructurallyEquals(shapeAtom.shape)) return true; } // // Do all vertices of that lie on the interior of this figure // List<Point> thatVertices = atom.GetVertices(); foreach (Point vertex in thatVertices) { if (!this.PointLiesInOrOn(vertex)) return false; } // // Check all midpoints of conenctions are on the interior. // foreach (Connection thatConn in atom.connections) { if (!this.PointLiesInOrOn(thatConn.Midpoint())) return false; } // // For any intersections between the atomic regions, the resultant points of intersection must be on the perimeter. // AtomicRegion thisFigureRegion = this.GetFigureAsAtomicRegion(); List<AtomicRegion.IntersectionAgg> intersections = thisFigureRegion.GetIntersections(figurePoints, atom); foreach (AtomicRegion.IntersectionAgg agg in intersections) { if (agg.overlap) { // No-Op } else { // An approximation may result in an intersection inside the figure (although we would expect on) if (!this.PointLiesInOrOn(agg.intersection1)) return false; if (agg.intersection2 != null) { if (!this.PointLiesInOrOn(agg.intersection2)) return false; } } } return true; }
public virtual bool CoordinateCongruent(AtomicRegion that) { // // Collect segment and arc connections. // List<Segment> thisSegs = new List<Segment>(); List<Arc> thisArcs = new List<Arc>(); List<Segment> thatSegs = new List<Segment>(); List<Arc> thatArcs = new List<Arc>(); SplitConnections(this, out thisSegs, out thisArcs); SplitConnections(that, out thatSegs, out thatArcs); // // We must have the same number of each type of connections // if (thisSegs.Count != thatSegs.Count) return false; if (thisArcs.Count != thatArcs.Count) return false; // // This is a naive approach since a more formal approach should follow order of connections; should generally work // // // An atomic region must have the same number of segments, each of the same length. // bool[] marked = new bool[thisSegs.Count]; foreach (Segment thisSeg in thisSegs) { bool found = false; for (int c = 0; c < thatSegs.Count; c++) { if (!marked[c]) { if (thisSeg.CoordinateCongruent(thatSegs[c])) { marked[c] = true; found = true; break; } } } if (!found) return false; } // Redundant: // if (marked.Contains(false)) return false; // Exit early if no arcs. if (!thisArcs.Any()) return true; // // An atomic region must have the same number of arcs, each of the same length (using the radius of the circle). // marked = new bool[thisArcs.Count]; foreach (Arc thisArc in thisArcs) { bool found = false; for (int c = 0; c < thatArcs.Count; c++) { if (!marked[c]) { if (thisArc.CoordinateCongruent(thatArcs[c])) { marked[c] = true; found = true; break; } } } if (!found) return false; } // Redundant: // if (marked.Contains(false)) return false; return true; }
public bool HasVertexExteriorTo(AtomicRegion that) { List<IntersectionAgg> intersections = this.GetIntersections(that); foreach (IntersectionAgg agg in intersections) { if (!agg.overlap) { if (!this.PointLiesOnOrInside(agg.intersection1)) return true; } } return false; }
// // Compose this atomic region with a segment // This operation will return a list of atomic regions iff the segment passes through the atomic region; this // creates two new atomic regions since the segment divides the atom. // //public static List<AtomicRegion> Compose(AtomicRegion thisAtom, Segment that, Figure owner) //{ // List<AtomicRegion> newAtoms = new List<AtomicRegion>(); // List<AtomicRegion.IntersectionAgg> intersections = thisAtom.GetIntersections(that); // // If there is only 1 intersection then we may have a 'corner' inside of the atomic region. // if (intersections.Count == 1) return newAtoms; // if (intersections.Count > 2) throw new ArgumentException("More than 3 intersections due to a segment during atomic region composition"); // // If there are two intersection points, this atomic region is split into 2 regions. // if (intersections.Count != 2) // { // throw new ArgumentException("Expected 2 intersections due to a segment during atomic region composition; have " + intersections.Count); // } // // // // Split the region into 2 new atomic regions. // // // // (0) Order the connections of this atomic region. // // (1) Make a copy of the list of connections // // (2) Replace 2 intersected connections with (up to) 4 new connections. // // (3) Add this segment connection // // // thisAtom.OrderConnections(); // AtomicRegion newAtom1 = new AtomicRegion(); // AtomicRegion newAtom2 = new AtomicRegion(); // bool[] marked = new bool[intersections.Count]; // bool atom1 = true; // foreach (Connection conn in thisAtom.connections) // { // bool found = false; // for (int i = 0; i < intersections.Count; i++) // { // if (!marked[i]) // { // marked[i] = true; // if (conn.Equals(intersections[i].Key)) // { // found = true; // // // // How does this new segment intersect this connection? // // // // Endpoint // if (conn.HasPoint(intersections[i].Value)) // { // // No-op // } // // Split this connection in the middle // else // { // Connection newConn1 = new Connection(conn.endpoint1, intersections[i].Value, conn.type, conn.segmentOwner); // Connection newConn2 = new Connection(conn.endpoint2, intersections[i].Value, conn.type, conn.segmentOwner); // // // // Which atomic region owns which new connection. // // // if (newAtom1.HasPoint(conn.endpoint1)) // { // newAtom1.AddConnection(newConn1); // newAtom2.AddConnection(newConn2); // } // else if (newAtom2.HasPoint(conn.endpoint1)) // { // newAtom2.AddConnection(newConn1); // newAtom1.AddConnection(newConn2); // } // // Neither atomic region has the point (possibly the first connection encountered). // else // { // // Arbitrary assignment // newAtom1.AddConnection(newConn1); // newAtom2.AddConnection(newConn2); // } // } // // Shift to the second (new) atomic region. // atom1 = false; // } // } // } // // This is not a splittable connection so just add it to the list. // if (!found) // { // if (atom1) newAtom1.AddConnection(conn); // else newAtom2.AddConnection(conn); // } // } // // // // Add this new segment as a connection to both atomic regions. // // // newAtom1.AddConnection(intersections[0].Value, intersections[1].Value, ConnectionType.SEGMENT, owner); // newAtom2.AddConnection(intersections[0].Value, intersections[1].Value, ConnectionType.SEGMENT, owner); // // Order the connections in the new regions we created. // newAtom1.OrderConnections(); // newAtom2.OrderConnections(); // newAtoms.Add(newAtom1); // newAtoms.Add(newAtom2); // return newAtoms; //} public static void Overlap(List <Point> figurePoints, AtomicRegion thisAtom, AtomicRegion thatAtom, out List <AtomicRegion> toAdd, out List <AtomicRegion> toRemove) { // // Acquire all arcs and segments. // List <Arc> graphArcs = new List <Arc>(); List <Segment> graphSegments = new List <Segment>(); foreach (Connection thisConn in thisAtom.connections) { if (thisConn.type == ConnectionType.SEGMENT) { graphSegments.Add(thisConn.segmentOrArc as Segment); } else { graphArcs.Add(thisConn.segmentOrArc as Arc); } } foreach (Connection thatConn in thatAtom.connections) { if (thatConn.type == ConnectionType.SEGMENT) { graphSegments.Add(thatConn.segmentOrArc as Segment); } else { graphArcs.Add(thatConn.segmentOrArc as Arc); } } // // Clear collinearities of all segments / arcs. // List <Circle> circles = new List <Circle>(); // get the list of applicable circles to these atoms. foreach (Segment seg in graphSegments) { seg.ClearCollinear(); } foreach (Arc arc in graphArcs) { Utilities.AddStructurallyUnique <Circle>(circles, arc.theCircle); arc.ClearCollinear(); } // // All points of interest for these atoms. // List <Point> allPoints = new List <Point>(); allPoints.AddRange(thisAtom.GetVertices()); allPoints.AddRange(thatAtom.GetVertices()); // // Determine 'collinearities' for the intersections. // List <AtomicRegion.IntersectionAgg> intersections = thisAtom.GetIntersections(figurePoints, thatAtom); List <Point> intersectionPts = new List <Point>(); foreach (AtomicRegion.IntersectionAgg agg in intersections) { if (agg.intersection1 != null) { if (!Utilities.HasStructurally <Point>(allPoints, agg.intersection1)) { intersectionPts.Add(agg.intersection1); } agg.thisConn.segmentOrArc.AddCollinearPoint(agg.intersection1); agg.thatConn.segmentOrArc.AddCollinearPoint(agg.intersection1); } if (agg.intersection2 != null) { if (!Utilities.HasStructurally <Point>(allPoints, agg.intersection2)) { intersectionPts.Add(agg.intersection2); } intersectionPts.Add(agg.intersection2); agg.thisConn.segmentOrArc.AddCollinearPoint(agg.intersection2); agg.thatConn.segmentOrArc.AddCollinearPoint(agg.intersection2); } } // Add any unlabeled intersection points. allPoints.AddRange(intersectionPts); // // Construct the Planar graph for atomic region identification. // Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph graph = new Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.PlanarGraph(); // Add the points as nodes in the graph. foreach (Point pt in allPoints) { graph.AddNode(pt); } // // Edges are based on all the collinear relationships. // foreach (Segment segment in graphSegments) { 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, Area_Based_Analyses.Atomizer.UndirectedPlanarGraph.EdgeType.REAL_SEGMENT); } } foreach (Arc arc in graphArcs) { for (int p = 0; p < arc.collinear.Count - 1; p++) { graph.AddUndirectedEdge(arc.collinear[p], arc.collinear[p + 1], new Segment(arc.collinear[p], arc.collinear[p + 1]).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, circles); // // Determine ownership of the atomic regions. // foreach (AtomicRegion atom in atoms) { if (thisAtom.Contains(atom)) { atom.AddOwners(thisAtom.owners); } if (thatAtom.Contains(atom)) { atom.AddOwners(thatAtom.owners); } } toAdd = atoms; toRemove = new List <AtomicRegion>(); toRemove.Add(thisAtom); toRemove.Add(thatAtom); }