diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6f9a44 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/settings.json diff --git a/blog/assets/osgEarth六边形网格/2dmap.earth b/blog/assets/osgEarth六边形网格/2dmap.earth new file mode 100644 index 0000000..accf7f9 --- /dev/null +++ b/blog/assets/osgEarth六边形网格/2dmap.earth @@ -0,0 +1,14 @@ + + + + + + + spherical-mercator + + + + E:/GISData/Imagery/tms.xml + + + diff --git a/blog/assets/osgEarth六边形网格/image.png b/blog/assets/osgEarth六边形网格/image.png new file mode 100644 index 0000000..97f7588 Binary files /dev/null and b/blog/assets/osgEarth六边形网格/image.png differ diff --git a/blog/osgEarth六边形网格.md b/blog/osgEarth六边形网格.md new file mode 100644 index 0000000..90a6f85 --- /dev/null +++ b/blog/osgEarth六边形网格.md @@ -0,0 +1,174 @@ +# osgEarth构建六边形网格兵棋地图示例 + +  在osgEarth中添加了osg::Geode,绘制蜂窝状六边形网格效果,包括墨卡托平面地图,地理坐标平面地图,三维地球等多种模式 +![alt text](assets/osgEarth六边形网格/image.png) +```c++ +// 函数:创建六边形蜂窝网格线,三维地球 +osg::ref_ptr createHexagonWireframe(const osgEarth::GeoExtent& extent, float radius, int rows, int cols) { + osg::ref_ptr geometry = new osg::Geometry; + + osg::ref_ptr 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 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 stateSet = geometry->getOrCreateStateSet(); + osg::ref_ptr lineWidth = new osg::LineWidth(1.0f); // 设置线宽为 1.0 + stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON); + + return geometry; +} + + +// 函数:创建六边形蜂窝网格线,平面地图 +osg::ref_ptr createHexagonWireframe(double startX,double startY, float radius, int rows, int cols) { + osg::ref_ptr geometry = new osg::Geometry; + + osg::ref_ptr 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 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 stateSet = geometry->getOrCreateStateSet(); + osg::ref_ptr 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 + * ... \ No newline at end of file