Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/h3lib/include/coordijk.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,11 @@ static inline Direction _unitIjkToDigit(const CoordIJK *ijk) {
_ijkNormalize(&c);

Direction digit = INVALID_DIGIT;
for (Direction i = CENTER_DIGIT; i < NUM_DIGITS; i++) {
// Iterate with an int rather than a Direction: incrementing an enum is
// valid C but not C++, and this header is included by C++ code.
for (int i = CENTER_DIGIT; i < NUM_DIGITS; i++) {
if (_ijkMatches(&c, &UNIT_VECS[i])) {
digit = i;
digit = (Direction)i;
break;
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/h3lib/include/mathExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef MATHEXTENSIONS_H
#define MATHEXTENSIONS_H

#include <math.h>
#include <stdbool.h>
#include <stdint.h>

Expand All @@ -28,6 +29,25 @@
*/
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

/**
* Simultaneously compute the sine and cosine of an angle.
*
* Many H3 coordinate transforms need both sin(x) and cos(x) of the same angle.
* Computing them together lets the math library share the argument reduction
* and polynomial evaluation, which is roughly twice as fast as two independent
* sin()/cos() calls, while returning identical values. The compiler builtin
* lowers to a single libm `sincos` call where one exists and falls back to
* separate sin()/cos() otherwise, so this stays portable.
*/
static inline void _sincos(double x, double *s, double *c) {
#if defined(__GNUC__) || defined(__clang__)
__builtin_sincos(x, s, c);
#else
*s = sin(x);
*c = cos(x);
#endif
}

/** Evaluates to true if a + b would overflow for int32 */
static inline bool ADD_INT32S_OVERFLOWS(int32_t a, int32_t b) {
if (a > 0) {
Expand Down
15 changes: 11 additions & 4 deletions src/h3lib/include/vec3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "h3api.h"
#include "latLng.h"
#include "mathExtensions.h"

/** @struct Vec3d
* @brief 3D floating point structure
Expand All @@ -42,11 +43,17 @@ typedef struct {

/** Convert latitude and longitude to a unit Vec3d on the sphere. */
static inline Vec3d latLngToVec3(LatLng geo) {
double r = cos(geo.lat);
// sin and cos of the latitude and of the longitude are each needed as a
// pair, so compute them together instead of with four separate calls.
double sinLat, cosLat, sinLng, cosLng;
_sincos(geo.lat, &sinLat, &cosLat);
_sincos(geo.lng, &sinLng, &cosLng);

double r = cosLat;
Vec3d out = {
.x = cos(geo.lng) * r,
.y = sin(geo.lng) * r,
.z = sin(geo.lat),
.x = cosLng * r,
.y = sinLng * r,
.z = sinLat,
};
return out;
}
Expand Down
19 changes: 14 additions & 5 deletions src/h3lib/lib/faceijk.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "coordijk.h"
#include "h3Index.h"
#include "latLng.h"
#include "mathExtensions.h"
#include "vec3d.h"

/** square root of 7 and inverse square root of 7 */
Expand Down Expand Up @@ -438,9 +439,11 @@ static void _vec3ToHex2d(const Vec3d *p, int res, int *face, Vec2d *v) {

// we now have (r, theta) in hex2d with theta ccw from x-axes

// convert to local x,y
v->x = r * cos(theta);
v->y = r * sin(theta);
// convert to local x,y (both the sine and cosine of theta are needed)
double sinTheta, cosTheta;
_sincos(theta, &sinTheta, &cosTheta);
v->x = r * cosTheta;
v->y = r * sinTheta;
}

/**
Expand Down Expand Up @@ -493,9 +496,15 @@ static void _hex2dToVec3(const Vec2d *v, int face, int res, int substrate,
Vec3d northDir, eastDir;
_vec3TangentBasis(faceCenterPoint[face], &northDir, &eastDir);

Vec3d dir = vec3LinComb(cos(theta), northDir, sin(theta), eastDir);
// Both the sine and cosine of theta and of r are needed, so compute each
// pair together instead of with four separate calls.
double sinTheta, cosTheta, sinR, cosR;
_sincos(theta, &sinTheta, &cosTheta);
_sincos(r, &sinR, &cosR);

*v3 = vec3LinComb(cos(r), faceCenterPoint[face], sin(r), dir);
Vec3d dir = vec3LinComb(cosTheta, northDir, sinTheta, eastDir);

*v3 = vec3LinComb(cosR, faceCenterPoint[face], sinR, dir);
vec3Normalize(v3);
}

Expand Down