Ejemplo n.º 1
0
        public VoronoiMap CreateVoronoiMap(int height, int width, IEnumerable <Site> sites)
        {
            if (sites == null)
            {
                throw new ArgumentNullException("sites");
            }

            if (sites.GroupBy(s => s.Point).Count() != sites.Count())
            {
                throw new ArgumentException("Multiple sites with the same coordinates passed!");
            }

            var siteList = string.Join(", ", sites.Select(s => s.Point.ToString()).ToArray());

            _logger.Log($"Create Voronoi map with sites: {siteList}");

            _eventQueue = new EventQueue();
            _beachLine  = new BeachLine(height);
            var map = new VoronoiMap();

            _eventQueue.Initialize(sites.Select(s => s.Point));
            map.AddRange(sites.Cast <IGeometry>());

            while (_eventQueue.HasEvents)
            {
                var sweepEvent = _eventQueue.GetNextEvent();

                var siteEvent = sweepEvent as SiteEvent;
                if (siteEvent != null)
                {
                    _logger.Log($"Sweepline SiteEvent: {siteEvent.Point}");
                    var halfEdges = _siteEventHandler.HandleEvent(siteEvent, _eventQueue, _beachLine);
                    map.AddRange(halfEdges);

                    foreach (var geo in halfEdges)
                    {
                        _logger.Log($"Add {geo}");
                    }

                    continue;
                }

                var circleEvent = sweepEvent as CircleEvent;
                if (circleEvent == null)
                {
                    throw new InvalidOperationException("SweepEvent is neither SiteEvent nor CircleEvent");
                }

                //_logger.Log($"Sweepline CircleEvent: {circleEvent.Point} for arc {circleEvent.Arc.Site}");
                var circleEventResult = _circleEventHandler.HandleEvent(circleEvent, _eventQueue, _beachLine);

                foreach (var geo in circleEventResult)
                {
                    _logger.Log($"Add {geo}");
                }

                // Add vertex and new half edge
                map.AddRange(circleEventResult);
            }

            _beachLine.FinishEdge(_beachLine.Root, width);

            //map.FinishEdges(width);

            map.ConnectEdges();

            _logger.Log("Finished Voronoi map creation");

            foreach (var edge in map.Where(g => g is HalfEdge).Cast <HalfEdge>())
            {
                _logger.Log(edge.ToString());
            }

            return(map);
        }