github.com/liucxer/courier@v1.7.1/h3/h3api.go (about)

     1  package h3
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  )
     7  
     8  // Maximum number of cell boundary vertices; worst case is pentagon:
     9  // 5 original Verts + 5 edge crossings
    10  const MAX_CELL_BNDRY_VERTS = 10
    11  
    12  /**
    13    @brief latitude/longitude in radians
    14  */
    15  type GeoCoord struct {
    16  	Lat float64 ///< latitude in radians
    17  	Lon float64 ///< longitude in radians
    18  }
    19  
    20  func (g GeoCoord) String() string {
    21  	return fmt.Sprintf("%f,%f", g.Lat, g.Lon)
    22  }
    23  
    24  func (g GeoCoord) AsDegrees() *GeoCoord {
    25  	return &GeoCoord{
    26  		Lon: normalizeDegree(radsToDegs(g.Lon), -180.0, 180),
    27  		Lat: normalizeDegree(radsToDegs(g.Lat), -90, 90),
    28  	}
    29  }
    30  
    31  func (g GeoCoord) AsRadians() *GeoCoord {
    32  	return &GeoCoord{
    33  		Lon: radsToDegs(g.Lon),
    34  		Lat: radsToDegs(g.Lat),
    35  	}
    36  }
    37  
    38  /**
    39    @brief cell boundary in latitude/longitude
    40  */
    41  type GeoBoundary struct {
    42  	numVerts int        ///< number of vertices
    43  	Verts    []GeoCoord ///< vertices in ccw order
    44  }
    45  
    46  func (gb GeoBoundary) String() string {
    47  	buf := bytes.NewBuffer(nil)
    48  	buf.WriteRune('[')
    49  	for i := range gb.Verts {
    50  		if i != 0 {
    51  			buf.WriteRune(' ')
    52  		}
    53  		buf.WriteString(gb.Verts[i].String())
    54  	}
    55  	buf.WriteRune(']')
    56  	return buf.String()
    57  }
    58  
    59  func (gb GeoBoundary) AsDegrees() *GeoBoundary {
    60  	list := make([]GeoCoord, len(gb.Verts))
    61  
    62  	for i := range gb.Verts {
    63  		list[i] = *(gb.Verts[i].AsDegrees())
    64  	}
    65  
    66  	gb.Verts = list
    67  
    68  	return &gb
    69  }
    70  
    71  func (gb GeoBoundary) AsRadians() *GeoBoundary {
    72  	list := make([]GeoCoord, len(gb.Verts))
    73  
    74  	for i := range gb.Verts {
    75  		list[i] = *(gb.Verts[i].AsDegrees())
    76  	}
    77  
    78  	gb.Verts = list
    79  
    80  	return &gb
    81  }
    82  
    83  /**
    84   *  @brief similar to GeoBoundary, but requires more alloc work
    85   */
    86  type Geofence struct {
    87  	numVerts int
    88  	verts    []GeoCoord
    89  }
    90  
    91  func (g *Geofence) IsZero() bool {
    92  	return g == nil || g.numVerts == 0
    93  }
    94  
    95  func (g *Geofence) NewIterate() func(vertexA *GeoCoord, vertexB *GeoCoord) bool {
    96  	loopIndex := -1
    97  
    98  	return func(vertexA *GeoCoord, vertexB *GeoCoord) bool {
    99  		loopIndex++
   100  
   101  		if loopIndex >= g.numVerts {
   102  			return false
   103  		}
   104  
   105  		*vertexA = g.verts[loopIndex]
   106  		*vertexB = g.verts[(loopIndex+1)%g.numVerts]
   107  
   108  		return true
   109  	}
   110  }
   111  
   112  /**
   113   *  @brief Simplified core of GeoJSON Polygon coordinates definition
   114   */
   115  type GeoPolygon struct {
   116  	geofence Geofence   ///< exterior boundary of the polygon
   117  	numHoles int        ///< number of elements in the array pointed to by holes
   118  	holes    []Geofence ///< interior boundaries (holes) in the polygon
   119  }
   120  
   121  /**
   122   *  @brief Simplified core of GeoJSON MultiPolygon coordinates definition
   123   */
   124  type GeoMultiPolygon struct {
   125  	numPolygons int
   126  	polygons    []GeoPolygon
   127  }
   128  
   129  /**
   130   *  @brief A coordinate node in a linked geo structure, part of a linked list
   131   */
   132  type LinkedGeoCoord struct {
   133  	vertex GeoCoord
   134  	next   *LinkedGeoCoord
   135  }
   136  
   137  /**
   138   *  @brief A loop node in a linked geo structure, part of a linked list
   139   */
   140  type LinkedGeoLoop struct {
   141  	first *LinkedGeoCoord
   142  	last  *LinkedGeoCoord
   143  	next  *LinkedGeoLoop
   144  }
   145  
   146  func (l *LinkedGeoLoop) IsZero() bool {
   147  	return l == nil || l.first == nil
   148  }
   149  
   150  func (l *LinkedGeoLoop) NewIterate() func(vertexA *GeoCoord, vertexB *GeoCoord) bool {
   151  	var currentCoord, nextCoord *LinkedGeoCoord
   152  
   153  	return func(vertexA *GeoCoord, vertexB *GeoCoord) bool {
   154  		var getNextCoord = func(coordToCheck *LinkedGeoCoord) *LinkedGeoCoord {
   155  			if coordToCheck == nil {
   156  				return l.first
   157  			}
   158  			return currentCoord.next
   159  
   160  		}
   161  
   162  		currentCoord = getNextCoord(currentCoord)
   163  
   164  		if currentCoord == nil {
   165  			return false
   166  		}
   167  
   168  		*vertexA = currentCoord.vertex
   169  		nextCoord = getNextCoord(currentCoord.next)
   170  		*vertexB = nextCoord.vertex
   171  
   172  		return true
   173  	}
   174  }
   175  
   176  /**
   177   *  @brief A polygon node in a linked geo structure, part of a linked list.
   178   */
   179  type LinkedGeoPolygon struct {
   180  	first *LinkedGeoLoop
   181  	last  *LinkedGeoLoop
   182  	next  *LinkedGeoPolygon
   183  }
   184  
   185  /**
   186   * @brief IJ hexagon coordinates
   187   *
   188   * Each axis is spaced 120 degrees apart.
   189   */
   190  type CoordIJ struct {
   191  	i int ///< i component
   192  	j int ///< j component
   193  }