Files
wiki/blog/osgEarth六边形网格.md

174 lines
5.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# osgEarth构建六边形网格兵棋地图示例
  在osgEarth中添加了osg::Geode绘制蜂窝状六边形网格效果包括墨卡托平面地图地理坐标平面地图三维地球等多种模式
![alt text](assets/osgEarth六边形网格/image.png)
```c++
// 函数:创建六边形蜂窝网格线,三维地球
osg::ref_ptr<osg::Geometry> createHexagonWireframe(const osgEarth::GeoExtent& extent, float radius, int rows, int cols) {
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
auto fromSRS = osgEarth::SpatialReference::get("wgs84");
auto srs = extent.getSRS();
// 计算每个六边形中心点的地理坐标
float height = std::sqrt(3.0f) * radius;
float lonDelta = radius;// extent.width() / cols;
float latDelta = radius;// extent.height() / rows;
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
float lonDelta = col * 1.5f * radius;
float latDelta = row * height;
if (col % 2 == 1)
latDelta += height / 2.0f;
float lon = 108.0 + lonDelta;
float lat = 35.0 + latDelta;
osg::Vec3d centerGeo(lon, lat, 3000.0);
// 计算六边形的顶点
for (int i = 0; i < 6; ++i)
{
float angle = osg::PI * 2.0f * float(i) / 6.0f;
float x = radius * std::cos(angle);
float y = radius * std::sin(angle);
osg::Vec3d vertexXYZ;
osgEarth::GeoPoint pppp(fromSRS, osg::Vec3d(lon + x, lat + y, 1.0));
pppp.transformInPlace(srs);
pppp.toWorld(vertexXYZ);
//vertices->push_back(centerXYZ + vertexXYZ - centerGeo);
vertices->push_back(vertexXYZ);
}
}
}
geometry->setVertexArray(vertices);
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_LINES);
int numHexagons = rows * cols;
for (int i = 0; i < numHexagons; ++i) {
int offset = i * 6;
for (int j = 0; j < 6; ++j) {
indices->push_back(offset + j);
indices->push_back(offset + (j + 1) % 6);
}
}
geometry->addPrimitiveSet(indices);
// 启用 VBO
geometry->setUseVertexBufferObjects(true);
// 设置线宽
osg::ref_ptr<osg::StateSet> stateSet = geometry->getOrCreateStateSet();
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(1.0f); // 设置线宽为 1.0
stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return geometry;
}
// 函数:创建六边形蜂窝网格线,平面地图
osg::ref_ptr<osg::Geometry> createHexagonWireframe(double startX,double startY, float radius, int rows, int cols) {
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
// 计算每个六边形中心点的地理坐标
float height = std::sqrt(3.0f) * radius;
for (int row = 0; row < rows; ++row)
{
for (int col = 0; col < cols; ++col)
{
float xDelta = col * 1.5f * radius;
float yDelta = row * height;
if (col % 2 == 1)
yDelta += height / 2.0f;
float lon = startX + xDelta;
float lat = startY + yDelta;
// 计算六边形的顶点
for (int i = 0; i < 6; ++i)
{
float angle = osg::PI * 2.0f * float(i) / 6.0f;
float x = radius * std::cos(angle);
float y = radius * std::sin(angle);
//vertices->push_back(centerXYZ + vertexXYZ - centerGeo);
vertices->push_back(osg::Vec3d(lon + x, lat + y, 1.0));
}
}
}
geometry->setVertexArray(vertices);
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_LINES);
int numHexagons = rows * cols;
for (int i = 0; i < numHexagons; ++i) {
int offset = i * 6;
for (int j = 0; j < 6; ++j) {
indices->push_back(offset + j);
indices->push_back(offset + (j + 1) % 6);
}
}
geometry->addPrimitiveSet(indices);
// 启用 VBO
geometry->setUseVertexBufferObjects(true);
// 设置线宽
osg::ref_ptr<osg::StateSet> stateSet = geometry->getOrCreateStateSet();
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(1.0f); // 设置线宽为 1.0
stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return geometry;
}
int main(int argc, char* argv[])
{
auto ddMap = osgDB::readNodeFile("E:/GISData/Imagery/2dmap.earth");
auto mapNode = osgEarth::MapNode::findMapNode(ddMap);
osgEarth::GeoPoint start(osgEarth::SpatialReference::get("wgs84"), 108.0, 35.0);
start.transformInPlace(mapNode->getMapSRS());
auto hexagon222 = createHexagonWireframe(start.x(), start.y()
, 500, 100, 100);
hexagon222->getOrCreateStateSet()->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0.0, 1.0, false), osg::StateAttribute::ON);
osgEarth::GLUtils::setLighting(hexagon222->getOrCreateStateSet(), osg::StateAttribute::OFF);
mapNode->addChild(hexagon222);
auto m = new osgEarth::EarthManipulator;
osgViewer::Viewer viewer;
viewer.setSceneData(ddMap);
viewer.setCameraManipulator(m);
viewer.getCamera()->addCullCallback(new osgEarth::AutoClipPlaneCullCallback(mapNode));
viewer.realize();
m->setViewpoint(osgEarth::Viewpoint("", 108, 35, 0.0, 0.0, -89.9, 100000));
return viewer.run();
}
```
## 附件
[2dmap.earth](./assets/osgEarth六边形网格/2dmap.earth)
## 性能问题
* 考虑使用instanced drawing
* 使用kd-tree
* ...