Ejemplo n.º 1
0
 /// <summary>
 /// Destroy a VertexGraph's sub-objects, freeing their memory. The caller is
 /// responsible for freeing memory allocated to the VertexGraph struct itself.
 /// </summary>
 /// <param name="graph">Graph to destroy</param>
 /// <!-- Based off 3.1.1 -->
 public static void destroyVertexGraph(ref VertexGraph graph)
 {
     foreach (var bucket in graph.buckets)
     {
         bucket.Clear();
     }
     graph.buckets.Clear();
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons.
        /// Polygon outlines will follow GeoJSON MultiPolygon order: Each polygon will
        /// have one outer loop, which is first in the list, followed by any holes.
        ///
        /// It is expected that all hexagons in the set have the same resolution and
        /// that the set contains no duplicates. Behavior is undefined if duplicates
        /// or multiple resolutions are present, and the algorithm may produce unexpected
        /// or invalid output.
        /// </summary>
        /// <param name="h3Set">Set of hexagons</param>
        /// <param name="numHexes">NUmber of hexagons in set</param>
        /// <param name="out_polygons">output polygon</param>
        /// <!-- Based off 3.1.1 -->
        public static void h3SetToLinkedGeo(ref List <H3Index> h3Set, int numHexes,
                                            ref LinkedGeo.LinkedGeoPolygon out_polygons)
        {
            VertexGraph graph = new VertexGraph(0, 0);

            h3SetToVertexGraph(ref h3Set, numHexes, ref graph);
            _vertexGraphToLinkedGeo(ref graph, ref out_polygons);
            // TODO: The return value, possibly indicating an error, is discarded here -
            // we should use this when we update the API to return a value
            LinkedGeo.normalizeMultiPolygon(ref out_polygons);
            VertexGraph.destroyVertexGraph(ref graph);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Get the next vertex node in the graph.
        /// </summary>
        /// <param name="graph">Graph to iterate</param>
        /// <returns>Vertex node or null if at the the end</returns>
        /// <!-- Based off 3.1.1 -->
        public static VertexNode firstVertexNode(ref VertexGraph graph)
        {
            foreach (var bucket in graph.buckets)
            {
                if (bucket.Count <= 0)
                {
                    continue;
                }
                return(bucket[0]);
            }

            return(null);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Internal: Create a vertex graph from a set of hexagons. It is the
        /// responsibility of the caller to call destroyVertexGraph on the populated
        /// graph, otherwise the memory in the graph nodes will not be freed.
        /// </summary>
        ///
        /// <param name="h3Set">Set of hexagons</param>
        /// <param name="numHexes">Number of hexagons in the set</param>
        /// <param name="graph">Output graph</param>
        /// <!-- Based off 3.1.1 -->
        public static void h3SetToVertexGraph(ref List <H3Index> h3Set, int numHexes,
                                              ref VertexGraph graph)
        {
            GeoBoundary vertices   = new GeoBoundary();
            GeoCoord    fromVertex = new GeoCoord();
            GeoCoord    toVertex   = new GeoCoord();

            VertexGraph.VertexNode edge;
            if (numHexes < 1)
            {
                // We still need to init the graph, or calls to destroyVertexGraph will
                // fail
                graph = new VertexGraph(0, 0);
                return;
            }

            int       res        = H3Index.H3_GET_RESOLUTION(h3Set[0]);
            const int minBuckets = 6;
            // TODO: Better way to calculate/guess?
            int numBuckets = numHexes > minBuckets ? numHexes : minBuckets;

            graph = new VertexGraph(numBuckets, res);

            // Iterate through every hexagon
            for (int i = 0; i < numHexes; i++)
            {
                H3Index.h3ToGeoBoundary(h3Set[i], ref vertices);
                // iterate through every edge
                for (int j = 0; j < vertices.numVerts; j++)
                {
                    fromVertex = new GeoCoord(vertices.verts[j].lat, vertices.verts[j].lon);
                    //fromVtx = vertices.verts[j];
                    int idx = (j + 1) % vertices.numVerts;
                    toVertex = new GeoCoord(vertices.verts[idx].lat, vertices.verts[idx].lon);
                    //toVtx = vertices.verts[(j + 1) % vertices.numVerts];
                    // If we've seen this edge already, it will be reversed
                    edge = VertexGraph.findNodeForEdge(ref graph, toVertex, fromVertex);
                    if (edge != null)
                    {
                        // If we've seen it, drop it. No edge is shared by more than 2
                        // hexagons, so we'll never see it again.
                        VertexGraph.removeVertexNode(ref graph, ref edge);
                    }
                    else
                    {
                        // Add a new node for this edge
                        VertexGraph.addVertexNode(ref graph, fromVertex, toVertex);
                    }
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Find the <see cref="VertexNode"/> for a given edge, if it exists.
        /// </summary>
        /// <param name="graph">Graph to look in</param>
        /// <param name="fromVtx">Start Vertex</param>
        /// <param name="ToVtx">End Vertex, or null if we don't care</param>
        /// <returns>Pointer to the vertex node, if found</returns>
        /// <!-- Based off 3.1.1 -->
        public static VertexNode findNodeForEdge(
            ref VertexGraph graph,
            GeoCoord fromVtx,
            GeoCoord toVtx)
        {
            uint index         = _hashVertex(fromVtx, graph.res, graph.numBuckets);
            var  currentBucket = graph.buckets[(int)index];

            var nodeIndex = currentBucket.FindIndex(
                t => GeoCoord.geoAlmostEqual(t.from, fromVtx) &&
                (toVtx == null || GeoCoord.geoAlmostEqual(t.to, toVtx))
                );

            return(nodeIndex < 0
                ? null
                : currentBucket[nodeIndex]);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Remove a node from the graph.  The input node will be freed, and should
        /// not be used after removal.
        /// </summary>
        /// <param name="graph">Graph to mutate</param>
        /// <param name="node">Node to remove</param>
        /// <returns>0 on success, 1 on failure (node not found)</returns>
        /// <!-- Based off 3.1.1 -->
        public static int removeVertexNode(ref VertexGraph graph, ref VertexNode node)
        {
            // Determine location
            uint index         = _hashVertex(node.from, graph.res, graph.numBuckets);
            var  currentBucket = graph.buckets[(int)index];

            var tnode     = node;
            var nodeIndex = currentBucket.FindIndex(t => t.from == tnode.from && t.to == tnode.to);

            // Failed to find the node
            if (nodeIndex < 0)
            {
                return(1);
            }
            currentBucket.RemoveAt(nodeIndex);
            graph.size--;
            return(0);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Internal: Create a LinkedGeoPolygon from a vertex graph. It is the
 /// responsibility of the caller to call destroyLinkedPolygon on the
 /// populated linked geo structure, or the memory for that structure
 /// will not be freed.
 /// </summary>
 /// <param name="graph">input graph</param>
 /// <param name="out_polygon">output polygon</param>
 /// <!-- Based off 3.1.1 -->
 internal static void _vertexGraphToLinkedGeo(ref VertexGraph graph, ref LinkedGeo.LinkedGeoPolygon out_polygon)
 {
     out_polygon = new LinkedGeo.LinkedGeoPolygon();
     VertexGraph.VertexNode edge;
     // Find the next unused entry point
     while ((edge = VertexGraph.firstVertexNode(ref graph)) != null)
     {
         var loop = LinkedGeo.addNewLinkedLoop(ref out_polygon);
         // Walk the graph to get the outline
         do
         {
             var addLinkedCoord = LinkedGeo.addLinkedCoord(ref loop, ref edge.from);
             var nextVertex     = edge.to;
             // Remove frees the node, so we can't use edge after this
             VertexGraph.removeVertexNode(ref graph, ref edge);
             edge = VertexGraph.findNodeForVertex(ref graph, ref nextVertex);
         } while (edge != null);
     }
 }
Ejemplo n.º 8
0
        /// <summary>Add an edge to the graph</summary>
        /// <param name="graph">Graph to add node to</param>
        /// <param name="fromVtx">Start vertex</param>
        /// <param name="toVtx">End vertex</param>
        /// <returns>new node</returns>
        /// <!-- Based off 3.1.1 -->
        public static VertexNode addVertexNode(ref VertexGraph graph, GeoCoord fromVtx,
                                               GeoCoord toVtx)
        {
            // Make the new node
            VertexNode node = _initVertexNode(fromVtx, toVtx);
            // Determine location
            var index = _hashVertex(fromVtx, graph.res, graph.numBuckets);
            // Check whether there's an existing node in that spot
            List <VertexNode> currentNode = graph.buckets[(int)index];

            if (currentNode.Count == 0)
            {
                // Set bucket to the new node
                graph.buckets[(int)index].Add(node);
            }
            else
            {
                //  Go through the list to make sure the
                //  edge doesn't already exist
                //
                //  NOTE: Later, use a Hashset
                foreach (var vertexNode in graph.buckets[(int)index])
                {
                    if (GeoCoord.geoAlmostEqual(vertexNode.from, fromVtx) &&
                        GeoCoord.geoAlmostEqual(vertexNode.to, toVtx))
                    {
                        //  already exists, bail.
                        return(vertexNode);
                    }
                }
                // Add the new node to the end of the list
                graph.buckets[(int)index].Add(node);
            }
            graph.size++;
            return(node);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Find a Vertex node starting at the given vertex
 /// </summary>
 /// <param name="graph">Graph to look in</param>
 /// <param name="fromVtx">Start vertex</param>
 /// <returns>Vertex node, if found</returns>
 /// <!-- Based off 3.1.1 -->
 public static VertexNode findNodeForVertex(
     ref VertexGraph graph,
     ref GeoCoord fromVtx)
 {
     return(findNodeForEdge(ref graph, fromVtx, null));
 }