Beispiel #1
0
        //
        // Extract the atomic regions.
        //
        public List<AtomicRegion> ExtractAtomicRegions(UndirectedPlanarGraph.PlanarGraph graph, List<Circle> circles)
        {
            memoized = new Agg[points.Count, points.Count];

            // Recursively construct.
            return MakeRegions(graph, circles, 0, points.Count - 1).atoms;
        }
Beispiel #2
0
        //
        //
        // Create the actual set of atomic regions for this cycle.
        //
        //   We need to check to see if any of the cycle segments are based on arcs.
        //   We have to handle the degree of each segment: do many circles intersect at these points?
        //
        public List<Atomizer.AtomicRegion> ConstructAtomicRegions(List<Circle> circles, UndirectedPlanarGraph.PlanarGraph graph)
        {
            List<Atomizer.AtomicRegion> regions = new List<Atomizer.AtomicRegion>();

            Atomizer.AtomicRegion region = null;

            //
            // Check for a direct polygon (no arcs).
            //
            region = PolygonDefinesRegion(graph);
            if (region != null)
            {
                regions.Add(region);
                return regions;
            }

            //
            // Does this region define a sector?
            //
            List<AtomicRegion> sectors = SectorOrTruncationDefinesRegion(circles, graph);
            if (sectors != null && sectors.Any())
            {
                regions.AddRange(sectors);
                return regions;
            }

            //
            // Do we have a set of regions defined by a polygon in which circle(s) cut out some of that region?
            //
            regions.AddRange(MixedArcChordedRegion(circles, graph));

            return regions;
        }
Beispiel #3
0
        public FacetCalculator(UndirectedPlanarGraph.PlanarGraph g)
        {
            graph = g;

            if (Utilities.ATOMIC_REGION_GEN_DEBUG)
            {
                Debug.WriteLine(graph);
            }

            primitives = new List<Primitive>();

            ExtractPrimitives();
        }
        //
        // Take the cycle-based representation and convert in into AtomicRegion objects.
        //
        public static List<AtomicRegion> Convert(UndirectedPlanarGraph.PlanarGraph graph,
                                                 List<Primitive> primitives, List<Circle> circles)
        {
            List<MinimalCycle> cycles = new List<MinimalCycle>();
            List<Filament> filaments = new List<Filament>();

            foreach (Primitive primitive in primitives)
            {
                if (primitive is MinimalCycle) cycles.Add(primitive as MinimalCycle);
                if (primitive is Filament) filaments.Add(primitive as Filament);
            }

            //
            // Convert the filaments to atomic regions.
            //
            List<AtomicRegion> regions = new List<AtomicRegion>();
            if (filaments.Any())
            {
                throw new Exception("A filament occurred in conversion to atomic regions.");
            }
            // regions.AddRange(HandleFilaments(graph, circles, filaments));

            ComposeCycles(graph, cycles);

            if (GeometryTutorLib.Utilities.ATOMIC_REGION_GEN_DEBUG)
            {
                Debug.WriteLine("Composed:");
                foreach (MinimalCycle cycle in cycles)
                {
                    Debug.WriteLine("\t" + cycle.ToString());
                }
            }

            //
            // Convert all cycles (perimeters) to atomic regions
            //
            foreach (MinimalCycle cycle in cycles)
            {
                List<AtomicRegion> temp = cycle.ConstructAtomicRegions(circles, graph);
                foreach (AtomicRegion atom in temp)
                {
                    if (!regions.Contains(atom)) regions.Add(atom);
                }
            }

            return regions;
        }
        //
        // If a cycle has an edge that is EXTENDED, there exist two regions, one on each side of the segment; compose the two segments.
        //
        // Fixed point algorithm: while there exists a cycle with an extended segment, compose.
        private static void ComposeCycles(UndirectedPlanarGraph.PlanarGraph graph, List<MinimalCycle> cycles)
        {
            for (int cycleIndex = HasComposableCycle(graph, cycles); cycleIndex != -1; cycleIndex = HasComposableCycle(graph, cycles))
            {
                // Get the cycle and remove it from the list.
                MinimalCycle thisCycle = cycles[cycleIndex];

                cycles.RemoveAt(cycleIndex);

                // Get the extended segment which is the focal segment of composition.
                GeometryTutorLib.ConcreteAST.Segment extendedSeg = thisCycle.GetExtendedSegment(graph);

                // Find the matching cycle that has the same Extended segment
                int otherIndex = GetComposableCycleWithSegment(graph, cycles, extendedSeg);
                MinimalCycle otherCycle = cycles[otherIndex];
                cycles.RemoveAt(otherIndex);

                // Compose the two cycles into a single cycle.
                MinimalCycle composed = thisCycle.Compose(otherCycle, extendedSeg);

                // Add the new, composed cycle
                cycles.Add(composed);
            }
        }
Beispiel #6
0
        //
        // 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 static int GetComposableCycleWithSegment(UndirectedPlanarGraph.PlanarGraph graph,
                                                         List<MinimalCycle> cycles,
                                                         GeometryTutorLib.ConcreteAST.Segment segment)
        {
            for (int c = 0; c < cycles.Count; c++)
            {
                if (cycles[c].HasThisExtendedSegment(graph, segment)) return c;
            }

            return -1;
        }
 private static int HasComposableCycle(UndirectedPlanarGraph.PlanarGraph graph, List<MinimalCycle> cycles)
 {
     for (int c = 0; c < cycles.Count; c++)
     {
         if (cycles[c].HasExtendedSegment(graph)) return c;
     }
     return -1;
 }
        //
        // A filament is a path from one node to another; it does not invoke a cycle.
        // In shaded-area problems this can only be accomplished with arcs of circles.
        //
        private static List<AtomicRegion> HandleFilaments(UndirectedPlanarGraph.PlanarGraph graph, List<Circle> circles, List<Filament> filaments)
        {
            List<AtomicRegion> atoms = new List<AtomicRegion>();

            foreach (Filament filament in filaments)
            {
                atoms.AddRange(filament.ExtractAtomicRegions(graph, circles));
            }

            return atoms;
        }
Beispiel #10
0
        public Segment GetExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph)
        {
            for (int p = 0; p < points.Count; p++)
            {
                if (graph.GetEdgeType(points[p], points[(p + 1) % points.Count]) == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT)
                {
                    return new Segment(points[p], points[p + 1 < points.Count ? p + 1 : 0]);
                }
            }

            return null;
        }
Beispiel #11
0
        private Atomizer.AtomicRegion PolygonDefinesRegion(UndirectedPlanarGraph.PlanarGraph graph)
        {
            List<Segment> sides = new List<Segment>();

            //
            // All connections between adjacent connections MUST be segments.
            //
            for (int p = 0; p < points.Count; p++)
            {
                Segment segment = new Segment(points[p], points[(p + 1) % points.Count]);

                sides.Add(segment);

                if (graph.GetEdge(points[p], points[(p + 1) % points.Count]).edgeType != UndirectedPlanarGraph.EdgeType.REAL_SEGMENT) return null;
            }

            //
            // All iterative connections cannot be arcs.
            //
            for (int p1 = 0; p1 < points.Count - 1; p1++)
            {
                // We want to check for a direct cycle, therefore, p2 starts at p1 not p1 + 1
                for (int p2 = p1; p2 < points.Count; p2++)
                {
                    UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p1], points[(p2 + 1) % points.Count]);

                    if (edge != null)
                    {
                        if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC) return null;
                    }
                }
            }

            //
            // Make the Polygon
            //
            Polygon poly = Polygon.MakePolygon(sides);

            if (poly == null) throw new ArgumentException("Real segments should define a polygon; they did not.");

            return new ShapeAtomicRegion(poly);
        }
Beispiel #12
0
        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;
        }
Beispiel #13
0
        //
        // Collect all arcs attributed to this this cycle;
        //
        private List<MinorArc> CollectStrictArcs(List<Circle> circles, UndirectedPlanarGraph.PlanarGraph graph)
        {
            List<MinorArc> minors = new List<MinorArc>();

            for (int p = 0; p < points.Count; p++)
            {
                UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]);

                if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_ARC)
                {
                    // Find the applicable circle.
                    Circle theCircle = null;
                    foreach (Circle circle in circles)
                    {
                        if (circle.HasArc(points[p], points[(p + 1) % points.Count]))
                        {
                            theCircle = circle;
                            break;
                        }
                    }

                    minors.Add(new MinorArc(theCircle, points[p], points[(p + 1) % points.Count]));
                }
            }

            return minors;
        }
Beispiel #14
0
        //
        // Collect all segments attributed to this this cycle
        //
        private List<Segment> CollectSegments(UndirectedPlanarGraph.PlanarGraph graph)
        {
            List<Segment> segments = new List<Segment>();

            for (int p = 0; p < points.Count; p++)
            {
                UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]);

                if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_SEGMENT)
                {
                    segments.Add(new Segment(points[p], points[(p + 1) % points.Count]));
                }
            }

            return segments;
        }
Beispiel #15
0
        public bool HasThisExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph, Segment segment)
        {
            if (!points.Contains(segment.Point1)) return false;
            if (!points.Contains(segment.Point2)) return false;

            return graph.GetEdgeType(segment.Point1, segment.Point2) == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT;
        }
Beispiel #16
0
 public bool HasExtendedSegment(UndirectedPlanarGraph.PlanarGraph graph)
 {
     return GetExtendedSegment(graph) != null;
 }
Beispiel #17
0
        //
        // Based on the two points, extract the circle which results in the connection (if the connection exists).
        //
        private List<AtomicRegion> HandleConnection(UndirectedPlanarGraph.PlanarGraph graph, List<Circle> circles, Point pt1, Point pt2)
        {
            List<AtomicRegion> atoms = new List<AtomicRegion>();

            UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(pt1, pt2);

            if (edge == null) return atoms;

            //
            // Find the one circle that applies to this set of points.
            //
            Circle theCircle = null;
            foreach (Circle circle in circles)
            {
                if (circle.PointLiesOn(pt1) && circle.PointLiesOn(pt2)) theCircle = circle;
            }

            switch (edge.edgeType)
            {
                case UndirectedPlanarGraph.EdgeType.REAL_ARC:
                case UndirectedPlanarGraph.EdgeType.REAL_DUAL:
                    atoms.AddRange(CreateSectors(theCircle, pt1, pt2));
            //                    atoms.AddRange(CreateSemiCircleRegions());
                    break;
            }

            return atoms;
        }
Beispiel #18
0
        private List<Atomizer.AtomicRegion> SectorOrTruncationDefinesRegion(List<Circle> circles, UndirectedPlanarGraph.PlanarGraph graph)
        {
            //
            // Do there exist any real-dual edges or extended segments? If so, this is not a sector.
            //
            for (int p = 0; p < points.Count; p++)
            {
                UndirectedPlanarGraph.PlanarGraphEdge edge = graph.GetEdge(points[p], points[(p + 1) % points.Count]);

                if (edge.edgeType == UndirectedPlanarGraph.EdgeType.EXTENDED_SEGMENT) return null;
                else if (edge.edgeType == UndirectedPlanarGraph.EdgeType.REAL_DUAL) return null;
            }

            //
            // Collect all segments; split into two collinear lists.
            //
            List<Segment> segments = CollectSegments(graph);
            List<List<Segment>> collinearSegmentSet = SplitSegmentsIntoCollinearSequences(segments);

            // A sector requires one (semicircl) or two sets of segments ('normal' arc).
            if (collinearSegmentSet.Count > 2) return null;

            //
            // Collect all arcs.
            //
            List<MinorArc> arcs = CollectStrictArcs(circles, graph);
            List<List<MinorArc>> collinearArcSet = SplitArcsIntoCollinearSequences(arcs);

            // A sector requires one set of arcs (no more, no less).
            if (collinearArcSet.Count != 1) return null;

            // Semicircle has one set of sides
            if (collinearSegmentSet.Count == 1) return ConvertToTruncationOrSemicircle(collinearSegmentSet[0], collinearArcSet[0]);

            // Pacman shape created with a circle results in Sector
            return ConvertToGeneralSector(collinearSegmentSet[0], collinearSegmentSet[1], collinearArcSet[0]);
        }