8 static int inversecantor(int cantor, int *x, int *y);
11 * This file is written by Nathan Wagner and dedicated to the public
15 double HL_vertexv[12] = {
16 .577350269189625764509148780502, 0.0,
17 .288675134594812882254574390251, 0.5,
18 -.288675134594812882254574390251, 0.5,
19 -.577350269189625764509148780502, 0.0,
20 -.288675134594812882254574390251, -0.5,
21 .288675134594812882254574390251, -0.5};
23 double HL_fand[16] = {
25 .577350269189625764509148780502, 0.0,
26 .288675134594812882254574390251, 0.5,
27 -.288675134594812882254574390251, 0.5,
28 -.577350269189625764509148780502, 0.0,
29 -.288675134594812882254574390251, -0.5,
30 .288675134594812882254574390251, -0.5,
31 .577350269189625764509148780502, 0.0
34 double HL_hfand[16] = {
36 0.0, .577350269189625764509148780502,
37 0.5, .288675134594812882254574390251,
38 0.5, -.288675134594812882254574390251,
39 0.0, -.577350269189625764509148780502,
40 -0.5, -.288675134594812882254574390251,
41 -0.5, .288675134594812882254574390251,
42 0.0, .577350269189625764509148780502
47 .577350269189625764509148780502f, 0.0f,
48 .288675134594812882254574390251f, 0.5f,
49 -.288675134594812882254574390251f, 0.5f,
50 -.577350269189625764509148780502f, 0.0f,
51 -.288675134594812882254574390251f, -0.5f,
52 .288675134594812882254574390251f, -0.5f,
53 .577350269189625764509148780502f, 0.0f
56 float HL_hfanf[16] = {
58 0.0f, .577350269189625764509148780502f,
59 0.5f, .288675134594812882254574390251f,
60 0.5f, -.288675134594812882254574390251f,
61 0.0f, -.577350269189625764509148780502f,
62 -0.5f, -.288675134594812882254574390251f,
63 -0.5f, .288675134594812882254574390251f,
64 0.0f, .577350269189625764509148780502f
67 /* size of a square that will exactly fit in a hexagon */
68 /* 2.0/(1+sqrt(3.0)) */
69 double HL_square = .73205080756887729352;
71 /* these all are for a hex one unit across */
72 static double hexptvd[6][2] = {
73 {.577350269189625764509148780502, 0.0}, /* 1.0/sqrt3 */
74 {.288675134594812882254574390251, 0.5}, /* 0.5/sqrt3 */
75 {-.288675134594812882254574390251, 0.5},
76 {-.577350269189625764509148780502, 0.0},
77 {-.288675134594812882254574390251, -0.5},
78 {.288675134594812882254574390251, -0.5}
83 /* TODO how is this related? to the above? */
84 static double texptvd[6][2] = {
85 {1.154700538379251529018297561004, 0.5}, /* 2.0/sqrt3 */
86 {.866025403784438646763723170753, 1.0}, /* 1.5/sqrt3 */
87 {.288675134594812882254574390251, 1.0},
89 {.288675134594812882254574390251, 0.0},
90 {.866025403784438646763723170753, 0.0}
93 static double hexpthd[6][2] = {
94 {0.0, .577350269189625764509148780502},
95 {0.5, .288675134594812882254574390251},
96 {0.5, -.288675134594812882254574390251},
97 {0.0, -.577350269189625764509148780502},
98 {-0.5, -.288675134594812882254574390251},
99 {-0.5, .288675134594812882254574390251}
105 c = 1.0 = distance from center to vertex
106 b = distance to hex side
107 a = distance along hex side
109 A = angle at point center, this is the polar coord angle
110 B = angle from vertex, this is 60 degrees
111 C = Other angle, which is 180 - 60 - A = 120 - A
113 sin B = sin 60 = sqrt(3) / 2
116 b = c * sin B / ( sin A cos B + sin B cos A)
118 c * sin B / ( sin A cos B + sin B cos A)
122 sinA 0.5 + sqrt3 * 0.5 cosA
137 #define RD (180.0 / M_PI)
138 /* angle ranges from 0-6 */
139 /* distance is 0 at origin, 1.0 at the hex side */
141 /* return the polar distance ? */
142 double HL_polar(double angle, double distance, double *x, double *y) {
143 double A, B, C, b, c;
151 /* convert angle to radians */
152 angle = angle * M_PI / 3.0;
154 /* calculate the distance along the ray to the hex side */
156 A = fmod(angle, M_PI/3.0); /* constrain to within an equilateral */
166 /* provided for completeness, but we don't use the value */
183 void HL_vertices(int cantor, double *vc) {
187 HL_hexcenter(cantor, &xc, &yc);
189 for (i=0; i<6; i++) {
190 *vc++ = hexptvd[i][0] + xc;
191 *vc++ = hexptvd[i][1] + yc;
193 *vc++ = hexptvd[0][0] + xc;
194 *vc++ = hexptvd[0][1] + yc;
197 void HL_trianglefan(int cantor, double *vc) {
198 HL_hexcenter(cantor, vc, vc+1);
199 HL_vertices(cantor, vc+2);
202 double HL_center_x(int cantor) {
205 HL_hexcenter(cantor, &x, 0);
209 double HL_center_y(int cantor) {
212 HL_hexcenter(cantor, 0, &y);
216 int HL_hexcenter(int cantor, double *xc, double *yc) {
218 double stride = 1.5/sqrt(3.0);
220 inversecantor(cantor, &x, &y);
222 if (xc) *xc = x * stride;
223 if (yc && x >= 0) *yc = y + ((x + 1) % 2) / 2.0 - 0.5;
224 if (yc && x < 0) *yc = y + ((-x + 1) % 2) / 2.0 - 0.5;
230 * This function assumes that the hexes are one unit across, and vertically
231 * oriented. If that is not the case, you will need to transform
232 * your input coordinates first.
234 int HL_cantor_bin(double x, double y) {
235 return HL_hexbin(1.0, x, y, 0, 0);
238 static int xy2ijk(int x, int y, int *i, int *j, int *k) {
244 pj = pj + (-x + 1) / 2;
254 return HL_cantor_xy(x,y);
257 static int ijk2xy(int i, int j, int k, int *x, int *y) {
274 return HL_cantor_xy(px,py);
277 int HL_cantor_ijk(int i, int j, int k) {
278 return ijk2xy(i,j,k,0,0);
281 int HL_distance(int from, int to) {
285 HL_cantor_arrays(from, 0, fc);
286 HL_cantor_arrays(to, 0, tc);
289 dist += abs(fc[i] - tc[i]);
295 int HL_hexes_within_range(int hex, int range, int *list, int size) {
300 return HL_hexes_at_range(hex, 0, list, size);
303 for (i=1;i<=range;i++) {
304 count += HL_hexes_at_range(hex, i, count > size ? 0 : list+count, size-count);
309 int HL_hexes_at_range(int hex, int range, int *list, int size) {
310 int q; /* p and q are count/loop vars */
311 int c[3]; /* ijk coord array */
318 } else if (range < 0) {
322 /* TODO don't bother to collect if the list isn't big enough? */
323 /* i.e. if (!list || size < range * 6) */
324 if (!list || size < 1) return range * 6;
326 HL_cantor_arrays(hex, 0, c);
329 hex = HL_cantor_ijkp(c);
331 for(q=0; q<size && q < range * 6; q++) {
333 hex = HL_adjhex(hex, q/range+2);
339 int HL_adjacent_hex(int start, int dir) {
340 if (dir < 0 || dir > 5) return 0;
342 return HL_adjhex(start, dir);
345 /* direction 0 is positive X , counter clockwise from there */
346 int HL_adjhex(int start, int dir) {
349 HL_cantor_arrays(start, 0, c);
353 c[0]--; c[1]++; break;
355 c[1]++; c[2]--; break;
357 c[0]++; c[2]--; break;
359 c[0]++; c[1]--; break;
361 c[1]--; c[2]++; break;
363 c[0]--; ; c[2]++; break;
366 return HL_cantor_ijkp(c);
369 int HL_cantor_xyp(int *xy) {
370 return HL_cantor_xy(xy[0], xy[1]);
373 int HL_cantor_ijkp(int *ijk) {
374 return HL_cantor_ijk(ijk[0], ijk[1], ijk[2]);
377 int HL_cantor_arrays(int can, int *xy, int *ijk) {
378 return HL_cantor_decode(can, xy, xy ? xy+1 : 0,
379 ijk, ijk ? ijk+1 : 0, ijk ? ijk+2 : 0);
382 int HL_cantor_decode(int can, int *x, int *y, int *i, int *j, int *k) {
385 inversecantor(can, &px, &py);
389 xy2ijk(px, py, i, j, k);
394 int HL_cantor_i(int cantor) {
397 HL_cantor_decode(cantor, 0,0, &i,0,0);
401 int HL_cantor_j(int cantor) {
404 HL_cantor_decode(cantor, 0,0, 0,&j,0);
408 int HL_cantor_k(int cantor) {
411 HL_cantor_decode(cantor, 0,0, 0,0,&k);
415 int HL_cantor_x(int cantor) {
417 inversecantor(cantor, &x, 0);
421 int HL_cantor_y(int cantor) {
423 inversecantor(cantor, 0, &y);
427 /* Determine if a map with these dimensions will overflow */
428 int HL_map_bounds_ok(int xdim, int ydim) {
430 /* return (x+y) * (x + y + 1) / 2 + y+1; */
432 if (INT_MAX - xdim - 1 < ydim) return 0;
433 if (INT_MAX / (xdim+ydim) < (xdim+ydim+1)) return 0;
434 if ( (xdim+ydim) * (xdim+ydim+1) / 2 > INT_MAX - ydim - 1)
440 int HL_map_max_dimension(void) {
443 low = 1; high = INT_MAX/2;
445 while (low != high - 1) {
446 try = (low + high) / 2;
447 if (HL_map_bounds_ok(try,try)) {
457 static int inversenatcantor(int cantor, int *x, int *y) {
462 w = (int)floor((sqrt(8.0 * cantor + 1.0) - 1.0)/2.0);
474 * map non negative integer pairs to their cantor pairing function
475 * number, plus one. We add one so that the result is never zero,
476 * leaving zero to be "invalid" or "none" or what have you.
479 static int natcantor(int x, int y) {
480 return (x+y) * (x + y + 1) / 2 + y+1;
483 /* See http://en.wikipedia.org/wiki/Cantor_pairing_function */
484 /* see also http://szudzik.com/ElegantPairing.pdf */
486 * if either coordinate is negative, map the integers onto the
487 * whole numbers, and then return the negative of the adjusted
488 * cantor number. As for most grids negative coordinates will
489 * be invalid, this will allow for a <= 0 test for invalid
490 * or out of bounds (on the negative side anyway, you'll
491 * still have to test for out of range on the positive side).
493 * TODO figure out what the maximum supported coordinates are
494 * for given integer sizes.
496 int HL_cantor_xy(int x, int y) {
497 if (x < 0 || y < 0) {
498 x = abs(2 * x) - (x < 0);
499 y = abs(2 * y) - (y < 0);
500 return -natcantor(x, y);
502 return natcantor(x,y);
505 static int inversecantor(int cantor, int *x, int *y) {
507 inversenatcantor(-cantor, x, y);
523 inversenatcantor(cantor, x, y);
534 /* y *must* be positive down as the xy /iso conversion assumes this */
535 static int hex_xy(struct hex *h) {
536 if (!h->iso) return 1;
538 h->y = -h->y - (h->x+1)/2;
540 /* need to round toward -inf, not toward zero, so x-1 */
541 h->y = -h->y - h->x/2;
550 static int hex_iso(struct hex *h) {
551 if (h->iso) return 1;
554 h->y = (-h->y - (h->x+1)/2);
556 /* need to round toward -inf, not toward zero, so x-1 */
557 h->y = (-h->y - (h->x)/2);
567 #define COS30 (.866025403784438646763723170752)
569 int HL_hexbin(double width, double x, double y, int *i, int *j) {
570 double z, rx, ry, rz;
571 double abs_dx, abs_dy, abs_dz;
575 /*x = x / cos(30 * M_PI / 180.0); */ /* rotated X coord */
577 y = y - x / 2.0; /* adjustment for rotated X */
579 /* adjust for actual hexwidth */
585 ix = rx = floor(x + 0.5);
586 iy = ry = floor(y + 0.5);
587 iz = rz = floor(z + 0.5);
592 abs_dx = fabs(rx - x);
593 abs_dy = fabs(ry - y);
594 abs_dz = fabs(rz - z);
596 if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
598 } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
612 return HL_cantor_xy(h.x, h.y);