LabelNode::LabelNode(MapNode* mapNode, const GeoPoint& position, const std::string& text, const TextSymbol* symbol ) : GeoPositionNode( mapNode, position ), _text ( text ) { Style style; style.add( const_cast<TextSymbol*>(symbol) ); init( style ); }
LabelNode::LabelNode(MapNode* mapNode, const GeoPoint& position, const std::string& text, const TextSymbol* symbol ) : GeoPositionNode( mapNode, position ), _text ( text ), _labelRotationRad ( 0. ), _followFixedCourse( false ) { Style style; style.add( const_cast<TextSymbol*>(symbol) ); init( style ); }
void KML_Placemark::build( xml_node<>* node, KMLContext& cx ) { Style masterStyle; std::string styleUrl = getValue(node, "styleurl"); if (!styleUrl.empty()) { // process a "stylesheet" style const Style* ref_style = cx._sheet->getStyle( styleUrl, false ); if (ref_style) { masterStyle = masterStyle.combineWith(*ref_style); } } xml_node<>* style = node->first_node("style", 0, false); if ( style ) { // process an "inline" style KML_Style kmlStyle; kmlStyle.scan(style, cx); masterStyle = masterStyle.combineWith(cx._activeStyle); } // parse the geometry. the placemark must have geometry to be valid. The // geometry parse may optionally specify an altitude mode as well. KML_Geometry geometry; geometry.build(node, cx, masterStyle); Geometry* allGeom = geometry._geom.get(); if ( allGeom ) { GeometryIterator giter( allGeom, false ); while( giter.hasMore() ) { Geometry* geom = giter.next(); Style style = masterStyle; AltitudeSymbol* alt = style.get<AltitudeSymbol>(); if ( geom && geom->getTotalPointCount() > 0 ) { // resolve the proper altitude mode for the anchor point AltitudeMode altMode = ALTMODE_RELATIVE; if (alt && !alt->clamping().isSetTo( alt->CLAMP_TO_TERRAIN ) && !alt->clamping().isSetTo( alt->CLAMP_RELATIVE_TO_TERRAIN ) ) { altMode = ALTMODE_ABSOLUTE; } GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode); bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON; bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET; // check for symbols. ModelSymbol* model = style.get<ModelSymbol>(); IconSymbol* icon = style.get<IconSymbol>(); TextSymbol* text = style.get<TextSymbol>(); // the annotation name: std::string name = getValue(node, "name"); AnnotationNode* featureNode = 0L; AnnotationNode* iconNode = 0L; AnnotationNode* modelNode = 0L; // one coordinate? It's a place marker or a label. if ( (model || icon || text) && geom->getTotalPointCount() == 1 ) { // load up the default icon if there we don't have one. if ( !model && !icon ) { icon = cx._options->defaultIconSymbol().get(); if ( icon ) style.add( icon ); } // if there's a model, render that - models do NOT get labels. if ( model ) { ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions ); node->setPosition( position ); // model scale: if ( cx._options->modelScale() != 1.0f ) { float s = *cx._options->modelScale(); node->setScale( osg::Vec3f(s,s,s) ); } // model local tangent plane rotation: if ( !cx._options->modelRotation()->zeroRotation() ) { node->setLocalRotation( *cx._options->modelRotation() ); } modelNode = node; } // is there a label? else if ( !name.empty() ) { if ( !text && cx._options->defaultTextSymbol().valid() ) { text = cx._options->defaultTextSymbol().get(); style.addSymbol( text ); } else { text = style.getOrCreate<TextSymbol>(); text->encoding() = TextSymbol::ENCODING_UTF8; } text->content()->setLiteral( name ); } // is there an icon? if ( icon ) { iconNode = new PlaceNode( cx._mapNode, position, style, cx._dbOptions ); } else if ( !model && text && !name.empty() ) { // note: models do not get labels. iconNode = new LabelNode( cx._mapNode, position, style ); } } // multiple coords? feature: if ( geom->getTotalPointCount() > 1 ) { ExtrusionSymbol* extruded = style.get<ExtrusionSymbol>(); // Remove symbols that we have already processed so the geometry // compiler doesn't get confused. if ( model ) style.removeSymbol( model ); if ( icon ) style.removeSymbol( icon ); if ( text ) style.removeSymbol( text ); Feature* feature = new Feature(geom, cx._srs.get(), style); featureNode = new FeatureNode( cx._mapNode, feature ); } // assemble the results: if ( (iconNode || modelNode) && featureNode ) { osg::Group* group = new osg::Group(); group->addChild( featureNode ); if ( iconNode ) group->addChild( iconNode ); if ( modelNode ) group->addChild( modelNode ); cx._groupStack.top()->addChild( group ); if ( iconNode && cx._options->declutter() == true ) { Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true ); } if ( iconNode ) KML_Feature::build( node, cx, iconNode ); if ( modelNode ) KML_Feature::build( node, cx, modelNode ); if ( featureNode ) KML_Feature::build( node, cx, featureNode ); } else { if ( iconNode ) { if ( cx._options->iconAndLabelGroup().valid() ) { cx._options->iconAndLabelGroup()->addChild( iconNode ); } else { cx._groupStack.top()->addChild( iconNode ); if ( cx._options->declutter() == true ) { Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true ); } } KML_Feature::build( node, cx, iconNode ); } if ( modelNode ) { cx._groupStack.top()->addChild( modelNode ); KML_Feature::build( node, cx, modelNode ); } if ( featureNode ) { cx._groupStack.top()->addChild( featureNode ); KML_Feature::build( node, cx, featureNode ); } } } } } }
osg::Node* MGRSGraticule::buildSQIDTiles( const std::string& gzd ) { const GeoExtent& extent = _gzd[gzd]; // parse the GZD into its components: unsigned zone; char letter; sscanf( gzd.c_str(), "%u%c", &zone, &letter ); TextSymbol* textSym = _options->secondaryStyle()->get<TextSymbol>(); if ( !textSym ) textSym = _options->primaryStyle()->getOrCreate<TextSymbol>(); AltitudeSymbol* alt = _options->secondaryStyle()->get<AltitudeSymbol>(); double h = 0.0; TextSymbolizer ts( textSym ); MGRSFormatter mgrs(MGRSFormatter::PRECISION_100000M); osg::Geode* textGeode = new osg::Geode(); textGeode->getOrCreateStateSet()->setRenderBinDetails( 9999, "DepthSortedBin" ); textGeode->getOrCreateStateSet()->setAttributeAndModes( _depthAttribute, 1 ); const SpatialReference* ecefSRS = extent.getSRS()->getECEF(); osg::Vec3d centerMap, centerECEF; extent.getCentroid(centerMap.x(), centerMap.y()); extent.getSRS()->transform(centerMap, ecefSRS, centerECEF); //extent.getSRS()->transformToECEF(centerMap, centerECEF); osg::Matrix local2world; ecefSRS->createLocalToWorld( centerECEF, local2world ); //= ECEF::createLocalToWorld(centerECEF); osg::Matrix world2local; world2local.invert(local2world); FeatureList features; std::vector<GeoExtent> sqidExtents; // UTM: if ( letter > 'B' && letter < 'Y' ) { // grab the SRS for the current UTM zone: // TODO: AL/AA designation?? const SpatialReference* utm = SpatialReference::create( Stringify() << "+proj=utm +zone=" << zone << " +north +units=m" ); // transform the four corners of the tile to UTM. osg::Vec3d gzdUtmSW, gzdUtmSE, gzdUtmNW, gzdUtmNE; extent.getSRS()->transform( osg::Vec3d(extent.xMin(),extent.yMin(),h), utm, gzdUtmSW ); extent.getSRS()->transform( osg::Vec3d(extent.xMin(),extent.yMax(),h), utm, gzdUtmNW ); extent.getSRS()->transform( osg::Vec3d(extent.xMax(),extent.yMin(),h), utm, gzdUtmSE ); extent.getSRS()->transform( osg::Vec3d(extent.xMax(),extent.yMax(),h), utm, gzdUtmNE ); // find the southern boundary of the first full SQID tile in the GZD tile. double southSQIDBoundary = gzdUtmSW.y(); //extentUTM.yMin(); double remainder = fmod( southSQIDBoundary, 100000.0 ); if ( remainder > 0.0 ) southSQIDBoundary += (100000.0 - remainder); // find the min/max X for this cell in UTM: double xmin = extent.yMin() >= 0.0 ? gzdUtmSW.x() : gzdUtmNW.x(); double xmax = extent.yMin() >= 0.0 ? gzdUtmSE.x() : gzdUtmNE.x(); // Record the UTM extent of each SQID cell in this tile. // Go from the south boundary northwards: for( double y = southSQIDBoundary; y < gzdUtmNW.y(); y += 100000.0 ) { // start at the central meridian (500K) and go west: for( double x = 500000.0; x > xmin; x -= 100000.0 ) { sqidExtents.push_back( GeoExtent(utm, x-100000.0, y, x, y+100000.0) ); } // then start at the central meridian and go east: for( double x = 500000.0; x < xmax; x += 100000.0 ) { sqidExtents.push_back( GeoExtent(utm, x, y, x+100000.0, y+100000.0) ); } } for( std::vector<GeoExtent>::iterator i = sqidExtents.begin(); i != sqidExtents.end(); ++i ) { GeoExtent utmEx = *i; // now, clamp each of the points in the UTM SQID extent to the map-space // boundaries of the GZD tile. (We only need to clamp in the X dimension, // Y geometry is allowed to overflow.) Also, skip NE, we don't need it. double r, xlimit; osg::Vec3d sw(utmEx.xMin(), utmEx.yMin(), 0); r = (sw.y()-gzdUtmSW.y())/(gzdUtmNW.y()-gzdUtmSW.y()); xlimit = gzdUtmSW.x() + r * (gzdUtmNW.x() - gzdUtmSW.x()); if ( sw.x() < xlimit ) sw.x() = xlimit; osg::Vec3d nw(utmEx.xMin(), utmEx.yMax(), 0); r = (nw.y()-gzdUtmSW.y())/(gzdUtmNW.y()-gzdUtmSW.y()); xlimit = gzdUtmSW.x() + r * (gzdUtmNW.x() - gzdUtmSW.x()); if ( nw.x() < xlimit ) nw.x() = xlimit; osg::Vec3d se(utmEx.xMax(), utmEx.yMin(), 0); r = (se.y()-gzdUtmSE.y())/(gzdUtmNE.y()-gzdUtmSE.y()); xlimit = gzdUtmSE.x() + r * (gzdUtmNE.x() - gzdUtmSE.x()); if ( se.x() > xlimit ) se.x() = xlimit; // at the northernmost GZD (lateral band X), clamp the northernmost SQIDs to the upper latitude. if ( letter == 'X' && nw.y() > gzdUtmNW.y() ) nw.y() = gzdUtmNW.y(); // need this in order to calculate the font size: double utmWidth = se.x() - sw.x(); // now transform the corner points back into the map SRS: utm->transform( sw, extent.getSRS(), sw ); utm->transform( nw, extent.getSRS(), nw ); utm->transform( se, extent.getSRS(), se ); // and draw valid sqid geometry. if ( sw.x() < se.x() ) { Feature* lat = new Feature(new LineString(2), extent.getSRS()); lat->geoInterp() = GEOINTERP_RHUMB_LINE; lat->getGeometry()->push_back( sw ); lat->getGeometry()->push_back( se ); features.push_back(lat); Feature* lon = new Feature(new LineString(2), extent.getSRS()); lon->geoInterp() = GEOINTERP_GREAT_CIRCLE; lon->getGeometry()->push_back( sw ); lon->getGeometry()->push_back( nw ); features.push_back(lon); // and the text label: osg::Vec3d sqidTextMap = (nw + se) * 0.5; sqidTextMap.z() += 1000.0; osg::Vec3d sqidTextECEF; extent.getSRS()->transform(sqidTextMap, ecefSRS, sqidTextECEF); //extent.getSRS()->transformToECEF(sqidTextMap, sqidTextECEF); osg::Vec3d sqidLocal; sqidLocal = sqidTextECEF * world2local; MGRSCoord mgrsCoord; if ( mgrs.transform( GeoPoint(extent.getSRS(),sqidTextMap,ALTMODE_ABSOLUTE), mgrsCoord) ) { textSym->size() = utmWidth/3.0; osgText::Text* d = ts.create( mgrsCoord.sqid ); osg::Matrixd textLocal2World; ecefSRS->createLocalToWorld( sqidTextECEF, textLocal2World ); d->setPosition( sqidLocal ); textGeode->addDrawable( d ); } } } } else if ( letter == 'A' || letter == 'B' ) { // SRS for south polar region UPS projection. This projection has (0,0) at the // south pole, with +X extending towards 90 degrees E longitude and +Y towards // 0 degrees longitude. const SpatialReference* ups = SpatialReference::create( "+proj=stere +lat_ts=-90 +lat_0=-90 +lon_0=0 +k_0=1 +x_0=0 +y_0=0"); osg::Vec3d gtemp; double r = GeoMath::distance(-osg::PI_2, 0.0, -1.3962634, 0.0); // -90 => -80 latitude double r2 = r*r; if ( letter == 'A' ) { for( double x = 0.0; x < 1200000.0; x += 100000.0 ) { double yminmax = sqrt( r2 - x*x ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(-x, -yminmax, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d(-x, yminmax, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double y = -1100000.0; y < 1200000.0; y += 100000.0 ) { double xmax = sqrt( r2 - y*y ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(-xmax, y, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d( 0, y, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double x = -1200000.0; x < 0.0; x += 100000.0 ) { for( double y = -1200000.0; y < 1200000.0; y += 100000.0 ) { osg::Vec3d sqidTextMap; ups->transform( osg::Vec3d(x+50000.0, y+50000.0, 0), extent.getSRS(), sqidTextMap); if ( sqidTextMap.y() < -80.0 ) { sqidTextMap.z() += 1000.0; osg::Vec3d sqidTextECEF; extent.getSRS()->transform(sqidTextMap, ecefSRS, sqidTextECEF); //extent.getSRS()->transformToECEF(sqidTextMap, sqidTextECEF); osg::Vec3d sqidLocal = sqidTextECEF * world2local; MGRSCoord mgrsCoord; if ( mgrs.transform( GeoPoint(extent.getSRS(),sqidTextMap,ALTMODE_ABSOLUTE), mgrsCoord) ) { textSym->size() = 33000.0; osgText::Text* d = ts.create( mgrsCoord.sqid ); osg::Matrixd textLocal2World; ecefSRS->createLocalToWorld( sqidTextECEF, textLocal2World ); d->setPosition( sqidLocal ); textGeode->addDrawable( d ); } } } } } else if ( letter == 'B' ) { for( double x = 100000.0; x < 1200000.0; x += 100000.0 ) { double yminmax = sqrt( r2 - x*x ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(x, -yminmax, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d(x, yminmax, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double y = -1100000.0; y < 1200000.0; y += 100000.0 ) { double xmax = sqrt( r2 - y*y ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d( 0, y, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d( xmax, y, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double x = 0.0; x < 1200000.0; x += 100000.0 ) { for( double y = -1200000.0; y < 1200000.0; y += 100000.0 ) { osg::Vec3d sqidTextMap; ups->transform( osg::Vec3d(x+50000.0, y+50000.0, 0), extent.getSRS(), sqidTextMap); if ( sqidTextMap.y() < -80.0 ) { sqidTextMap.z() += 1000.0; osg::Vec3d sqidTextECEF; extent.getSRS()->transform(sqidTextMap, ecefSRS, sqidTextECEF); //extent.getSRS()->transformToECEF(sqidTextMap, sqidTextECEF); osg::Vec3d sqidLocal = sqidTextECEF * world2local; MGRSCoord mgrsCoord; if ( mgrs.transform( GeoPoint(extent.getSRS(),sqidTextMap,ALTMODE_ABSOLUTE), mgrsCoord) ) { textSym->size() = 33000.0; osgText::Text* d = ts.create( mgrsCoord.sqid ); osg::Matrixd textLocal2World; ecefSRS->createLocalToWorld( sqidTextECEF, textLocal2World ); d->setPosition( sqidLocal ); textGeode->addDrawable( d ); } } } } } } else if ( letter == 'Y' || letter == 'Z' ) { // SRS for north polar region UPS projection. This projection has (0,0) at the // south pole, with +X extending towards 90 degrees E longitude and +Y towards // 180 degrees longitude. const SpatialReference* ups = SpatialReference::create( "+proj=stere +lat_ts=90 +lat_0=90 +lon_0=0 +k_0=1 +x_0=0 +y_0=0"); osg::Vec3d gtemp; double r = GeoMath::distance(osg::PI_2, 0.0, 1.46607657, 0.0); // 90 -> 84 latitude double r2 = r*r; if ( letter == 'Y' ) { for( double x = 0.0; x < 700000.0; x += 100000.0 ) { double yminmax = sqrt( r2 - x*x ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(-x, -yminmax, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d(-x, yminmax, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double y = -600000.0; y < 700000.0; y += 100000.0 ) { double xmax = sqrt( r2 - y*y ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(-xmax, y, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d( 0, y, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double x = -700000.0; x < 0.0; x += 100000.0 ) { for( double y = -700000.0; y < 700000.0; y += 100000.0 ) { osg::Vec3d sqidTextMap; ups->transform( osg::Vec3d(x+50000.0, y+50000.0, 0), extent.getSRS(), sqidTextMap); if ( sqidTextMap.y() > 84.0 ) { sqidTextMap.z() += 1000.0; osg::Vec3d sqidTextECEF; extent.getSRS()->transform(sqidTextMap, ecefSRS, sqidTextECEF); //extent.getSRS()->transformToECEF(sqidTextMap, sqidTextECEF); osg::Vec3d sqidLocal = sqidTextECEF * world2local; MGRSCoord mgrsCoord; if ( mgrs.transform( GeoPoint(extent.getSRS(),sqidTextMap,ALTMODE_ABSOLUTE), mgrsCoord) ) { textSym->size() = 33000.0; osgText::Text* d = ts.create( mgrsCoord.sqid ); osg::Matrixd textLocal2World; ecefSRS->createLocalToWorld( sqidTextECEF, textLocal2World ); d->setPosition( sqidLocal ); textGeode->addDrawable( d ); } } } } } else if ( letter == 'Z' ) { for( double x = 100000.0; x < 700000.0; x += 100000.0 ) { double yminmax = sqrt( r2 - x*x ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d(x, -yminmax, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d(x, yminmax, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double y = -600000.0; y < 700000.0; y += 100000.0 ) { double xmax = sqrt( r2 - y*y ); Feature* f = new Feature( new LineString(2), extent.getSRS() ); f->geoInterp() = GEOINTERP_GREAT_CIRCLE; osg::Vec3d p0, p1; ups->transform( osg::Vec3d( 0, y, 0), extent.getSRS(), p0 ); ups->transform( osg::Vec3d( xmax, y, 0), extent.getSRS(), p1 ); f->getGeometry()->push_back( p0 ); f->getGeometry()->push_back( p1 ); features.push_back( f ); } for( double x = 0.0; x < 700000.0; x += 100000.0 ) { for( double y = -700000.0; y < 700000.0; y += 100000.0 ) { osg::Vec3d sqidTextMap; ups->transform( osg::Vec3d(x+50000.0, y+50000.0, 0), extent.getSRS(), sqidTextMap); if ( sqidTextMap.y() > 84.0 ) { sqidTextMap.z() += 1000.0; osg::Vec3d sqidTextECEF; extent.getSRS()->transform(sqidTextMap, ecefSRS, sqidTextECEF); //extent.getSRS()->transformToECEF(sqidTextMap, sqidTextECEF); osg::Vec3d sqidLocal = sqidTextECEF * world2local; MGRSCoord mgrsCoord; if ( mgrs.transform( GeoPoint(extent.getSRS(),sqidTextMap,ALTMODE_ABSOLUTE), mgrsCoord) ) { textSym->size() = 33000.0; osgText::Text* d = ts.create( mgrsCoord.sqid ); osg::Matrixd textLocal2World; ecefSRS->createLocalToWorld( sqidTextECEF, textLocal2World ); d->setPosition( sqidLocal ); textGeode->addDrawable( d ); } } } } } } osg::Group* group = new osg::Group(); Style lineStyle; lineStyle.add( _options->secondaryStyle()->get<LineSymbol>() ); lineStyle.add( _options->secondaryStyle()->get<AltitudeSymbol>() ); GeometryCompiler compiler; osg::ref_ptr<Session> session = new Session( getMapNode()->getMap() ); FilterContext context( session.get(), _featureProfile.get(), extent ); // make sure we get sufficient tessellation: compiler.options().maxGranularity() = 0.25; osg::Node* geomNode = compiler.compile(features, lineStyle, context); if ( geomNode ) group->addChild( geomNode ); osg::MatrixTransform* mt = new osg::MatrixTransform(local2world); mt->addChild(textGeode); group->addChild( mt ); // prep for depth offset: DepthOffsetUtils::prepareGraph( group ); group->getOrCreateStateSet()->addUniform( _minDepthOffset.get() ); return group; }
osg::Group* UTMData::buildGZDTile(const std::string& name, const GeoExtent& extent, const Style& style, const FeatureProfile* featureProfile, const Map* map) { osg::Group* group = new osg::Group(); Style lineStyle; lineStyle.add( const_cast<LineSymbol*>(style.get<LineSymbol>()) ); lineStyle.add( const_cast<AltitudeSymbol*>(style.get<AltitudeSymbol>()) ); bool hasText = style.get<TextSymbol>() != 0L; GeometryCompiler compiler; osg::ref_ptr<Session> session = new Session(map); FilterContext context( session.get(), featureProfile, extent ); // make sure we get sufficient tessellation: compiler.options().maxGranularity() = 1.0; FeatureList features; // longitudinal line: LineString* lon = new LineString(2); lon->push_back( osg::Vec3d(extent.xMin(), extent.yMax(), 0) ); lon->push_back( osg::Vec3d(extent.xMin(), extent.yMin(), 0) ); Feature* lonFeature = new Feature(lon, extent.getSRS()); lonFeature->geoInterp() = GEOINTERP_GREAT_CIRCLE; features.push_back( lonFeature ); // latitudinal line: LineString* lat = new LineString(2); lat->push_back( osg::Vec3d(extent.xMin(), extent.yMin(), 0) ); lat->push_back( osg::Vec3d(extent.xMax(), extent.yMin(), 0) ); Feature* latFeature = new Feature(lat, extent.getSRS()); latFeature->geoInterp() = GEOINTERP_RHUMB_LINE; features.push_back( latFeature ); // top lat line at 84N if ( extent.yMax() == 84.0 ) { LineString* lat = new LineString(2); lat->push_back( osg::Vec3d(extent.xMin(), extent.yMax(), 0) ); lat->push_back( osg::Vec3d(extent.xMax(), extent.yMax(), 0) ); Feature* latFeature = new Feature(lat, extent.getSRS()); latFeature->geoInterp() = GEOINTERP_RHUMB_LINE; features.push_back( latFeature ); } osg::Node* geomNode = compiler.compile(features, lineStyle, context); if ( geomNode ) group->addChild( geomNode ); // get the geocentric tile center: osg::Vec3d tileCenter; extent.getCentroid( tileCenter.x(), tileCenter.y() ); const SpatialReference* ecefSRS = extent.getSRS()->getGeocentricSRS(); osg::Vec3d centerECEF; extent.getSRS()->transform( tileCenter, ecefSRS, centerECEF ); if ( hasText ) { osg::Vec3d west, east; extent.getSRS()->transform( osg::Vec3d(extent.xMin(),tileCenter.y(),0), ecefSRS, west ); extent.getSRS()->transform( osg::Vec3d(extent.xMax(),tileCenter.y(),0), ecefSRS, east ); const TextSymbol* textSym_in = style.get<TextSymbol>(); osg::ref_ptr<TextSymbol> textSym = textSym_in ? new TextSymbol(*textSym_in) : new TextSymbol(); textSym->size() = (west-east).length() / 3.0; TextSymbolizer ts(textSym.get()); osg::Geode* textGeode = new osg::Geode(); osg::Drawable* d = ts.create(name); d->getOrCreateStateSet()->setRenderBinToInherit(); textGeode->addDrawable(d); Registry::shaderGenerator().run(textGeode, Registry::stateSetCache()); osg::Matrixd centerL2W; ecefSRS->createLocalToWorld( centerECEF, centerL2W ); osg::MatrixTransform* mt = new osg::MatrixTransform(centerL2W); mt->addChild(textGeode); group->addChild(mt); } //group = buildGZDChildren( group, name ); group = ClusterCullingFactory::createAndInstall( group, centerECEF )->asGroup(); return group; }
osg::Node* UTMGraticule::buildGZDTile( const std::string& name, const GeoExtent& extent ) { osg::Group* group = new osg::Group(); Style lineStyle; lineStyle.add( _options->primaryStyle()->get<LineSymbol>() ); lineStyle.add( _options->primaryStyle()->get<AltitudeSymbol>() ); //const Style& lineStyle = *_options->lineStyle(); //Style textStyle = *_options->textStyle(); bool hasText = _options->primaryStyle()->get<TextSymbol>() != 0L; GeometryCompiler compiler; osg::ref_ptr<Session> session = new Session( _mapNode->getMap() ); FilterContext context( session.get(), _featureProfile.get(), extent ); // make sure we get sufficient tessellation: compiler.options().maxGranularity() = 1.0; FeatureList features; // longitudinal line: LineString* lon = new LineString(2); lon->push_back( osg::Vec3d(extent.xMin(), extent.yMax(), 0) ); lon->push_back( osg::Vec3d(extent.xMin(), extent.yMin(), 0) ); Feature* lonFeature = new Feature(lon, extent.getSRS()); lonFeature->geoInterp() = GEOINTERP_GREAT_CIRCLE; features.push_back( lonFeature ); // latitudinal line: LineString* lat = new LineString(2); lat->push_back( osg::Vec3d(extent.xMin(), extent.yMin(), 0) ); lat->push_back( osg::Vec3d(extent.xMax(), extent.yMin(), 0) ); Feature* latFeature = new Feature(lat, extent.getSRS()); latFeature->geoInterp() = GEOINTERP_RHUMB_LINE; features.push_back( latFeature ); // top lat line at 84N if ( extent.yMax() == 84.0 ) { LineString* lat = new LineString(2); lat->push_back( osg::Vec3d(extent.xMin(), extent.yMax(), 0) ); lat->push_back( osg::Vec3d(extent.xMax(), extent.yMax(), 0) ); Feature* latFeature = new Feature(lat, extent.getSRS()); latFeature->geoInterp() = GEOINTERP_RHUMB_LINE; features.push_back( latFeature ); } osg::Node* geomNode = compiler.compile(features, lineStyle, context); if ( geomNode ) group->addChild( geomNode ); // get the geocentric tile center: osg::Vec3d tileCenter; extent.getCentroid( tileCenter.x(), tileCenter.y() ); osg::Vec3d centerECEF; extent.getSRS()->transformToECEF( tileCenter, centerECEF ); if ( hasText ) { osg::Vec3d west, east; extent.getSRS()->transformToECEF(osg::Vec3d(extent.xMin(),tileCenter.y(),0), west ); extent.getSRS()->transformToECEF(osg::Vec3d(extent.xMax(),tileCenter.y(),0), east ); TextSymbol* textSym = _options->primaryStyle()->getOrCreate<TextSymbol>(); textSym->size() = (west-east).length() / 3.0; TextSymbolizer ts( textSym ); osg::Geode* textGeode = new osg::Geode(); textGeode->getOrCreateStateSet()->setRenderBinDetails( 9998, "DepthSortedBin" ); textGeode->getOrCreateStateSet()->setAttributeAndModes( _depthAttribute, 1 ); osg::Drawable* d = ts.create(name); d->getOrCreateStateSet()->setRenderBinToInherit(); textGeode->addDrawable(d); osg::MatrixTransform* mt = new osg::MatrixTransform(ECEF::createLocalToWorld(centerECEF)); mt->addChild(textGeode); group->addChild(mt); } group = buildGZDChildren( group, name ); group = ClusterCullingFactory::createAndInstall( group, centerECEF )->asGroup(); return group; }
void KML_Placemark::build( xml_node<>* node, KMLContext& cx ) { Style masterStyle; std::string styleUrl = getValue(node, "styleurl"); if (!styleUrl.empty()) { // process a "stylesheet" style const Style* ref_style = cx._sheet->getStyle( styleUrl, false ); if (ref_style) { masterStyle = masterStyle.combineWith(*ref_style); } } xml_node<>* style = node->first_node("style", 0, false); if ( style ) { // process an "inline" style KML_Style kmlStyle; kmlStyle.scan(style, cx); masterStyle = masterStyle.combineWith(cx._activeStyle); } // parse the geometry. the placemark must have geometry to be valid. The // geometry parse may optionally specify an altitude mode as well. KML_Geometry geometry; geometry.build(node, cx, masterStyle); Geometry* allGeom = geometry._geom.get(); if ( allGeom ) { GeometryIterator giter( allGeom, false ); while( giter.hasMore() ) { Geometry* geom = giter.next(); Style style = masterStyle; AltitudeSymbol* alt = style.get<AltitudeSymbol>(); if ( geom && geom->getTotalPointCount() > 0 ) { // resolve the proper altitude mode for the anchor point AltitudeMode altMode = ALTMODE_RELATIVE; if (alt && !alt->clamping().isSetTo( alt->CLAMP_TO_TERRAIN ) && !alt->clamping().isSetTo( alt->CLAMP_RELATIVE_TO_TERRAIN ) ) { altMode = ALTMODE_ABSOLUTE; } GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode); // check for symbols. ModelSymbol* model = style.get<ModelSymbol>(); IconSymbol* icon = style.get<IconSymbol>(); TextSymbol* text = style.get<TextSymbol>(); // for a single point placemark, apply the default icon and text symbols // if none are specified in the KML. if (geom->getTotalPointCount() == 1) { if (!model && !icon && cx._options->defaultIconSymbol().valid()) { icon = cx._options->defaultIconSymbol().get(); style.add(icon); } if (!text && cx._options->defaultTextSymbol().valid()) { text = cx._options->defaultTextSymbol().get(); style.add(text); } } // the annotation name: std::string name = getValue(node, "name"); if (!name.empty()) { OE_INFO << LC << "Placemark: " << name << std::endl; } AnnotationNode* featureNode = 0L; AnnotationNode* iconNode = 0L; AnnotationNode* modelNode = 0L; // one coordinate? It's a place marker or a label. if ( (model || icon || text) && geom->getTotalPointCount() == 1 ) { // if there's a model, render that - models do NOT get labels. if ( model ) { ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions.get() ); node->setPosition( position ); // model scale: if ( cx._options->modelScale() != 1.0f ) { float s = *cx._options->modelScale(); node->getPositionAttitudeTransform()->setScale(osg::Vec3d(s,s,s)); } // model local tangent plane rotation: if ( !cx._options->modelRotation()->zeroRotation() ) { node->getPositionAttitudeTransform()->setAttitude( *cx._options->modelRotation() ); } modelNode = node; } // is there a label? else if ( !name.empty() ) { if ( !text ) { text = style.getOrCreate<TextSymbol>(); text->encoding() = TextSymbol::ENCODING_UTF8; } text->content()->setLiteral( name ); } // is there an icon? if ( icon ) { PlaceNode* placeNode = new PlaceNode( position ); placeNode->setStyle(style, cx._dbOptions.get()); iconNode = placeNode; } else if ( !model && text && !name.empty() ) { // note: models do not get labels. iconNode = new LabelNode(); iconNode->setStyle(style); } } // multiple coords? feature: if ( geom->getTotalPointCount() > 1 ) { // Remove symbols that we have already processed so the geometry // compiler doesn't get confused. if ( model ) style.removeSymbol( model ); if ( icon ) style.removeSymbol( icon ); if ( text ) style.removeSymbol( text ); Feature* feature = new Feature(geom, cx._srs.get(), style); featureNode = new FeatureNode(feature ); featureNode->setMapNode( cx._mapNode ); } if ( iconNode ) { Registry::objectIndex()->tagNode( iconNode, iconNode ); } if ( modelNode ) { Registry::objectIndex()->tagNode( modelNode, modelNode ); } if ( featureNode ) { Registry::objectIndex()->tagNode( featureNode, featureNode ); } // assemble the results: if ( (iconNode || modelNode) && featureNode ) { osg::Group* group = new osg::Group(); group->addChild( featureNode ); if ( iconNode ) group->addChild( iconNode ); if ( modelNode ) group->addChild( modelNode ); cx._groupStack.top()->addChild( group ); if ( iconNode ) KML_Feature::build( node, cx, iconNode ); if ( modelNode ) KML_Feature::build( node, cx, modelNode ); if ( featureNode ) KML_Feature::build( node, cx, featureNode ); } else { if ( iconNode ) { if ( cx._options->iconAndLabelGroup().valid() ) { cx._options->iconAndLabelGroup()->addChild( iconNode ); } else { cx._groupStack.top()->addChild( iconNode ); } KML_Feature::build( node, cx, iconNode ); } if ( modelNode ) { cx._groupStack.top()->addChild( modelNode ); KML_Feature::build( node, cx, modelNode ); } if ( featureNode ) { osg::Node* child = featureNode; // If this feature node is map-clamped, we most likely need a depth-offset // shader to prevent z-fighting with the terrain. if (alt && alt->clamping() == alt->CLAMP_TO_TERRAIN && alt->technique() == alt->TECHNIQUE_MAP) { DepthOffsetGroup* g = new DepthOffsetGroup(); g->addChild( featureNode ); child = g; } cx._groupStack.top()->addChild( child ); KML_Feature::build( node, cx, featureNode ); } } } } } }
void KML_Placemark::build( const Config& conf, KMLContext& cx ) { Style masterStyle; if ( conf.hasValue("styleurl") ) { // process a "stylesheet" style const Style* ref_style = cx._sheet->getStyle( conf.value("styleurl"), false ); if ( ref_style ) masterStyle = *ref_style; } else if ( conf.hasChild("style") ) { // process an "inline" style KML_Style kmlStyle; kmlStyle.scan( conf.child("style"), cx ); masterStyle = cx._activeStyle; } // parse the geometry. the placemark must have geometry to be valid. The // geometry parse may optionally specify an altitude mode as well. KML_Geometry geometry; geometry.build(conf, cx, masterStyle); Geometry* allGeom = geometry._geom.get(); if ( allGeom ) { GeometryIterator giter( allGeom, false ); while( giter.hasMore() ) { Geometry* geom = giter.next(); Style style = masterStyle; // KML's default altitude mode is clampToGround. AltitudeMode altMode = ALTMODE_RELATIVE; AltitudeSymbol* altSym = style.get<AltitudeSymbol>(); if ( !altSym ) { altSym = style.getOrCreate<AltitudeSymbol>(); altSym->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN; altSym->technique() = AltitudeSymbol::TECHNIQUE_SCENE; } else if ( !altSym->clamping().isSetTo(AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) ) { altMode = ALTMODE_ABSOLUTE; } if ( geom && geom->getTotalPointCount() > 0 ) { GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode); bool isPoly = geom->getComponentType() == Geometry::TYPE_POLYGON; bool isPoint = geom->getComponentType() == Geometry::TYPE_POINTSET; // check for symbols. ModelSymbol* model = style.get<ModelSymbol>(); IconSymbol* icon = style.get<IconSymbol>(); TextSymbol* text = style.get<TextSymbol>(); if ( !text && cx._options->defaultTextSymbol().valid() ) text = cx._options->defaultTextSymbol().get(); // the annotation name: std::string name = conf.hasValue("name") ? conf.value("name") : ""; if ( text && !name.empty() ) { text->content()->setLiteral( name ); } AnnotationNode* featureNode = 0L; AnnotationNode* iconNode = 0L; AnnotationNode* modelNode = 0L; // one coordinate? It's a place marker or a label. if ( model || icon || text || geom->getTotalPointCount() == 1 ) { // load up the default icon if there we don't have one. if ( !model && !icon ) { icon = cx._options->defaultIconSymbol().get(); if ( icon ) style.add( icon ); } // if there's a model, render that - models do NOT get labels. if ( model ) { ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions ); node->setPosition( position ); if ( cx._options->modelScale() != 1.0f ) { float s = *cx._options->modelScale(); node->setScale( osg::Vec3f(s,s,s) ); } if ( !cx._options->modelRotation()->zeroRotation() ) { node->setLocalRotation( *cx._options->modelRotation() ); } modelNode = node; } else if ( !text && !name.empty() ) { text = style.getOrCreate<TextSymbol>(); text->content()->setLiteral( name ); } if ( icon ) { iconNode = new PlaceNode( cx._mapNode, position, style, cx._dbOptions ); } else if ( !model && text && !name.empty() ) { // note: models do not get labels. iconNode = new LabelNode( cx._mapNode, position, style ); } } // multiple coords? feature: if ( geom->getTotalPointCount() > 1 ) { ExtrusionSymbol* extruded = style.get<ExtrusionSymbol>(); AltitudeSymbol* altitude = style.get<AltitudeSymbol>(); // Remove symbols that we have already processed so the geometry // compiler doesn't get confused. if ( model ) style.removeSymbol( model ); if ( icon ) style.removeSymbol( icon ); if ( text ) style.removeSymbol( text ); // analyze the data; if the Z coords are all 0.0, enable draping. if ( /*isPoly &&*/ !extruded && altitude && altitude->clamping() != AltitudeSymbol::CLAMP_TO_TERRAIN ) { bool zeroElev = true; ConstGeometryIterator gi( geom, false ); while( zeroElev == true && gi.hasMore() ) { const Geometry* g = gi.next(); for( Geometry::const_iterator ji = g->begin(); ji != g->end() && zeroElev == true; ++ji ) { if ( !osg::equivalent(ji->z(), 0.0) ) zeroElev = false; } } if ( zeroElev ) { altitude->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; altitude->technique() = AltitudeSymbol::TECHNIQUE_GPU; } } // Make a feature node; drape if we're not extruding. bool draped = isPoly && !extruded && (!altitude || altitude->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN); if ( draped && style.get<LineSymbol>() && !style.get<PolygonSymbol>() ) { draped = false; } // turn off the clamping if we're draping. if ( draped && altitude ) { altitude->technique() = AltitudeSymbol::TECHNIQUE_DRAPE; } GeometryCompilerOptions compilerOptions; // Check for point-model substitution: if ( style.has<ModelSymbol>() ) { compilerOptions.instancing() = true; } Feature* feature = new Feature(geom, cx._srs.get(), style); featureNode = new FeatureNode( cx._mapNode, feature, draped, compilerOptions ); } // assemble the results: if ( (iconNode || modelNode) && featureNode ) { osg::Group* group = new osg::Group(); group->addChild( featureNode ); if ( iconNode ) group->addChild( iconNode ); if ( modelNode ) group->addChild( modelNode ); cx._groupStack.top()->addChild( group ); if ( iconNode && cx._options->declutter() == true ) Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true ); if ( iconNode ) KML_Feature::build( conf, cx, iconNode ); if ( modelNode ) KML_Feature::build( conf, cx, modelNode ); if ( featureNode ) KML_Feature::build( conf, cx, featureNode ); } else { if ( iconNode ) { if ( cx._options->iconAndLabelGroup().valid() ) { cx._options->iconAndLabelGroup()->addChild( iconNode ); } else { cx._groupStack.top()->addChild( iconNode ); if ( cx._options->declutter() == true ) Decluttering::setEnabled( iconNode->getOrCreateStateSet(), true ); } KML_Feature::build( conf, cx, iconNode ); } if ( modelNode ) { cx._groupStack.top()->addChild( modelNode ); KML_Feature::build( conf, cx, modelNode ); } if ( featureNode ) { cx._groupStack.top()->addChild( featureNode ); KML_Feature::build( conf, cx, featureNode ); } } } } } }