CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-h3

Python bindings for H3, a hierarchical hexagonal geospatial indexing system

84

0.95x
Overview
Eval results
Files

directed-edges.mddocs/

Directed Edges

Operations for working with directed edges between adjacent H3 cells. H3 directed edges represent connections between neighboring cells and enable analysis of cell boundaries, adjacency relationships, and edge-based operations.

Capabilities

Edge Creation and Validation

Create and validate H3 directed edges between adjacent cells.

def cells_to_directed_edge(origin: str, destination: str) -> str:
    """
    Create a directed edge between two adjacent H3 cells.
    
    Creates an H3 directed edge identifier representing the connection
    from origin cell to destination cell.
    
    Args:
        origin: Starting H3 cell identifier
        destination: Ending H3 cell identifier
        
    Returns:
        H3 directed edge identifier
        
    Raises:
        H3CellInvalidError: If either cell identifier is invalid
        H3NotNeighborsError: If cells are not adjacent neighbors
        H3ResMismatchError: If cells have different resolutions
        
    Note:
        Cells must be immediate neighbors (grid_distance = 1).
        Both cells must be at the same resolution.
        Edge direction matters: edge(A,B) ≠ edge(B,A).
    """

def is_valid_directed_edge(edge: str) -> bool:
    """
    Check if an H3 directed edge identifier is valid.
    
    Args:
        edge: H3 directed edge identifier (string or int)
        
    Returns:
        True if valid H3 directed edge, False otherwise
        
    Note:
        Returns False for any input that cannot be parsed as H3 edge,
        including H3 cells or vertices.
    """

Edge Decomposition

Extract information from H3 directed edges.

def directed_edge_to_cells(e: str) -> tuple[str, str]:
    """
    Get the origin and destination cells from a directed edge.
    
    Args:
        e: H3 directed edge identifier
        
    Returns:
        Tuple of (origin_cell, destination_cell)
        
    Raises:
        H3DirEdgeInvalidError: If e is not a valid H3 directed edge
        
    Note:
        This is the inverse operation of cells_to_directed_edge().
    """

def get_directed_edge_origin(e: str) -> str:
    """
    Get the origin cell from a directed edge.
    
    Args:
        e: H3 directed edge identifier
        
    Returns:
        Origin H3 cell identifier
        
    Raises:
        H3DirEdgeInvalidError: If e is not a valid H3 directed edge
    """

def get_directed_edge_destination(e: str) -> str:
    """
    Get the destination cell from a directed edge.
    
    Args:
        e: H3 directed edge identifier
        
    Returns:
        Destination H3 cell identifier
        
    Raises:
        H3DirEdgeInvalidError: If e is not a valid H3 directed edge
    """

Edge Enumeration

Find all directed edges associated with a cell.

def origin_to_directed_edges(origin: str) -> list[str]:
    """
    Get all directed edges starting from an origin cell.
    
    Returns edges from the origin cell to each of its neighbors.
    
    Args:
        origin: H3 cell identifier
        
    Returns:
        List of H3 directed edge identifiers starting from origin.
        Order is not guaranteed.
        
    Raises:
        H3CellInvalidError: If origin is not a valid H3 cell
        
    Note:
        Hexagon cells return 6 edges, pentagon cells return 5 edges.
        Each edge connects to one of the cell's immediate neighbors.
    """

Edge Geometry

Extract geometric information from directed edges.

def directed_edge_to_boundary(edge: str) -> tuple[tuple[float, float], ...]:
    """
    Get the boundary points of a directed edge.
    
    Returns the line segments that form the edge boundary between
    two adjacent cells.
    
    Args:
        edge: H3 directed edge identifier
        
    Returns:
        Tuple of (lat, lng) coordinate pairs defining the edge boundary.
        Typically returns 2 points (start and end of the edge line).
        
    Raises:
        H3DirEdgeInvalidError: If edge is not a valid H3 directed edge
        
    Note:
        Points are ordered from origin cell boundary toward destination cell.
        The edge represents the shared boundary between the two cells.
    """

Usage Examples

Basic Edge Operations

import h3

# Create two adjacent cells
origin = h3.latlng_to_cell(37.7749, -122.4194, 9)
neighbors = h3.grid_ring(origin, k=1)
destination = neighbors[0]  # Pick first neighbor

print(f"Origin: {origin}")
print(f"Destination: {destination}")

# Verify they are neighbors
is_neighbor = h3.are_neighbor_cells(origin, destination)
print(f"Are neighbors: {is_neighbor}")

# Create directed edge
edge = h3.cells_to_directed_edge(origin, destination)
print(f"Directed edge: {edge}")

# Validate the edge
is_valid = h3.is_valid_directed_edge(edge)
print(f"Edge is valid: {is_valid}")

Edge Decomposition

import h3

# Start with a known edge
origin = h3.latlng_to_cell(40.7589, -73.9851, 8)  # NYC
all_edges = h3.origin_to_directed_edges(origin)
edge = all_edges[0]  # Pick first edge

print(f"Working with edge: {edge}")

# Extract components
extracted_origin = h3.get_directed_edge_origin(edge)
extracted_dest = h3.get_directed_edge_destination(edge)

print(f"Extracted origin: {extracted_origin}")
print(f"Extracted destination: {extracted_dest}")
print(f"Origin matches: {origin == extracted_origin}")

# Use combined extraction
origin_dest = h3.directed_edge_to_cells(edge)
print(f"Combined extraction: {origin_dest}")
print(f"Matches individual: {(extracted_origin, extracted_dest) == origin_dest}")

# Verify round-trip
reconstructed_edge = h3.cells_to_directed_edge(extracted_origin, extracted_dest)
print(f"Reconstructed edge: {reconstructed_edge}")
print(f"Round-trip success: {edge == reconstructed_edge}")

Edge Enumeration and Analysis

import h3

# Analyze edges for different cell types
cells = [
    h3.latlng_to_cell(37.7749, -122.4194, 7),  # Regular hexagon
    h3.get_pentagons(7)[0]  # Pentagon at same resolution
]

for i, cell in enumerate(cells):
    cell_type = "pentagon" if h3.is_pentagon(cell) else "hexagon"
    print(f"\nCell {i+1} ({cell_type}): {cell}")
    
    # Get all outgoing edges
    edges = h3.origin_to_directed_edges(cell)
    print(f"  Outgoing edges: {len(edges)}")
    
    # Analyze each edge
    for j, edge in enumerate(edges):
        dest = h3.get_directed_edge_destination(edge)
        print(f"    Edge {j}: {edge} -> {dest}")
        
        # Verify neighbor relationship
        is_neighbor = h3.are_neighbor_cells(cell, dest)
        assert is_neighbor, f"Edge destination should be neighbor"
        
    # Expected: hexagon has 6 edges, pentagon has 5 edges
    expected_count = 5 if h3.is_pentagon(cell) else 6
    print(f"  Expected edges: {expected_count}, actual: {len(edges)}")
    assert len(edges) == expected_count

Edge Geometry and Boundaries

import h3

# Create an edge and examine its geometry
center = h3.latlng_to_cell(51.5074, -0.1278, 9)  # London
neighbors = h3.grid_ring(center, k=1)
edge = h3.cells_to_directed_edge(center, neighbors[0])

print(f"Analyzing edge: {edge}")

# Get edge boundary
boundary = h3.directed_edge_to_boundary(edge)
print(f"Edge boundary points: {len(boundary)}")

for i, (lat, lng) in enumerate(boundary):
    print(f"  Point {i}: {lat:.6f}, {lng:.6f}")

# Compare with cell boundaries
origin_boundary = h3.cell_to_boundary(center)
dest_boundary = h3.cell_to_boundary(neighbors[0])

print(f"\nOrigin cell boundary: {len(origin_boundary)} points")
print(f"Destination cell boundary: {len(dest_boundary)} points")

# Edge boundary should be part of both cell boundaries
print(f"\nEdge represents shared boundary between cells")

Edge Network Analysis

import h3

# Build a local edge network
center = h3.latlng_to_cell(37.7749, -122.4194, 8)
region = h3.grid_disk(center, k=2)

print(f"Analyzing edge network for {len(region)} cells")

# Collect all edges within the region
all_edges = []
edge_count_by_cell = {}

for cell in region:
    edges = h3.origin_to_directed_edges(cell)
    
    # Filter edges to only include those within our region
    internal_edges = []
    for edge in edges:
        dest = h3.get_directed_edge_destination(edge)
        if dest in region:
            internal_edges.append(edge)
    
    all_edges.extend(internal_edges)
    edge_count_by_cell[cell] = len(internal_edges)

print(f"Total internal edges: {len(all_edges)}")

# Analyze edge distribution
edge_counts = list(edge_count_by_cell.values())
print(f"Edge count per cell - min: {min(edge_counts)}, max: {max(edge_counts)}, avg: {sum(edge_counts)/len(edge_counts):.1f}")

# Verify each edge connects cells within region
print("\nValidating edge network:")
valid_edges = 0
for edge in all_edges:
    origin, dest = h3.directed_edge_to_cells(edge)
    if origin in region and dest in region:
        valid_edges += 1

print(f"Valid internal edges: {valid_edges}/{len(all_edges)}")

Bidirectional Edge Analysis

import h3

# Analyze bidirectional relationships
cell_a = h3.latlng_to_cell(40.7589, -73.9851, 9)
neighbors = h3.grid_ring(cell_a, k=1)
cell_b = neighbors[0]

print(f"Cell A: {cell_a}")
print(f"Cell B: {cell_b}")

# Create edges in both directions
edge_a_to_b = h3.cells_to_directed_edge(cell_a, cell_b)
edge_b_to_a = h3.cells_to_directed_edge(cell_b, cell_a)

print(f"A->B edge: {edge_a_to_b}")
print(f"B->A edge: {edge_b_to_a}")
print(f"Edges are different: {edge_a_to_b != edge_b_to_a}")

# Verify both edges represent the same geometric boundary
boundary_a_to_b = h3.directed_edge_to_boundary(edge_a_to_b)
boundary_b_to_a = h3.directed_edge_to_boundary(edge_b_to_a)

print(f"\nBoundary A->B: {len(boundary_a_to_b)} points")
print(f"Boundary B->A: {len(boundary_b_to_a)} points")

# Boundaries should be related (possibly reversed)
print(f"Same boundary points: {set(boundary_a_to_b) == set(boundary_b_to_a)}")

# Check all pairs of neighbors have symmetric edges
cell_edges = h3.origin_to_directed_edges(cell_a)
print(f"\nSymmetric edge verification:")

for edge in cell_edges:
    neighbor = h3.get_directed_edge_destination(edge)
    reverse_edge = h3.cells_to_directed_edge(neighbor, cell_a)
    
    print(f"  {cell_a} -> {neighbor}: {edge}")
    print(f"  {neighbor} -> {cell_a}: {reverse_edge}")
    print(f"    Both valid: {h3.is_valid_directed_edge(edge) and h3.is_valid_directed_edge(reverse_edge)}")

Edge Length Calculation

import h3

# Calculate edge lengths using the edge measurement functions
center = h3.latlng_to_cell(0, 0, 10)  # Equator, high resolution
edges = h3.origin_to_directed_edges(center)

print(f"Edge length analysis for resolution 10 cell at equator:")
print(f"Cell has {len(edges)} edges")

# Calculate length of each edge
edge_lengths = []
for i, edge in enumerate(edges):
    length_km = h3.edge_length(edge, 'km')
    length_m = h3.edge_length(edge, 'm')
    edge_lengths.append(length_km)
    
    print(f"  Edge {i}: {length_km:.3f} km ({length_m:.1f} m)")

# Compare to average for this resolution
avg_edge_length = h3.average_hexagon_edge_length(10, 'km')
actual_avg = sum(edge_lengths) / len(edge_lengths)

print(f"\nAverage edge length (H3 system): {avg_edge_length:.3f} km")
print(f"Average edge length (this cell): {actual_avg:.3f} km")
print(f"Match: {abs(avg_edge_length - actual_avg) < 0.001}")

# Variation in edge lengths (should be minimal for regular hexagon)
max_length = max(edge_lengths)
min_length = min(edge_lengths)
variation = (max_length - min_length) / avg_edge_length

print(f"Edge length variation: {variation:.1%}")

Install with Tessl CLI

npx tessl i tessl/pypi-h3

docs

advanced-operations.md

cell-hierarchy.md

core-cell-operations.md

directed-edges.md

grid-navigation.md

index.md

measurements.md

polygon-operations.md

tile.json