source: geovis/branches/rex/Placard.cpp @ 6570

Last change on this file since 6570 was 6570, checked in by ldelgass, 8 years ago

First pass at porting to new Map layer API

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2015  HUBzero Foundation, LLC
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <string>
9#include <sstream>
10
11#include <osg/Depth>
12#include <osgText/Text>
13#include <osgEarthAnnotation/AnnotationUtils>
14#include <osgEarth/Registry>
15#include <osgEarth/ShaderGenerator>
16#include <osgEarth/ScreenSpaceLayout>
17#include <osgEarthSymbology/BBoxSymbol>
18#include <osgEarthSymbology/PolygonSymbol>
19#include <osgEarthSymbology/TextSymbol>
20#include <osgEarthSymbology/Fill>
21
22#include "Placard.h"
23#include "Trace.h"
24
25#define LC "[PlacardNode] "
26
27using namespace GeoVis;
28
29Placard::Placard() :
30    _enabled(true)
31{
32    osgEarth::Symbology::TextSymbol *ts = _textStyle.getOrCreateSymbol<osgEarth::Symbology::TextSymbol>();
33    //ts->halo()->color() = osgEarth::Symbology::Color(1, 1, 1);
34    //ts->halo()->width() = 2;
35    ts->fill()->color() = osgEarth::Symbology::Color(0, 0, 0);
36    ts->size() = 14;
37    //ts->alignment() = alignment;
38    ts->declutter() = false;
39    //ts->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
40    double charSize = ts->size().isSet() ? ts->size()->eval() : 14.0;
41    _padding = (float)(charSize / 2.0);
42
43    osgEarth::Symbology::BBoxSymbol *bbs = _textStyle.getOrCreateSymbol<osgEarth::Symbology::BBoxSymbol>();
44    bbs->fill() = osgEarth::Symbology::Color(0.75, 0.75, 0.75, 0.75);
45    bbs->margin() = _padding;
46}
47
48PlacardLabelNode::PlacardLabelNode(osgEarth::MapNode *mapNode,
49                                   const osgEarth::GeoPoint& position,
50                                   const Placard& placardConf,
51                                   const osgEarth::Features::AttributeTable &attrs) :
52    osgEarth::Annotation::LabelNode(mapNode, position, placardConf.getStyle()),
53    _placardConf(placardConf),
54    _attrs(attrs)
55{
56    setConfig(placardConf);
57}
58
59void
60PlacardLabelNode::setConfig(const Placard& placardConf)
61{
62    _placardConf = placardConf;
63    std::ostringstream oss;
64    for (size_t i = 0; i < placardConf.getNumEntries(); i++) {
65        std::string name, label;
66        placardConf.getEntry(i, name, label);
67        oss << label << ": ";
68        TRACE(" attr: %s '%s'", name.c_str(), label.c_str());
69        osgEarth::Features::AttributeTable::const_iterator itr = _attrs.find(name);
70        if (itr == _attrs.end())
71            continue;
72        switch (itr->second.first) {
73        case osgEarth::Features::ATTRTYPE_STRING:
74            TRACE(" value: %s", itr->second.getString().c_str());
75            oss << itr->second.getString() << std::endl;
76            break;
77        case osgEarth::Features::ATTRTYPE_INT:
78            TRACE(" value: %d", itr->second.getInt());
79            oss << itr->second.getInt() << std::endl;
80            break;
81        case osgEarth::Features::ATTRTYPE_DOUBLE:
82            TRACE(" value: %g", itr->second.getDouble());
83            oss << itr->second.getDouble() << std::endl;
84            break;
85        case osgEarth::Features::ATTRTYPE_BOOL:
86            TRACE(" value: %s", itr->second.getBool() ? "true" : "false");
87            oss << (itr->second.getBool() ? "true" : "false") << std::endl;
88            break;
89        default:
90            break;
91        }
92    }
93    setText(oss.str());
94}
95
96PlacardNode::PlacardNode(osgEarth::MapNode *mapNode,
97                         const osgEarth::GeoPoint& position,
98                         const Placard& placardConf,
99                         const osgEarth::Features::AttributeTable &attrs) :
100    osgEarth::Annotation::GeoPositionNode(mapNode, position),
101    _placardConf(placardConf),
102    _attrs(attrs)
103{
104    setConfig(placardConf);
105    init(placardConf.getStyle());
106}
107
108void
109PlacardNode::setConfig(const Placard& placardConf)
110{
111    _placardConf = placardConf;
112    std::ostringstream oss;
113    for (size_t i = 0; i < placardConf.getNumEntries(); i++) {
114        std::string name, label;
115        placardConf.getEntry(i, name, label);
116        oss << label << ": ";
117        TRACE(" attr: %s '%s'", name.c_str(), label.c_str());
118        osgEarth::Features::AttributeTable::const_iterator itr = _attrs.find(name);
119        if (itr == _attrs.end())
120            continue;
121        switch (itr->second.first) {
122        case osgEarth::Features::ATTRTYPE_STRING:
123            TRACE(" value: %s", itr->second.getString().c_str());
124            oss << itr->second.getString() << std::endl;
125            break;
126        case osgEarth::Features::ATTRTYPE_INT:
127            TRACE(" value: %d", itr->second.getInt());
128            oss << itr->second.getInt() << std::endl;
129            break;
130        case osgEarth::Features::ATTRTYPE_DOUBLE:
131            TRACE(" value: %g", itr->second.getDouble());
132            oss << itr->second.getDouble() << std::endl;
133            break;
134        case osgEarth::Features::ATTRTYPE_BOOL:
135            TRACE(" value: %s", itr->second.getBool() ? "true" : "false");
136            oss << (itr->second.getBool() ? "true" : "false") << std::endl;
137            break;
138        default:
139            break;
140        }
141    }
142    setText(oss.str());
143}
144
145void
146PlacardNode::init( const osgEarth::Symbology::Style& style )
147{
148    osgEarth::ScreenSpaceLayout::activate(this->getOrCreateStateSet());
149    _backdropGeode = new osg::Geode();
150    _backdropGeode->setComputeBoundingSphereCallback(new osgEarth::Annotation::ControlPointCallback());
151    getPositionAttitudeTransform()->addChild( _backdropGeode.get() );
152
153    osg::StateSet* stateSet = _backdropGeode->getOrCreateStateSet();
154    stateSet->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), 1 );
155
156    _geode = new osg::Geode();
157
158    // ensure that (0,0,0) is the bounding sphere control/center point.
159    // useful for things like horizon culling.
160    _geode->setComputeBoundingSphereCallback(new osgEarth::Annotation::ControlPointCallback());
161
162    getPositionAttitudeTransform()->addChild( _geode.get() );
163    stateSet = _geode->getOrCreateStateSet();
164    stateSet->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), 1 );
165
166    setStyle( style );
167}
168
169void
170PlacardNode::setText( const std::string& text )
171{
172    if ( !_dynamic && getNumParents() > 0 )
173    {
174        OE_WARN << LC << "Illegal state: cannot change a LabelNode that is not dynamic" << std::endl;
175        return;
176    }
177
178    _text = text;
179    if (!_geode.valid())
180        return;
181
182    osgText::Text* d = dynamic_cast<osgText::Text*>(_geode->getDrawable(0));
183    if ( d )
184    {
185        d->setText( text );
186        d->dirtyDisplayList();
187    }
188
189    if (!_backdropGeode.valid())
190        return;
191
192    osg::Geometry *bd = dynamic_cast<osg::Geometry*>(_backdropGeode->getDrawable(0));
193    if (bd) {
194        osg::BoundingBox bbox = d->getBoundingBox();
195        _backdropGeode->removeDrawables( 0, _backdropGeode->getNumDrawables() );
196        const osgEarth::Symbology::PolygonSymbol* gs = _style.get<osgEarth::Symbology::PolygonSymbol>();
197        osg::Vec4 color(0.75, 0.75, 0.75, 0.75);
198        if (gs && gs->fill().isSet()) {
199            color = gs->fill().get().color();
200        }
201        osg::Drawable *bd = osgEarth::Annotation::AnnotationUtils::create2DQuad(bbox, _placardConf.getPadding(), color);
202        _backdropGeode->addDrawable(bd);
203    }
204}
205
206void
207PlacardNode::setStyle( const osgEarth::Symbology::Style& style )
208{
209    if ( !_dynamic && getNumParents() > 0 )
210    {
211        OE_WARN << LC << "Illegal state: cannot change a LabelNode that is not dynamic" << std::endl;
212        return;
213    }
214    _backdropGeode->removeDrawables( 0, _backdropGeode->getNumDrawables() );
215
216    _geode->removeDrawables( 0, _geode->getNumDrawables() );
217
218    _style = style;
219
220    const osgEarth::Symbology::TextSymbol* symbol = _style.get<osgEarth::Symbology::TextSymbol>();
221
222    if ( _text.empty() )
223        _text = symbol->content()->eval();
224
225    osg::Drawable* t = osgEarth::Annotation::AnnotationUtils::createTextDrawable( _text, symbol, osg::Vec3(0,0,0) );
226    _geode->addDrawable(t);
227    _geode->setCullingActive(false);
228
229    const osgEarth::Symbology::PolygonSymbol* gs = _style.get<osgEarth::Symbology::PolygonSymbol>();
230    osg::Vec4 color(0.75, 0.75, 0.75, 0.75);
231    if (gs && gs->fill().isSet()) {
232        color = gs->fill().get().color();
233    }
234
235    osg::BoundingBox bbox = t->getBoundingBox();
236    osg::Drawable *bd = osgEarth::Annotation::AnnotationUtils::create2DQuad(bbox, _placardConf.getPadding(), color);
237    _backdropGeode->addDrawable(bd);
238    _backdropGeode->setCullingActive(false);
239
240    applyStyle( _style );
241
242    setLightingIfNotSet( false );
243
244    osgEarth::Registry::shaderGenerator().run(
245        this,
246        "osgEarth.PlacardNode",
247        osgEarth::Registry::stateSetCache() );
248
249    // Set to max priority to draw on top in decluttering sort
250    setPriority(FLT_MAX);
251    // setPriority calls updateLayoutData
252    //updateLayoutData();
253}
254
255void
256PlacardNode::setPriority(float value)
257{
258    osgEarth::Annotation::GeoPositionNode::setPriority(value);
259    updateLayoutData();
260}
261
262void
263PlacardNode::updateLayoutData()
264{
265    if (!_geode.valid())
266        return;
267
268    if (!_dataLayout.valid())
269    {
270        _dataLayout = new osgEarth::ScreenSpaceLayoutData();
271    }
272
273    // re-apply annotation drawable-level stuff as neccesary.
274    for (unsigned i = 0; i < _backdropGeode->getNumDrawables(); ++i)
275    {
276        _backdropGeode->getDrawable(i)->setUserData(_dataLayout.get());
277    }
278    // re-apply annotation drawable-level stuff as neccesary.
279    for (unsigned i = 0; i < _geode->getNumDrawables(); ++i)
280    {
281        _geode->getDrawable(i)->setUserData(_dataLayout.get());
282    }
283
284    _dataLayout->setPriority(getPriority());
285    const osgEarth::Symbology::TextSymbol *ts = getStyle().get<osgEarth::Symbology::TextSymbol>();
286    if (ts)
287    {
288        _dataLayout->setPixelOffset(ts->pixelOffset().get());
289    }
290}
291
292void
293PlacardNode::setDynamic( bool dynamic )
294{
295    osgEarth::Annotation::GeoPositionNode::setDynamic( dynamic );
296
297    osgText::Text* d = dynamic_cast<osgText::Text*>(_geode->getDrawable(0));
298    if ( d )
299    {
300        d->setDataVariance( dynamic ? osg::Object::DYNAMIC : osg::Object::STATIC );
301    }
302    osg::Geometry *bd = dynamic_cast<osg::Geometry*>(_backdropGeode->getDrawable(0));
303    if (bd) {
304        bd->setDataVariance( dynamic ? osg::Object::DYNAMIC : osg::Object::STATIC );
305    }
306}
307
308osgEarth::Config
309PlacardNode::getConfig() const
310{
311    osgEarth::Config conf = osgEarth::Annotation::GeoPositionNode::getConfig();
312
313    conf.key() = "placard";
314
315    conf.add   ( "text",   _text );
316    conf.addObj( "style",  _style );
317    conf.add   ( "padding", _placardConf.getPadding() );
318
319    return conf;
320}
Note: See TracBrowser for help on using the repository browser.