public void SplitBeachSection(Point site)
        {
            BeachSection containingBeachSection = BeachSectionContainingPoint(site);
            BeachSection newBeachSectionLeft    = new BeachSection(containingBeachSection.focus, containingBeachSection.leftBoundary, site);
            BeachSection newBeachSectionCentre  = new BeachSection(site, containingBeachSection.focus, containingBeachSection.focus);
            BeachSection newBeachSectionRight   = new BeachSection(containingBeachSection.focus, site, containingBeachSection.rightBoundary);

            beachSections.Remove(containingBeachSection);
            beachSections.Add(newBeachSectionLeft);
            beachSections.Add(newBeachSectionCentre);
            beachSections.Add(newBeachSectionRight);

            foreach (IntersectEventPoint iep in IntersectEventPoint.FromBeachSections(new List <BeachSection> {
                newBeachSectionLeft, newBeachSectionRight
            }))
            {
                if (iep.Point().y <= site.y)
                {
                    eventQueue.Add(iep);
                }
            }

            foreach (IntersectEventPoint iep in IntersectEventPoint.FromBeachSections(new List <BeachSection> {
                containingBeachSection
            }))
            {
                if (iep.Point().y <= site.y)
                {
                    eventQueue.Remove(iep);
                }
            }
        }
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return(false);
            }

            IntersectEventPoint that       = (IntersectEventPoint)obj;
            List <Point>        thisPoints = new List <Point> {
                a, b, c
            };

            return(thisPoints.Contains(that.a) && thisPoints.Contains(that.b) && thisPoints.Contains(that.c));
        }
        public static HashSet <IntersectEventPoint> FromBeachSections(IEnumerable <BeachSection> beachSections)
        {
            HashSet <IntersectEventPoint> set = new HashSet <IntersectEventPoint>();

            foreach (BeachSection bs in beachSections)
            {
                if (!bs.IsLeftmost() &&
                    !bs.IsRightmost() &&
                    bs.leftBoundary != bs.rightBoundary
                    )
                {
                    Line lineA = bs.leftBoundary.LineWith(bs.rightBoundary);
                    Line lineB = bs.leftBoundary.LineWith(bs.focus);
                    if (!lineA.Equals(lineB) && bs.Closed())
                    {
                        IntersectEventPoint iep = new IntersectEventPoint(bs);
                        set.Add(iep);
                    }
                }
            }
            return(set);
        }
        public void ConsumeBeachSection(IntersectEventPoint intersectEventPoint)
        {
            BeachSection consumedBeachSection = intersectEventPoint.consumedBeachSection;
            BeachSection leftBeachSection     = beachSections.Predecessor(consumedBeachSection);
            BeachSection rightBeachSection    = beachSections.Successor(consumedBeachSection);
            BeachSection newLeftBeachSection  = new BeachSection(leftBeachSection.focus, leftBeachSection.leftBoundary, rightBeachSection.focus);
            BeachSection newRightBeachSection = new BeachSection(rightBeachSection.focus, leftBeachSection.focus, rightBeachSection.rightBoundary);

            beachSections.Remove(consumedBeachSection);
            beachSections.Remove(leftBeachSection);
            beachSections.Remove(rightBeachSection);
            beachSections.Add(newLeftBeachSection);
            beachSections.Add(newRightBeachSection);

            foreach (IntersectEventPoint iep in IntersectEventPoint.FromBeachSections(new List <BeachSection> {
                leftBeachSection, rightBeachSection
            }))
            {
                if (iep.Point().y <= intersectEventPoint.Point().y)
                {
                    eventQueue.Remove(iep);
                }
            }

            foreach (IntersectEventPoint iep in IntersectEventPoint.FromBeachSections(new List <BeachSection> {
                newLeftBeachSection, newRightBeachSection
            }))
            {
                if (iep.Point().y <= intersectEventPoint.Point().y)
                {
                    if (!iep.Equals(intersectEventPoint))
                    {
                        eventQueue.Add(iep);
                    }
                }
            }
        }
        internal Dictionary <Point, VoronoiCellUnorganised> WithPoints(IEnumerable <Point> points)
        {
            if (points.Count() == 0)
            {
                throw new System.ArgumentException("No points provided");
            }

            cells = new Dictionary <Point, VoronoiCellUnorganised>();

            // We'll start at the top of the field and work down.

            // Initialise the beachline with all points having most Y coordinate.
            // There'll often be only one of these, but calculating their interactions
            // with no background beachline is more difficult so it helps to include them all at once.

            HashSet <Point>     distinctPoints = new HashSet <Point>(points);
            List <Point>        highestPoints  = FindHighestPoints(distinctPoints).OrderBy(p => p.x).ToList();
            float               mostY          = highestPoints.First().y;
            IEnumerable <Point> otherPoints    = distinctPoints.Where(p => p.y < mostY);

            List <BeachSection> initialBeachSections = new List <BeachSection>();

            for (int i = 0; i < highestPoints.Count; i++)
            {
                Point left  = null;
                Point right = null;
                Point focus = highestPoints[i];
                cells[focus] = new VoronoiCellUnorganised(focus);
                if (i > 0)
                {
                    left = highestPoints[i - 1];
                    cells[focus].AddBorder(left);
                }

                if (i + 1 < highestPoints.Count)
                {
                    right = highestPoints[i + 1];
                    cells[focus].AddBorder(right);
                }

                BeachSection bs = new BeachSection(focus, left, right);
                initialBeachSections.Add(bs);
            }

            BeachLine beachLine = new BeachLine(initialBeachSections, otherPoints);

            // For the remaining points that don't lie on the initial beachline, handle them in descending order
            // of their y coordinate.

            while (beachLine.HasMoreEvents())
            {
                IEventPoint eventPoint = beachLine.PopEvent();

                if (eventPoint.EventType() == "Site")
                {
                    Point site = eventPoint.Point();

                    BeachSection containingBeachSection = beachLine.BeachSectionContainingPoint(site);

                    VoronoiCellUnorganised cell = new VoronoiCellUnorganised(site);
                    cells[site] = cell;
                    AddBorderBetweenCells(site, containingBeachSection.focus);

                    beachLine.SplitBeachSection(site);
                }
                else // EventType = "Intersect"
                {
                    IntersectEventPoint intersectEventPoint = (IntersectEventPoint)eventPoint;

                    BeachSection consumedBeachSection = intersectEventPoint.consumedBeachSection;

                    AddBorderBetweenCells(consumedBeachSection.leftBoundary, consumedBeachSection.rightBoundary);

                    beachLine.ConsumeBeachSection(intersectEventPoint);
                }
            }
            return(cells);
        }