添加osgEarth创建六边形网格文章
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.vscode/settings.json
|
||||||
14
blog/assets/osgEarth六边形网格/2dmap.earth
Normal file
14
blog/assets/osgEarth六边形网格/2dmap.earth
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<map name = "ddmap" type="projected" version="2">
|
||||||
|
<options>
|
||||||
|
<terrain driver = "rex" lighting = "true" skirt_ratio="0.05" min_tile_range_factor = "6" first_lod = "0" blending = "false" color = "#ffffffff" tile_size = "17" normalize_edges = "true" compress_normal_maps = "false" normal_maps = "true" min_expiry_frames = "0" min_expiry_time = "0"/>
|
||||||
|
<!-- <profile>plate-carre</profile> -->
|
||||||
|
<profile>spherical-mercator</profile>
|
||||||
|
</options>
|
||||||
|
|
||||||
|
<image name="world" driver="tms" opacity = "1.0" format="png">
|
||||||
|
<url>E:/GISData/Imagery/tms.xml</url>
|
||||||
|
</image>
|
||||||
|
|
||||||
|
</map>
|
||||||
BIN
blog/assets/osgEarth六边形网格/image.png
Normal file
BIN
blog/assets/osgEarth六边形网格/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 535 KiB |
174
blog/osgEarth六边形网格.md
Normal file
174
blog/osgEarth六边形网格.md
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
# osgEarth构建六边形网格兵棋地图示例
|
||||||
|
|
||||||
|
在osgEarth中添加了osg::Geode,绘制蜂窝状六边形网格效果,包括墨卡托平面地图,地理坐标平面地图,三维地球等多种模式
|
||||||
|

|
||||||
|
```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
|
||||||
|
* ...
|
||||||
Reference in New Issue
Block a user