/// <summary> /// Adds a spatial object into the index /// </summary> /// <param name="o">The object to add to the index</param> public void Add(ISpatialObject o) { // Points are handled using their own index. Unfortunately, they // must implement IPoint in order for it to work (something // that should really be reflected in the parameter list). // Could cover this by using the fact that an ISpatialObject that is // a point must be able to return an IWindow (from which we can // pull out the point position). Just a bit more convoluted. if (o is IPoint) { m_Points.Add(o as IPoint); return; } Item item = new Item(o); SpatialType t = o.SpatialType; if (t == SpatialType.Line) { m_Lines.AddItem(item); } else if (t == SpatialType.Text) { m_Text.AddItem(item); } else if (t == SpatialType.Polygon) { m_Polygons.AddItem(item); } else { throw new NotSupportedException("Unexpected object type: " + o.SpatialType); } }
/** * Look for groups of vertices that are separated by at most merge_distance() * and merge them into a single vertex. */ private void MergeVertices() { // The overall strategy is to start from each vertex and grow a maximal // cluster of mergable vertices. In graph theoretic terms, we find the // connected components of the undirected graph whose edges connect pairs of // vertices that are separated by at most merge_distance. // // We then choose a single representative vertex for each cluster, and // update all the edges appropriately. We choose an arbitrary existing // vertex rather than computing the centroid of all the vertices to avoid // creating new vertex pairs that need to be merged. (We guarantee that all // vertex pairs are separated by at least merge_distance in the output.) var index = new PointIndex(_options.MergeDistance.Radians); foreach (var edge in _edges) { index.Add(edge.Key); var vset = edge.Value; foreach (var v in vset) { index.Add(v); } } // Next, we loop through all the vertices and attempt to grow a maximial // mergeable group starting from each vertex. var mergeMap = new Dictionary <S2Point, S2Point>(); var frontier = new Stack <S2Point>(); var mergeable = new List <S2Point>(); foreach (var entry in index) { var point = entry.Value; if (point.IsMarked) { continue; // Already processed. } point.Mark(); // Grow a maximal mergeable component starting from "vstart", the // canonical representative of the mergeable group. var vstart = point.Point; frontier.Push(vstart); while (frontier.Any()) { var v0 = frontier.Pop(); index.Query(v0, mergeable); foreach (var v1 in mergeable) { frontier.Push(v1); mergeMap.Add(v1, vstart); } } } // Finally, we need to replace vertices according to the merge_map. MoveVertices(mergeMap); }