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

     1  package h3
     2  
     3  import "C"
     4  import (
     5  	"math"
     6  )
     7  
     8  /**
     9   * @brief IJK hexagon coordinates
    10   *
    11   * Each axis is spaced 120 degrees apart.
    12   */
    13  type CoordIJK struct {
    14  	i int
    15  	j int
    16  	k int
    17  }
    18  
    19  /** @brief CoordIJK unit vectors corresponding to the 7 H3 digits.
    20   */
    21  var UNIT_VECS = [7]CoordIJK{
    22  	{0, 0, 0}, // direction 0
    23  	{0, 0, 1}, // direction 1
    24  	{0, 1, 0}, // direction 2
    25  	{0, 1, 1}, // direction 3
    26  	{1, 0, 0}, // direction 4
    27  	{1, 0, 1}, // direction 5
    28  	{1, 1, 0}, // direction 6
    29  }
    30  
    31  type Direction uint
    32  
    33  /** @brief H3 digit representing ijk+ axes direction.
    34   * Values will be within the lowest 3 bits of an integer.
    35   */
    36  const (
    37  	/** H3 digit in center */
    38  	CENTER_DIGIT Direction = 0
    39  	/** H3 digit in k-axes direction */
    40  	K_AXES_DIGIT Direction = 1
    41  	/** H3 digit in j-axes direction */
    42  	J_AXES_DIGIT Direction = 2
    43  	/** H3 digit in j == k direction */
    44  	JK_AXES_DIGIT Direction = J_AXES_DIGIT | K_AXES_DIGIT /* 3 */
    45  	/** H3 digit in i-axes direction */
    46  	I_AXES_DIGIT Direction = 4
    47  	/** H3 digit in i == k direction */
    48  	IK_AXES_DIGIT Direction = I_AXES_DIGIT | K_AXES_DIGIT /* 5 */
    49  	/** H3 digit in i == j direction */
    50  	IJ_AXES_DIGIT Direction = I_AXES_DIGIT | J_AXES_DIGIT /* 6 */
    51  	/** H3 digit in the invalid direction */
    52  	INVALID_DIGIT Direction = 7
    53  	/** Valid digits will be less than this value. Same value as INVALID_DIGIT.
    54  	 */
    55  	NUM_DIGITS Direction = INVALID_DIGIT
    56  )
    57  
    58  /**
    59   * Sets an IJK coordinate to the specified component values.
    60   *
    61   * @param ijk The IJK coordinate to set.
    62   * @param i The desired i component value.
    63   * @param j The desired j component value.
    64   * @param k The desired k component value.
    65   */
    66  func _setIJK(ijk *CoordIJK, i, j, k int) {
    67  	ijk.i = i
    68  	ijk.j = j
    69  	ijk.k = k
    70  }
    71  
    72  func fabsl(arg0 float64) float64 {
    73  	return math.Abs(arg0)
    74  }
    75  
    76  /**
    77   * Determine the containing hex in ijk+ coordinates for a 2D cartesian
    78   * coordinate vector (from DGGRID).
    79   *
    80   * @param v The 2D cartesian coordinate vector.
    81   * @param h The ijk+ coordinates of the containing hex.
    82   */
    83  func _hex2dToCoordIJK(v *Vec2d, h *CoordIJK) {
    84  	var a1, a2 float64
    85  	var x1, x2 float64
    86  	var m1, m2 int
    87  	var r1, r2 float64
    88  
    89  	// quantize into the ij system and then normalize
    90  	h.k = 0
    91  	a1 = fabsl(v.x)
    92  	a2 = fabsl(v.y)
    93  
    94  	// first do a reverse conversion
    95  	x2 = a2 / M_SIN60
    96  	x1 = a1 + x2/2.0
    97  
    98  	// check if we have the center of a hex
    99  	m1 = int(x1)
   100  	m2 = int(x2)
   101  
   102  	// otherwise round correctly
   103  	r1 = x1 - float64(m1)
   104  	r2 = x2 - float64(m2)
   105  	if r1 < 0.5 {
   106  		if r1 < 1.0/3.0 {
   107  			if r2 < (1.0+r1)/2.0 {
   108  				h.i = m1
   109  				h.j = m2
   110  			} else {
   111  				h.i = m1
   112  				h.j = m2 + 1
   113  			}
   114  		} else {
   115  			if r2 < (1.0 - r1) {
   116  				h.j = m2
   117  			} else {
   118  				h.j = m2 + 1
   119  			}
   120  
   121  			if (1.0-r1) <= r2 && r2 < (2.0*r1) {
   122  				h.i = m1 + 1
   123  			} else {
   124  				h.i = m1
   125  			}
   126  		}
   127  	} else {
   128  		if r1 < 2.0/3.0 {
   129  			if r2 < (1.0 - r1) {
   130  				h.j = m2
   131  			} else {
   132  				h.j = m2 + 1
   133  			}
   134  
   135  			if (2.0*r1-1.0) < r2 && r2 < (1.0-r1) {
   136  				h.i = m1
   137  			} else {
   138  				h.i = m1 + 1
   139  			}
   140  		} else {
   141  			if r2 < (r1 / 2.0) {
   142  				h.i = m1 + 1
   143  				h.j = m2
   144  			} else {
   145  				h.i = m1 + 1
   146  				h.j = m2 + 1
   147  			}
   148  		}
   149  	}
   150  
   151  	// now fold across the axes if necessary
   152  	if v.x < 0 {
   153  		if h.j%2 == 0 {
   154  			// even
   155  			axisi := int64(h.j / 2)
   156  			diff := int64(h.i) - axisi
   157  			h.i = int(float64(h.i) - 2*float64(diff))
   158  		} else {
   159  			axisi := int64((h.j + 1) / 2)
   160  			diff := int64(h.i) - axisi
   161  			h.i = int(float64(h.i) - (2*float64(diff) + 1))
   162  		}
   163  	}
   164  
   165  	if v.y < 0.0 {
   166  		h.i = h.i - (2*h.j+1)/2
   167  		h.j = -1 * h.j
   168  	}
   169  
   170  	_ijkNormalize(h)
   171  }
   172  
   173  /**
   174   * Find the center point in 2D cartesian coordinates of a hex.
   175   *
   176   * @param h The ijk coordinates of the hex.
   177   * @param v The 2D cartesian coordinates of the hex center point.
   178   */
   179  func _ijkToHex2d(h *CoordIJK, v *Vec2d) {
   180  	i := float64(h.i - h.k)
   181  	j := float64(h.j - h.k)
   182  	v.x = i - 0.5*j
   183  	v.y = j * M_SQRT3_2
   184  }
   185  
   186  /**
   187   * Returns whether or not two ijk coordinates contain exactly the same
   188   * component values.
   189   *
   190   * @param c1 The first set of ijk coordinates.
   191   * @param c2 The second set of ijk coordinates.
   192   * @return 1 if the two addresses match, 0 if they do not.
   193   */
   194  func _ijkMatches(c1 *CoordIJK, c2 *CoordIJK) bool {
   195  	return (c1.i == c2.i && c1.j == c2.j && c1.k == c2.k)
   196  }
   197  
   198  /**
   199   * Add two ijk coordinates.
   200   *
   201   * @param h1 The first set of ijk coordinates.
   202   * @param h2 The second set of ijk coordinates.
   203   * @param sum The sum of the two sets of ijk coordinates.
   204   */
   205  func _ijkAdd(h1 *CoordIJK, h2 *CoordIJK, sum *CoordIJK) {
   206  	sum.i = h1.i + h2.i
   207  	sum.j = h1.j + h2.j
   208  	sum.k = h1.k + h2.k
   209  }
   210  
   211  /**
   212   * Subtract two ijk coordinates.
   213   *
   214   * @param h1 The first set of ijk coordinates.
   215   * @param h2 The second set of ijk coordinates.
   216   * @param diff The difference of the two sets of ijk coordinates (h1 - h2).
   217   */
   218  func _ijkSub(h1 *CoordIJK, h2 *CoordIJK, diff *CoordIJK) {
   219  	diff.i = h1.i - h2.i
   220  	diff.j = h1.j - h2.j
   221  	diff.k = h1.k - h2.k
   222  }
   223  
   224  /**
   225   * Uniformly scale ijk coordinates by a scalar. Works in place.
   226   *
   227   * @param c The ijk coordinates to scale.
   228   * @param factor The scaling factor.
   229   */
   230  func _ijkScale(c *CoordIJK, factor int) {
   231  	c.i *= factor
   232  	c.j *= factor
   233  	c.k *= factor
   234  }
   235  
   236  /**
   237   * Normalizes ijk coordinates by setting the components to the smallest possible
   238   * values. Works in place.
   239   *
   240   * @param c The ijk coordinates to normalize.
   241   */
   242  func _ijkNormalize(c *CoordIJK) {
   243  	// remove any negative values
   244  	if c.i < 0 {
   245  		c.j -= c.i
   246  		c.k -= c.i
   247  		c.i = 0
   248  	}
   249  
   250  	if c.j < 0 {
   251  		c.i -= c.j
   252  		c.k -= c.j
   253  		c.j = 0
   254  	}
   255  
   256  	if c.k < 0 {
   257  		c.i -= c.k
   258  		c.j -= c.k
   259  		c.k = 0
   260  	}
   261  
   262  	// remove the min value if needed
   263  	min := c.i
   264  	if c.j < min {
   265  		min = c.j
   266  	}
   267  	if c.k < min {
   268  		min = c.k
   269  	}
   270  	if min > 0 {
   271  		c.i -= min
   272  		c.j -= min
   273  		c.k -= min
   274  	}
   275  }
   276  
   277  /**
   278   * Determines the H3 digit corresponding to a unit vector in ijk coordinates.
   279   *
   280   * @param ijk The ijk coordinates; must be a unit vector.
   281   * @return The H3 digit (0-6) corresponding to the ijk unit vector, or
   282   * INVALID_DIGIT on failure.
   283   */
   284  func _unitIjkToDigit(ijk *CoordIJK) Direction {
   285  	c := *ijk
   286  	_ijkNormalize(&c)
   287  	digit := INVALID_DIGIT
   288  	for i := int(CENTER_DIGIT); i < int(NUM_DIGITS); i++ {
   289  		if _ijkMatches(&c, &UNIT_VECS[i]) {
   290  			digit = Direction(i)
   291  			break
   292  		}
   293  	}
   294  
   295  	return digit
   296  }
   297  
   298  /**
   299   * Find the normalized ijk coordinates of the indexing parent of a cell in a
   300   * counter-clockwise aperture 7 grid. Works in place.
   301   *
   302   * @param ijk The ijk coordinates.
   303   */
   304  func _upAp7(ijk *CoordIJK) {
   305  	// convert to CoordIJ
   306  	i := ijk.i - ijk.k
   307  	j := ijk.j - ijk.k
   308  	ijk.i = int(lroundl(float64(3*i-j) / 7.0))
   309  	ijk.j = int(lroundl(float64(i+2*j) / 7.0))
   310  	ijk.k = 0
   311  	_ijkNormalize(ijk)
   312  }
   313  
   314  /**
   315   * Find the normalized ijk coordinates of the indexing parent of a cell in a
   316   * clockwise aperture 7 grid. Works in place.
   317   *
   318   * @param ijk The ijk coordinates.
   319   */
   320  func _upAp7r(ijk *CoordIJK) {
   321  	// convert to CoordIJ
   322  	i := ijk.i - ijk.k
   323  	j := ijk.j - ijk.k
   324  	ijk.i = int(lroundl(float64(2*i+j) / 7.0))
   325  	ijk.j = int(lroundl(float64(3*j-i) / 7.0))
   326  	ijk.k = 0
   327  	_ijkNormalize(ijk)
   328  }
   329  
   330  /**
   331   * Find the normalized ijk coordinates of the hex centered on the indicated
   332   * hex at the next finer aperture 7 counter-clockwise resolution. Works in
   333   * place.
   334   *
   335   * @param ijk The ijk coordinates.
   336   */
   337  func _downAp7(ijk *CoordIJK) {
   338  	// res r unit vectors in res r+1
   339  	iVec := CoordIJK{3, 0, 1}
   340  	jVec := CoordIJK{1, 3, 0}
   341  	kVec := CoordIJK{0, 1, 3}
   342  	_ijkScale(&iVec, ijk.i)
   343  	_ijkScale(&jVec, ijk.j)
   344  	_ijkScale(&kVec, ijk.k)
   345  	_ijkAdd(&iVec, &jVec, ijk)
   346  	_ijkAdd(ijk, &kVec, ijk)
   347  	_ijkNormalize(ijk)
   348  }
   349  
   350  /**
   351   * Find the normalized ijk coordinates of the hex centered on the indicated
   352   * hex at the next finer aperture 7 clockwise resolution. Works in place.
   353   *
   354   * @param ijk The ijk coordinates.
   355   */
   356  func _downAp7r(ijk *CoordIJK) {
   357  	// res r unit vectors in res r+1
   358  	iVec := CoordIJK{3, 1, 0}
   359  	jVec := CoordIJK{0, 3, 1}
   360  	kVec := CoordIJK{1, 0, 3}
   361  	_ijkScale(&iVec, ijk.i)
   362  	_ijkScale(&jVec, ijk.j)
   363  	_ijkScale(&kVec, ijk.k)
   364  	_ijkAdd(&iVec, &jVec, ijk)
   365  	_ijkAdd(ijk, &kVec, ijk)
   366  	_ijkNormalize(ijk)
   367  }
   368  
   369  /**
   370   * Find the normalized ijk coordinates of the hex in the specified digit
   371   * direction from the specified ijk coordinates. Works in place.
   372   *
   373   * @param ijk The ijk coordinates.
   374   * @param digit The digit direction from the original ijk coordinates.
   375   */
   376  func _neighbor(ijk *CoordIJK, digit Direction) {
   377  	if digit > CENTER_DIGIT && digit < NUM_DIGITS {
   378  		_ijkAdd(ijk, &UNIT_VECS[digit], ijk)
   379  		_ijkNormalize(ijk)
   380  	}
   381  }
   382  
   383  /**
   384   * Rotates ijk coordinates 60 degrees counter-clockwise. Works in place.
   385   *
   386   * @param ijk The ijk coordinates.
   387   */
   388  func _ijkRotate60ccw(ijk *CoordIJK) {
   389  	// unit vector rotations
   390  	iVec := CoordIJK{1, 1, 0}
   391  	jVec := CoordIJK{0, 1, 1}
   392  	kVec := CoordIJK{1, 0, 1}
   393  	_ijkScale(&iVec, ijk.i)
   394  	_ijkScale(&jVec, ijk.j)
   395  	_ijkScale(&kVec, ijk.k)
   396  	_ijkAdd(&iVec, &jVec, ijk)
   397  	_ijkAdd(ijk, &kVec, ijk)
   398  	_ijkNormalize(ijk)
   399  }
   400  
   401  /**
   402   * Rotates ijk coordinates 60 degrees clockwise. Works in place.
   403   *
   404   * @param ijk The ijk coordinates.
   405   */
   406  func _ijkRotate60cw(ijk *CoordIJK) {
   407  	// unit vector rotations
   408  	iVec := CoordIJK{1, 0, 1}
   409  	jVec := CoordIJK{1, 1, 0}
   410  	kVec := CoordIJK{0, 1, 1}
   411  	_ijkScale(&iVec, ijk.i)
   412  	_ijkScale(&jVec, ijk.j)
   413  	_ijkScale(&kVec, ijk.k)
   414  	_ijkAdd(&iVec, &jVec, ijk)
   415  	_ijkAdd(ijk, &kVec, ijk)
   416  	_ijkNormalize(ijk)
   417  }
   418  
   419  /**
   420   * Rotates indexing digit 60 degrees counter-clockwise. Returns result.
   421   *
   422   * @param digit Indexing digit (between 1 and 6 inclusive)
   423   */
   424  func _rotate60ccw(digit Direction) Direction {
   425  	switch digit {
   426  	case K_AXES_DIGIT:
   427  		return IK_AXES_DIGIT
   428  	case IK_AXES_DIGIT:
   429  		return I_AXES_DIGIT
   430  	case I_AXES_DIGIT:
   431  		return IJ_AXES_DIGIT
   432  	case IJ_AXES_DIGIT:
   433  		return J_AXES_DIGIT
   434  	case J_AXES_DIGIT:
   435  		return JK_AXES_DIGIT
   436  	case JK_AXES_DIGIT:
   437  		return K_AXES_DIGIT
   438  	default:
   439  		return digit
   440  	}
   441  }
   442  
   443  /**
   444   * Rotates indexing digit 60 degrees clockwise. Returns result.
   445   *
   446   * @param digit Indexing digit (between 1 and 6 inclusive)
   447   */
   448  func _rotate60cw(digit Direction) Direction {
   449  	switch digit {
   450  	case K_AXES_DIGIT:
   451  		return JK_AXES_DIGIT
   452  	case JK_AXES_DIGIT:
   453  		return J_AXES_DIGIT
   454  	case J_AXES_DIGIT:
   455  		return IJ_AXES_DIGIT
   456  	case IJ_AXES_DIGIT:
   457  		return I_AXES_DIGIT
   458  	case I_AXES_DIGIT:
   459  		return IK_AXES_DIGIT
   460  	case IK_AXES_DIGIT:
   461  		return K_AXES_DIGIT
   462  	default:
   463  		return digit
   464  	}
   465  }
   466  
   467  /**
   468   * Find the normalized ijk coordinates of the hex centered on the indicated
   469   * hex at the next finer aperture 3 counter-clockwise resolution. Works in
   470   * place.
   471   *
   472   * @param ijk The ijk coordinates.
   473   */
   474  func _downAp3(ijk *CoordIJK) {
   475  	// res r unit vectors in res r+1
   476  	iVec := CoordIJK{2, 0, 1}
   477  	jVec := CoordIJK{1, 2, 0}
   478  	kVec := CoordIJK{0, 1, 2}
   479  	_ijkScale(&iVec, ijk.i)
   480  	_ijkScale(&jVec, ijk.j)
   481  	_ijkScale(&kVec, ijk.k)
   482  	_ijkAdd(&iVec, &jVec, ijk)
   483  	_ijkAdd(ijk, &kVec, ijk)
   484  	_ijkNormalize(ijk)
   485  }
   486  
   487  /**
   488   * Find the normalized ijk coordinates of the hex centered on the indicated
   489   * hex at the next finer aperture 3 clockwise resolution. Works in place.
   490   *
   491   * @param ijk The ijk coordinates.
   492   */
   493  func _downAp3r(ijk *CoordIJK) {
   494  	// res r unit vectors in res r+1
   495  	iVec := CoordIJK{2, 1, 0}
   496  	jVec := CoordIJK{0, 2, 1}
   497  	kVec := CoordIJK{1, 0, 2}
   498  	_ijkScale(&iVec, ijk.i)
   499  	_ijkScale(&jVec, ijk.j)
   500  	_ijkScale(&kVec, ijk.k)
   501  	_ijkAdd(&iVec, &jVec, ijk)
   502  	_ijkAdd(ijk, &kVec, ijk)
   503  	_ijkNormalize(ijk)
   504  }
   505  
   506  /**
   507   * Finds the distance between the two coordinates. Returns result.
   508   *
   509   * @param c1 The first set of ijk coordinates.
   510   * @param c2 The second set of ijk coordinates.
   511   */
   512  func ijkDistance(c1 *CoordIJK, c2 *CoordIJK) float64 {
   513  	diff := CoordIJK{}
   514  	_ijkSub(c1, c2, &diff)
   515  	_ijkNormalize(&diff)
   516  	absDiff := &CoordIJK{int(math.Abs(float64(diff.i))), int(math.Abs(float64(diff.j))), int(math.Abs(float64(diff.k)))}
   517  	return math.Max(float64(absDiff.i), math.Max(float64(absDiff.j), float64(absDiff.k)))
   518  }
   519  
   520  /**
   521   * Transforms coordinates from the IJK+ coordinate system to the IJ coordinate
   522   * system.
   523   *
   524   * @param ijk The input IJK+ coordinates
   525   * @param ij The output IJ coordinates
   526   */
   527  func ijkToIj(ijk *CoordIJK, ij *CoordIJ) {
   528  	ij.i = ijk.i - ijk.k
   529  	ij.j = ijk.j - ijk.k
   530  }
   531  
   532  /**
   533   * Transforms coordinates from the IJ coordinate system to the IJK+ coordinate
   534   * system.
   535   *
   536   * @param ij The input IJ coordinates
   537   * @param ijk The output IJK+ coordinates
   538   */
   539  func ijToIjk(ij *CoordIJ, ijk *CoordIJK) {
   540  	ijk.i = ij.i
   541  	ijk.j = ij.j
   542  	ijk.k = 0
   543  	_ijkNormalize(ijk)
   544  }
   545  
   546  /**
   547   * Convert IJK coordinates to cube coordinates, in place
   548   * @param ijk Coordinate to convert
   549   */
   550  func ijkToCube(ijk *CoordIJK) {
   551  	//
   552  	// * Convert IJK coordinates to cube coordinates, in place
   553  	// * @param ijk Coordinate to convert
   554  	//
   555  	ijk.i = -ijk.i + ijk.k
   556  	ijk.j = ijk.j - ijk.k
   557  	ijk.k = -ijk.i - ijk.j
   558  }
   559  
   560  /**
   561   * Convert cube coordinates to IJK coordinates, in place
   562   * @param ijk Coordinate to convert
   563   */
   564  func cubeToIjk(ijk *CoordIJK) {
   565  	//
   566  	// * Convert cube coordinates to IJK coordinates, in place
   567  	// * @param ijk Coordinate to convert
   568  	//
   569  	ijk.i = -ijk.i
   570  	ijk.k = 0
   571  	_ijkNormalize(ijk)
   572  }
   573  
   574  func lroundl(x float64) int32 {
   575  	return int32(math.Round(x))
   576  }