osg::Node* makeLabelNode(const FilterContext& context, const Feature* feature, const std::string& value, const TextSymbol* text, NumericExpression& priorityExpr ) { LabelNode* labelNode = new LabelNode( context.getSession()->getMapInfo().getProfile()->getSRS(), GeoPoint(feature->getSRS(), feature->getGeometry()->getBounds().center()), value, text ); if ( text->priority().isSet() ) { AnnotationData* data = new AnnotationData(); data->setPriority( feature->eval(priorityExpr, &context) ); labelNode->setAnnotationData( data ); } return labelNode; }
void GeodeticGraticule::initLabelPool(CameraData& cdata) { const osgEarth::SpatialReference* srs = osgEarth::SpatialReference::create("wgs84"); Style style; TextSymbol* text = style.getOrCreateSymbol<TextSymbol>(); text->alignment() = TextSymbol::ALIGN_CENTER_CENTER; text->fill()->color() = options().labelColor().get(); AltitudeSymbol* alt = style.getOrCreateSymbol<AltitudeSymbol>(); alt->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; unsigned int labelPoolSize = 8 * options().gridLines().get(); for (unsigned int i = 0; i < labelPoolSize; i++) { GeoPoint pt(srs, 0,0,0); LabelNode* label = new LabelNode(_mapNode.get(), pt, "0,0"); label->setDynamic(true); label->setStyle(style); cdata._labelPool.push_back(label); } }
bool GraticuleLabelingEngine::cullTraverse(osgUtil::CullVisitor& nv, CameraData& data) { osg::Camera* cam = nv.getCurrentCamera(); // Don't draw the labels if we are too far from North-Up: double heading = getCameraHeading(cam->getViewMatrix()); if (osg::RadiansToDegrees(fabs(heading)) > 7.0) return false; // Initialize the label pool for this camera if we have not done so: if (data.xLabels.empty()) { for (unsigned i = 0; i < MAX_LABELS; ++i) { LabelNode* label = new LabelNode(); label->setDynamic(true); label->setStyle(_xLabelStyle); label->setHorizonCulling(false); label->setOcclusionCulling(false); data.xLabels.push_back(label); } for (unsigned i = 0; i < MAX_LABELS; ++i) { LabelNode* label = new LabelNode(); label->setDynamic(true); label->setStyle(_yLabelStyle); label->setHorizonCulling(false); label->setOcclusionCulling(false); data.yLabels.push_back(label); } } // Start out with all labels off. We will then turn back on the ones we use: for (unsigned i = 0; i < MAX_LABELS; ++i) { data.xLabels[i]->setNodeMask(0); data.yLabels[i]->setNodeMask(0); } // Intersect the corners of the view frustum with the ellipsoid. // This will yield the approximate geo-extent of the view. // TODO: graduate this to the core if generally useful - could be helpful // for displaying the extent of the current view. // Calculate the "clip to world" matrix = MVPinv. osg::Matrix MVP = (*nv.getModelViewMatrix()) * cam->getProjectionMatrix(); osg::Matrix MVPinv; MVPinv.invert(MVP); EllipsoidIntersector ellipsoid(_srs->getEllipsoid()); // For each corner, transform the clip coordinates at the near and far // planes into world space and intersect that line with the ellipsoid: osg::Vec3d p0, p1; // find the lower-left corner of the frustum: osg::Vec3d LL_world; p0 = osg::Vec3d(-1, -1, -1) * MVPinv; p1 = osg::Vec3d(-1, -1, +1) * MVPinv; bool LL_ok = ellipsoid.intersectLine(p0, p1, LL_world); if (!LL_ok) return false; // find the upper-left corner of the frustum: osg::Vec3d UL_world; p0 = osg::Vec3d(-1, +1, -1) * MVPinv; p1 = osg::Vec3d(-1, +1, +1) * MVPinv; bool UL_ok = ellipsoid.intersectLine(p0, p1, UL_world); if (!UL_ok) return false; // find the lower-right corner of the frustum: osg::Vec3d LR_world; p0 = osg::Vec3d(+1, -1, -1) * MVPinv; p1 = osg::Vec3d(+1, -1, +1) * MVPinv; bool LR_ok = ellipsoid.intersectLine(p0, p1, LR_world); if (!LR_ok) return false; // Use this for clamping geopoints to the edges of the frustum: ClipSpace window(MVP, MVPinv); return updateLabels(LL_world, UL_world, LR_world, window, data); }
void GeodeticGraticule::updateLabels() { const osgEarth::SpatialReference* srs = osgEarth::SpatialReference::create("wgs84"); Threading::ScopedMutexLock lock(_cameraDataMapMutex); for (CameraDataMap::iterator i = _cameraDataMap.begin(); i != _cameraDataMap.end(); ++i) { CameraData& cdata = i->second; std::vector< GeoExtent > extents; if (cdata._viewExtent.crossesAntimeridian()) { GeoExtent first, second; cdata._viewExtent.splitAcrossAntimeridian(first, second); extents.push_back(first); extents.push_back(second); } else { extents.push_back( cdata._viewExtent ); } double resDegrees = cdata._resolution * 180.0; // We want half the resolution so the labels don't appear as often as the grid lines resDegrees *= 2.0; // Hide all the labels for (unsigned int i = 0; i < cdata._labelPool.size(); i++) { cdata._labelPool[i]->setNodeMask(0); } // Approximate offset in degrees double degOffset = cdata._metersPerPixel / 111000.0; unsigned int labelIndex = 0; bool done = false; for (unsigned int extentIndex = 0; extentIndex < extents.size() && !done; extentIndex++) { GeoExtent extent = extents[extentIndex]; int minLonIndex = floor(((extent.xMin() + 180.0)/resDegrees)); int maxLonIndex = ceil(((extent.xMax() + 180.0)/resDegrees)); int minLatIndex = floor(((extent.yMin() + 90)/resDegrees)); int maxLatIndex = ceil(((extent.yMax() + 90)/resDegrees)); // Generate horizontal labels for (int i = minLonIndex; i <= maxLonIndex && !done; i++) { GeoPoint point(srs, -180.0 + (double)i * resDegrees, cdata._lat + (_centerOffset.y() * degOffset), 0, ALTMODE_ABSOLUTE); LabelNode* label = cdata._labelPool[labelIndex++].get(); label->setNodeMask(~0u); label->setPosition(point); std::string text = getText( point, false); label->setText( text ); if (labelIndex == cdata._labelPool.size() - 1) { done = true; } } // Generate the vertical labels for (int i = minLatIndex; i <= maxLatIndex && !done; i++) { GeoPoint point(srs, cdata._lon + (_centerOffset.x() * degOffset), -90.0 + (double)i * resDegrees, 0, ALTMODE_ABSOLUTE); // Skip drawing labels at the poles if (osg::equivalent(osg::absolute( point.y()), 90.0, 0.1)) { continue; } LabelNode* label = cdata._labelPool[labelIndex++].get(); label->setNodeMask(~0u); label->setPosition(point); std::string text = getText( point, true); label->setText( text ); if (labelIndex == cdata._labelPool.size() - 1) { done = true; } } } } }