Exemple #1
0
    // 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);
    }
Exemple #2
0
        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));
        }
Exemple #3
0
    // 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);
    }
Exemple #4
0
        //
        // 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));
    }
Exemple #5
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);
        }
Exemple #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);
        }
Exemple #7
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));
        }
Exemple #8
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;
        }
Exemple #9
0
        //
        // 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);
        }
Exemple #10
0
        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);
        }
Exemple #11
0
        // 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;
        }
Exemple #12
0
        // 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;
        }