测量工具主要是用于测量地球上两点之间的表面距离,空间距离,表面积可空间面积,以及两点之间的可视等。
表面距离测量:
核心代码:
bool GeoGlobe::DistanceMeasureHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
if (_Finished)
return false;
osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButton() == _mouseButton)
{
_mouseDown = true;
_mouseDownX = ea.getX();
_mouseDownY = ea.getY();
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == _mouseButton)
{
float eps = 1.0f;
_mouseDown = false;
if (osg::equivalent(ea.getX(), _mouseDownX, eps) && osg::equivalent(ea.getY(), _mouseDownY, eps))
{
double lon, lat;
if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat))
{
if (!_gotFirstLocation)
{
_Finished = false;
// clear();
_gotFirstLocation = true;
_feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );
}
else
{
if (_lastPointTemporary)
{
_feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 );
_lastPointTemporary = false;
}
else
{
_feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );
}
_start = GeoPoint(getMapNode()->getMapSRS(), lon, lat, ALTMODE_ABSOLUTE);
_featureNode->init();
if (_geoInterpolation == GEOINTERP_GREAT_CIRCLE)
{
distance = GeoMath::distance(_feature->getGeometry()->asVector());
}
for (MeasureToolEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i)
{
i->get()->onDistanceChanged(this, distance);
}
std::ostringstream s1;
std::ostringstream osm;
osm.precision(2); // 浮点数转换限制
osm.setf(std::ios::fixed); // 将浮点数的位数限定为小数点之后的位数
if (distance > 1000)
{
osm << distance / 1e3;
s1 << osm.str() << "km" << "\n";
}
else
{
osm << distance;
s1 << osm.str() << "m" << "\n";
}
std::string na = s1.str();
m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->size() = 18.0f;
m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->fill()->color() = Color::White;
m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->font() = "msyh.ttc";
m_SymStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
m_ptrLabelNode = new GeoGlobe::Annotation::PlaceNode(_start, na, m_SymStyle);
m_ptrLabelNode->setDynamic(true);
m_ptrLabelNode->setCullingActive(true);
m_ptrGroup->addChild(m_ptrLabelNode);
if (_Finished || !_isPath) {
_gotFirstLocation = false;
}
fireDistanceChanged();
aa.requestRedraw();
}
}
}
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK) {
if (_gotFirstLocation)
{
_Finished = true;
aa.requestRedraw();
return true;
}
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
{
if (_gotFirstLocation)
{
double lon, lat;
if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat))
{
if (!_lastPointTemporary)
{
_feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) );
_lastPointTemporary = true;
}
else
{
_feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 );
}
_featureNode->init();
fireDistanceChanged();
aa.requestRedraw();
}
}
}
return false;
}
空间距离测量:
核心代码:
bool Distance3DTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (m_bIsFinished)
return false;
osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
int size;
std::ostringstream s1;
osgEarth::GeoPoint mapPoint;
if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton()== osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
if (m_isDrag)
{
m_isDrag = false;
return true;
}
if (!pick(view, ea, world))
{
return false;
m_isDrag = false;
}
//线的起点
if (m_bIsFirst)
{
m_PickPoints.push_back(world);
size = m_PickPoints.size();
RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);
displayGroup->addChild(RubberBand);
std::string strText = "start";
mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));
m_isDrag = false;
m_bIsFirst = false;
return false;
}
else
{
m_PickPoints.push_back(world);
size = m_PickPoints.size();
//画线,使用相对位置,再偏移至绝对位置,数值小,线不抖
osg::Node* ptrLine3D = createLine(m_PickPoints[size - 2], m_PickPoints[size - 1], m_PickPoints[0]);
displayGroup->addChild(ptrLine3D);
//计算三维距离
m_Distance3D += (m_PickPoints[size - 2]- m_PickPoints[size - 1]).length();
//添加标签,设置有效位
s1 << setiosflags(ios::fixed) << setprecision(2) << m_Distance3D << "m" << "\n";
std::string strText = s1.str();
mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));
//删除橡皮筋对象
displayGroup->removeChild(RubberBand);
m_isDrag = false;
}
m_isDrag = false;
}
else if(ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
{
if (!m_bIsFirst)
{
if (!pick(view, ea, world))
return false;
displayGroup->removeChild(RubberBand);
RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);
displayGroup->addChild(RubberBand);
}
}
else if(ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK)
{
m_isDrag = false;
m_bIsFinished = true;
displayGroup->removeChild(RubberBand);
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
{
m_isDrag = true;
}
return false;
}
表面面积:
核心代码:
bool AreaTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object* object, osg::NodeVisitor* visitor)
{
if (m_bFinished)
return false;
osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
if (m_bIsDrag)
{
m_bIsDrag = false;
return false;
}
osg::Vec3d vecWord;
m_ptrMapNode->getTerrain()->getWorldCoordsUnderMouse(aa.asView(), ea.getX(), ea.getY(), vecWord);
m_vecWorld.push_back(vecWord);
osgEarth::GeoPoint mapPoint;
mapPoint.fromWorld(m_ptrMapNode->getMapSRS(), vecWord);
m_vecWgs84.push_back(mapPoint.vec3d());
if (mapPoint.x() < -180 || mapPoint.x() > 180 || mapPoint.y() < -90 || mapPoint.y() > 90 || fabs(mapPoint.z()) > 1000000)
return false;
osgEarth::Features::Feature* ptrFeature = m_ptrFeartureNode->getFeature();
ptrFeature->getGeometry()->push_back(mapPoint.vec3d());
m_ptrFeartureNode->dirty();
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
m_bFinished = true;
Calcuate();
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
{
osgEarth::Features::Feature* ptrFeature = m_ptrFeartureNode->getFeature();
if (ptrFeature->getGeometry()->size() == 0)
return false;
osg::Vec3d vecWord;
m_ptrMapNode->getTerrain()->getWorldCoordsUnderMouse(aa.asView(), ea.getX(), ea.getY(), vecWord);
osgEarth::GeoPoint mapPoint;
mapPoint.fromWorld(m_ptrMapNode->getMapSRS(), vecWord);
if (mapPoint.x() < -180 || mapPoint.x() > 180 || mapPoint.y() < -90 || mapPoint.y() > 90 || fabs(mapPoint.z()) > 1000000)
return false;
if (ptrFeature->getGeometry()->size() == 1)
ptrFeature->getGeometry()->push_back(mapPoint.vec3d());
else
ptrFeature->getGeometry()->back() = mapPoint.vec3d();
m_ptrFeartureNode->dirty();
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
{
m_bIsDrag = true;
}
return false;
}
空间面积:
核心代码:
bool Area3DTrakerElement::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (m_bIsFinished)
return false;
osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
osg::Group* root = static_cast<osg::Group*>(view->getSceneData());
int size;
std::ostringstream s1;
osgEarth::GeoPoint mapPoint;
if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
if (m_isDrag)
{
m_isDrag = false;
return true;
}
//线的起点
if (m_bIsFirst)
{
if (!pick(view, ea, world))
return false;
m_PickPoints.push_back(world);
size = m_PickPoints.size();
/*
std::string strText = CodeHelp::String_To_UTF8("起点");
mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(), world);
displayGroup->addChild(CreateLabel(m_mapNode, mapPoint, strText));
*/
m_bIsFirst = false;
m_isDrag = false;
return false;
}
else
{
m_PickPoints.push_back(world);
size = m_PickPoints.size();
//画线,使用相对位置,再偏移至绝对位置,数值小,线不抖
osg::Node* ptrLine3D = createLine(m_PickPoints[size - 2], m_PickPoints[size - 1], m_PickPoints[0]);
displayGroup->addChild(ptrLine3D);
//删除橡皮筋对象
displayGroup->removeChild(RubberBand);
displayGroup->removeChild(m_closeRubberBand);
}
m_isDrag = false;
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
{
if (!m_bIsFirst)
{
if (!pick(view, ea, world))
return false;
displayGroup->removeChild(RubberBand);
displayGroup->removeChild(m_closeRubberBand);
RubberBand = createLine(m_PickPoints[m_PickPoints.size() - 1], world, m_PickPoints[0]);
m_closeRubberBand = createLine(m_PickPoints[0], world, m_PickPoints[0]);
displayGroup->addChild(RubberBand);
displayGroup->addChild(m_closeRubberBand);
}
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK)
{
//面积闭合
osg::Node* ptrLine3D = createLine(m_PickPoints[0], m_PickPoints[m_PickPoints.size() - 1], m_PickPoints[0]);
displayGroup->addChild(ptrLine3D);
m_isDrag = false;
//计算三维距离
//1 三角形剖分
if (!AreaMeasurement(m_PickPoints, m_Area3D))
return false;
2 平面拟合
//double Area;
//calArea3D(m_PickPoints,Area);
//3 直接去掉Z值
std::vector<osg::Vec2d> Points;
double area;
//添加标签,设置有效位
if (m_Area3D > 100000)
{
double showValue = m_Area3D / 1000000;
s1 << setiosflags(ios::fixed) << setprecision(2) << showValue << "km^2" << "\n";
}
else
s1 << setiosflags(ios::fixed) << setprecision(2) << m_Area3D << "m^2" << "\n";
osg::Vec3d labelPos;
for (int i = 0;i<m_PickPoints.size();i++)
{
labelPos += m_PickPoints[i];
}
labelPos = labelPos / m_PickPoints.size();
mapPoint.fromWorld(m_mapNode->getTerrain()->getSRS(),labelPos);
std::string strText = s1.str();
osgEarth::Symbology::Style style;
style.getOrCreate<osgEarth::Symbology::TextSymbol>()->size() = 18.0f;
style.getOrCreate<osgEarth::Symbology::TextSymbol>()->fill()->color() = osgEarth::Symbology::Color::White;
style.getOrCreate<osgEarth::Symbology::TextSymbol>()->font() = "msyh.ttc";
style.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
osg::ref_ptr<GeoGlobe::PlaceName::GeoBillboard> billboard = new GeoGlobe::PlaceName::GeoBillboard(osgEarth::GeoPoint(m_mapNode->getMapSRS(), mapPoint), strText, style, true);
billboard->setCullingActive(false);
displayGroup->addChild(/*CreateLabel(m_mapNode, mapPoint, strText)*/billboard);
m_bIsFinished = true;
displayGroup->removeChild(RubberBand);
displayGroup->removeChild(m_closeRubberBand);
}
else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
{
m_isDrag = true;
}
return false;
}