Comments (5)
Further experimentation shows that the above doesn't account for the differing order of vertices and edges. To solve this, I believe it's possible to just get the starting vertex of the next edge clockwise around the cell.
The below code seems to work fine at multiple resolutions from 0 to 7 in my application; I'll spin up proper tests and a previous-edge function as well.
static const Direction nextEdgeClockwiseDirectionsHex[8] = {
// Direction 0, center
CENTER_DIGIT,
// Direction 1, k-axes direction
JK_AXES_DIGIT, // K_AXES_DIGIT -> JK_AXES_DIGIT,
// Direction 2, j-axes direction
IJ_AXES_DIGIT, // J_AXES_DIGIT -> IJ_AXES_DIGIT
// Direction 3, j == k direction
J_AXES_DIGIT, // JK_AXES_DIGIT -> J_AXES_DIGIT
// Direction 4, i-axes direction
IK_AXES_DIGIT, // I_AXES_DIGIT -> IK_AXES_DIGIT
// Direction 5, i == k direction
K_AXES_DIGIT, // IK_AXES_DIGIT -> K_AXES_DIGIT
// Direction 6, i == j direction
I_AXES_DIGIT, // IJ_AXES_DIGIT -> I_AXES_DIGIT
// Invalid digit (7)
INVALID_DIGIT // INVALID_DIGIT -> INVALID_DIGIT
};
static const Direction nextEdgeClockwiseDirectionsPent[8] = {
// Direction 0, center
CENTER_DIGIT,
// Direction 1, k-axes direction
IK_AXES_DIGIT, // K_AXES_DIGIT -> IK_AXES_DIGIT
// Direction 2, j-axes direction
K_AXES_DIGIT, // J_AXES_DIGIT -> K_AXES_DIGIT
// Direction 3, j == k direction
I_AXES_DIGIT, // JK_AXES_DIGIT -> I_AXES_DIGIT
// Direction 4, i-axes direction
J_AXES_DIGIT, // I_AXES_DIGIT -> J_AXES_DIGIT
// Direction 5, i == k direction
JK_AXES_DIGIT, // IK_AXES_DIGIT -> JK_AXES_DIGIT
// Direction 6, i == j direction
INVALID_DIGIT, // IJ_AXES_DIGIT (invalid for pentagons) -> INVALID_DIGIT
// Invalid digit (7)
INVALID_DIGIT // INVALID_DIGIT -> INVALID_DIGIT
};
// ...
/**
* Returns the next edge in the clockwise order around the origin cell
* @param edge The directed edge H3Index
* @param nextClockwiseEdge The next clockwise edge output
*/
H3Error H3_EXPORT(directedEdgeGetNextClockwise)(H3Index edge, H3Index* nextClockwiseEdge) {
Direction direction = H3_GET_RESERVED_BITS(edge);
if (direction == CENTER_DIGIT || direction == INVALID_DIGIT) {
return E_DIR_EDGE_INVALID;
}
H3Index origin;
H3Error originResult = H3_EXPORT(getDirectedEdgeOrigin)(edge, &origin);
if (originResult) {
return originResult;
}
*nextClockwiseEdge = edge;
int isPent = H3_EXPORT(isPentagon)(origin);
if (isPent) {
Direction nextDirection = nextEdgeClockwiseDirectionsPent[direction];
H3_SET_RESERVED_BITS(*nextClockwiseEdge, nextDirection);
} else {
Direction nextDirection = nextEdgeClockwiseDirectionsHex[direction];
H3_SET_RESERVED_BITS(*nextClockwiseEdge, nextDirection);
}
return E_SUCCESS;
}
/**
* Provides the vertices at either end of the directed edge.
* @param edge The directed edge H3Index
* @param vStart The starting vertex H3Index
* @param vEnd The starting vertex H3Index
*/
H3Error H3_EXPORT(directedEdgeToVertices)(H3Index edge, H3Index* vStart, H3Index* vEnd) {
// Get the origin and neighbor direction from the edge
Direction direction = H3_GET_RESERVED_BITS(edge);
H3Index origin;
H3Error originResult = H3_EXPORT(getDirectedEdgeOrigin)(edge, &origin);
if (originResult) {
return originResult;
}
// Get the start vertex for the edge
int startVertex = vertexNumForDirection(origin, direction);
if (startVertex == INVALID_VERTEX_NUM) {
// This is not actually an edge (i.e. no valid direction),
// so return no vertices.
return E_DIR_EDGE_INVALID;
}
H3Error firstVertexErr = H3_EXPORT(cellToVertex)(origin, startVertex, vStart);
if (firstVertexErr) {
return firstVertexErr;
}
// Handle the end vertex for the edge
int isPent = H3_EXPORT(isPentagon)(origin);
int nextDirection;
if (isPent) {
nextDirection = nextEdgeClockwiseDirectionsPent[direction];
} else {
nextDirection = nextEdgeClockwiseDirectionsHex[direction];
}
int endVertex = vertexNumForDirection(origin, nextDirection);
H3Error secondVertexErr = H3_EXPORT(cellToVertex)(origin, endVertex, vEnd);
if (secondVertexErr) {
return secondVertexErr;
}
return E_SUCCESS;
}
from h3.
If I'm understanding correctly, this is already implemented as directedEdgeToBoundary
. Is there something that function doesn't provide that you need for your use case?
from h3.
My goal is to draw the boundaries between cells that don't share a value in the dataset
Another option here is to use cellsToMultiPolygon
, which will draw a single polygon for multiple cells. You'd need to cluster your cells by shared value, then send each cluster to cellsToMultiPolygon
to get the appropriate outline. This is likely easier than dealing with edges directly.
from h3.
Neither of the existing functions you mention really get at what I need, or would require significant additional processing to achieve the result I'm looking for.
Both functions mentioned give me, ultimately, the boundary around a group of cells, where the only information on what category adjacent cells belong to is "is this is in the provided set or not?" What it doesn't give me is the set of boundary edges or vertices between cells with different values in the provided set, where I don't care about the edges between cells in the provided set and outside.
Consider the following diagram:
Here I'm only interested in retrieving the purple edges. This is already doable by iterating over the provided set of cells and retaining only those edges that are both:
- Between cells that are both in the set
- Between cells of different values
Turning this into a rendering solution is where the problem comes in. The size of the dataset means that I have an interest in rendering these borders with as few vertices in the boundary as possible. directedEdgeToBoundary
or cellsToMultipolgyon
means that to filter out the edges not in purple, I'll need to potentially iterate over a large number of points in the result of the function that will then need to be discarded.
Furthermore, filtering out coincident points on the purple edges will mean two floating-point comparisons per vertex, instead of a single equality check if I'm able to get vertices associated with each edge directly, impacting performance.
The second problem comes with large datasets. I can't fit in memory an array with all the cells in a particular set - think of binning the world by nations at resolution 7+ or so. What I can do is split the entire world up into chunks that I know do fit in memory (say, children of cells at resolution 2) and then compute the interior (purple) borders per chunk.
Testing this approach with country data has shown that it's viable - when rendering a slice of the world at resolution 7, I'm able to pull only those cells in resolution 2 within view and then use this chunk-wise method to compute borders.
I've actually achieved what I set out to do using the code from my last post, and am still preparing the tests necessary for a proper pull request. I believe there's probably value in users being able to associate vertices with edge data anyway, even beyond my admittedly niche use case. We can associated edges with cells, and cells with vertices, but unless I'm mistaken there's no way to associate edges with vertices directly.
from h3.
Ok, I think I understand now. I apologize, I skimmed over this at first and didn't realize you were dealing directly with vertex-mode vertexes instead of lat/lng vertexes. I'm still not 100% sure I understand the use case, which I still suspect could be solved as efficiently without the new method, but I can definitely see that directedEdgeToVertexes
is something we'd want to add (I think it was originally planned but we never added it in after adding vertex mode), and we'd be happy to accept a PR. I have a few notes on the code you've posted above, but it would be easier to add them in code review.
from h3.
Related Issues (20)
- Replace empty function parameters with `void` HOT 1
- cell_to_child_pos() version 4 of the Python API client HOT 3
- polygonToCells: validity of polygons HOT 3
- Missing library stubs MYPY HOT 2
- polygonToCells not returning all H3Cells for the bounding box containing both USA and Russia HOT 1
- Confirmation of grid algorithm HOT 3
- cellToChildren error HOT 2
- Expose cellToChildrenSize in bindings HOT 1
- Getting unexpected results when converting coordinates in either direction HOT 4
- Meta: blog post has broken images HOT 5
- API | distance between h3s challenging to work around HOT 5
- Example H3 data sets HOT 3
- Completely cover a polygon with H3 cells using H3 extension for PostGIS
- Hi
- H3 Bug - Easily Reproducible HOT 1
- cellToVertex result seems to be incorrect? HOT 3
- Issue with H3: Uberβs Hexagonal Hierarchical Spatial Index HOT 2
- can't use the h3 gem in ruby using windows HOT 2
- FP exception handler triggered on both x86 and aarch64 HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from h3.