source: geovis/trunk/Placard.cpp @ 6295

Last change on this file since 6295 was 6273, checked in by ldelgass, 9 years ago

Fix placard to work with osgearth trunk refactor (Decluttering -> ScreenSpaceLayout?)

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