source: geovis/trunk/Placard.cpp @ 6507

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

Use new text bounding box symbol if using new API.

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