source: geovis/branches/1.0/Placard.cpp @ 6666

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

add default placard offset

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