1 /* -*-c++-*- */
2 /* osgEarth - Geospatial SDK for OpenSceneGraph
3  * Copyright 2019 Pelican Mapping
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 
20 #include <osgEarth/MaskSource>
21 #include <osgEarth/Registry>
22 #include <osgEarth/Map>
23 
24 #include <osgEarthFeatures/TransformFilter>
25 #include <osgEarthFeatures/FeatureSource>
26 #include <osgEarthFeatures/FilterContext>
27 #include <osgEarthFeatures/FeatureCursor>
28 
29 #include <osgDB/FileNameUtils>
30 #include <OpenThreads/Mutex>
31 #include <OpenThreads/ScopedLock>
32 
33 #include "FeatureMaskOptions"
34 
35 #define LC "[FeatureMaskDriver] "
36 
37 using namespace osgEarth;
38 using namespace osgEarth::Features;
39 using namespace osgEarth::Drivers;
40 
41 //------------------------------------------------------------------------
42 
43 class FeatureMaskSource : public MaskSource
44 {
45 public:
FeatureMaskSource(const MaskSourceOptions & options)46     FeatureMaskSource( const MaskSourceOptions& options )
47         : MaskSource( options ), _options( options ), _failed( false )
48     {
49         // the data source from which to pull features:
50         if ( _options.featureSource().valid() )
51         {
52             _features = _options.featureSource().get();
53         }
54         else if ( _options.featureOptions().isSet() )
55         {
56             _features = FeatureSourceFactory::create( _options.featureOptions().value() );
57             if ( !_features.valid() )
58             {
59                 OE_WARN << "FeatureModelSource - no valid feature source provided" << std::endl;
60             }
61         }
62     }
63 
getOptions() const64     const MaskSourceOptions& getOptions() const {
65         return _options;
66     }
67 
68     //override
initialize(const osgDB::Options * readOptions)69     Status initialize(const osgDB::Options* readOptions)
70     {
71         if (!_features.valid())
72             return Status::Error(LC, "No feature source available");
73 
74         const Status& fstatus = _features->open(readOptions);
75         if (fstatus.isError())
76             return fstatus;
77 
78         return Status::OK();
79     }
80 
createBoundary(const SpatialReference * srs,ProgressCallback * progress)81     osg::Vec3dArray* createBoundary(const SpatialReference* srs, ProgressCallback* progress)
82     {
83         if (getStatus().isError())
84             return 0L;
85 
86         if ( _features.valid() )
87         {
88             if ( _features->getFeatureProfile() )
89             {
90                 osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor(progress);
91                 if ( cursor.valid() && cursor->hasMore() )
92                 {
93                     Feature* f = cursor->nextFeature();
94                     if ( f && f->getGeometry() )
95                     {
96                         // Init a filter to transform feature in desired SRS
97                         if (!srs->isEquivalentTo(_features->getFeatureProfile()->getSRS()))
98                         {
99                             FilterContext cx;
100                             cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) );
101 
102                             TransformFilter xform( srs );
103                             FeatureList featureList;
104                             featureList.push_back(f);
105                             cx = xform.push(featureList, cx);
106                         }
107 
108                         return f->getGeometry()->createVec3dArray();
109                     }
110                 }
111             }
112             else
113             {
114                 setStatus(Status::Error("Failed to create boundary"));
115                 OE_WARN << LC << getStatus().message() << std::endl;
116             }
117         }
118         else
119         {
120             setStatus(Status::Error("Failed to create boundary"));
121             OE_WARN << LC << getStatus().message() << std::endl;
122         }
123         return 0L;
124     }
125 
126 private:
127     bool _failed;
128     const FeatureMaskOptions _options;
129     osg::ref_ptr<FeatureSource> _features;
130 };
131 
132 //------------------------------------------------------------------------
133 
134 class FeatureMaskDriver : public MaskSourceDriver
135 {
136 public:
FeatureMaskDriver()137     FeatureMaskDriver()
138     {
139         supportsExtension( "osgearth_mask_feature", "osgEarth feature mask plugin" );
140     }
141 
className() const142     virtual const char* className() const
143     {
144         return "osgEarth Feature Mask Plugin";
145     }
146 
readObject(const std::string & file_name,const Options * options) const147     virtual ReadResult readObject(const std::string& file_name, const Options* options) const
148     {
149         if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name )))
150             return ReadResult::FILE_NOT_HANDLED;
151 
152         return new FeatureMaskSource( getMaskSourceOptions(options) );
153     }
154 };
155 
156 REGISTER_OSGPLUGIN(osgearth_mask_feature, FeatureMaskDriver)
157