root/OpenSceneGraph/trunk/src/osgPlugins/ogr/ReaderWriterOGR.cpp @ 12697

Revision 12697, 18.1 kB (checked in by robert, 3 years ago)

From Alberto Luacas, typo fixes

  • Property svn:eol-style set to native
Line 
1/* -*- mode: c++; c-default-style: k&r; tab-width: 4; c-basic-offset: 4; -*-
2 * Copyright (C) 2007 Cedric Pinson - mornifle@plopbyte.net
3 *
4 * This library is open source and may be redistributed and/or modified under 
5 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
6 * (at your option) any later version.  The full license is in LICENSE file
7 * included with this distribution, and on the openscenegraph.org website.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * OpenSceneGraph Public License for more details.
13*/
14
15#include <osg/Image>
16#include <osg/Notify>
17#include <osg/Geode>
18#include <osg/GL>
19#include <osg/Geometry>
20#include <osg/Point>
21#include <osg/Material>
22#include <osg/TriangleFunctor>
23#include <osgUtil/Tessellator>
24
25#include <osgDB/Registry>
26#include <osgDB/FileNameUtils>
27#include <osgDB/FileUtils>
28#include <osgDB/ImageOptions>
29
30#include <OpenThreads/ScopedLock>
31#include <OpenThreads/ReentrantMutex>
32#include <gdal_priv.h>
33#include <ogr_feature.h>
34#include <cpl_error.h>
35#include <ogr_core.h>
36#include <ogr_feature.h>
37#include <ogrsf_frmts.h>
38
39#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex) 
40
41void CPL_STDCALL CPLOSGErrorHandler( CPLErr eErrClass, int nError,
42                             const char * pszErrorMsg )
43{
44    if( eErrClass == CE_Debug )
45    {
46        OSG_DEBUG << pszErrorMsg << std::endl;
47    }
48    else if( eErrClass == CE_Warning )
49    {
50        OSG_WARN << nError << " " << pszErrorMsg << std::endl;
51    }
52    else
53    {
54        OSG_FATAL << nError << " " << pszErrorMsg << std::endl;
55    }
56}
57
58static osg::Material* createDefaultMaterial()
59{
60    osg::Vec4 color;
61    for (int i = 0; i < 3; i++)
62        color[i] = (1.0 * (rand() / (1.0*RAND_MAX)));
63    color[3] = 1;
64    osg::Material* mat = new osg::Material;
65    mat->setDiffuse(osg::Material::FRONT_AND_BACK, color);
66    return mat;
67}
68
69struct TriangulizeFunctor
70{
71    osg::Vec3Array* _vertexes;
72
73    // do nothing
74    void operator ()(const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3, bool treatVertexDataAsTemporary) {
75        _vertexes->push_back(v1);
76        _vertexes->push_back(v2);
77        _vertexes->push_back(v3);
78    }
79};
80
81static osg::Vec3Array* triangulizeGeometry(osg::Geometry* src)
82{
83    if (src->getNumPrimitiveSets() == 1 &&
84        src->getPrimitiveSet(0)->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType &&
85        src->getVertexArray() &&
86        src->getVertexArray()->getType() == osg::Array::Vec3ArrayType)
87        return static_cast<osg::Vec3Array*>(src->getVertexArray());
88
89    osg::TriangleFunctor<TriangulizeFunctor> functor;
90    osg::Vec3Array* array = new osg::Vec3Array;
91    functor._vertexes = array;
92    src->accept(functor);
93    return array;
94}
95
96
97class ReaderWriterOGR : public osgDB::ReaderWriter
98{
99
100public:
101    ReaderWriterOGR()
102    {
103        supportsExtension("ogr","OGR file reader");
104        supportsOption("useRandomColorByFeature", "Assign a random color to each feature.");
105        supportsOption("addGroupPerFeature", "Places each feature in a separate group.");
106        oldHandler = CPLSetErrorHandler(CPLOSGErrorHandler);
107    }
108
109    virtual ~ReaderWriterOGR()
110    {
111        CPLSetErrorHandler(oldHandler);
112    }
113   
114    virtual const char* className() const { return "OGR file reader"; }
115
116    virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
117    {
118        OSG_INFO<<"OGR::readNode("<<file<<")"<<std::endl;
119       
120        if (file.empty()) return ReadResult::FILE_NOT_FOUND;
121   
122        if (osgDB::equalCaseInsensitive(osgDB::getFileExtension(file),"ogr"))
123        {
124            OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex);
125            return readFile(osgDB::getNameLessExtension(file), options);
126        }
127
128        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex);
129        std::string fileName = osgDB::findDataFile( file, options );
130        if (fileName.empty()) return readFile(file, options); // ReadResult::FILE_NOT_FOUND;
131
132        return readFile(fileName, options);
133    }
134
135    virtual ReadResult readFile(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
136    {
137        if (OGRSFDriverRegistrar::GetRegistrar()->GetDriverCount() == 0)
138            OGRRegisterAll();
139
140        // Try to open data source
141        OGRDataSource* file = OGRSFDriverRegistrar::Open(fileName.c_str());
142        if (!file)
143            return 0;
144
145        bool useRandomColorByFeature = false;
146        bool addGroupPerFeature = false;
147        if (options)
148        {
149            if (options->getOptionString().find("UseRandomColorByFeature") != std::string::npos)
150                useRandomColorByFeature = true;
151            if (options->getOptionString().find("useRandomColorByFeature") != std::string::npos)
152                useRandomColorByFeature = true;
153            if (options->getOptionString().find("addGroupPerFeature") != std::string::npos)
154                addGroupPerFeature = true;
155        }
156
157        osg::Group* group = new osg::Group;
158
159        for (int i = 0; i < file->GetLayerCount(); i++)
160        {
161            osg::Group* node = readLayer(file->GetLayer(i), file->GetName(), useRandomColorByFeature, addGroupPerFeature);
162            if (node)
163                group->addChild( node );
164        }
165        OGRDataSource::DestroyDataSource( file );
166        return group;
167    }
168
169    osg::Group* readLayer(OGRLayer* ogrLayer, const std::string& name, bool useRandomColorByFeature, bool addGroupPerFeature) const
170    {
171        if (!ogrLayer)
172            return 0;
173
174        osg::Group* layer = new osg::Group;
175        layer->setName(ogrLayer->GetLayerDefn()->GetName());
176        ogrLayer->ResetReading();
177
178        OGRFeature* ogrFeature = NULL;
179        while ((ogrFeature = ogrLayer->GetNextFeature()) != NULL)
180        {
181            osg::Geode* feature = readFeature(ogrFeature, useRandomColorByFeature);
182            if (feature)
183            {
184                if (addGroupPerFeature)
185                {
186                    osg::Group* featureGroup = new osg::Group;
187                    featureGroup->addChild(feature);
188                    layer->addChild(featureGroup);
189                }
190                else
191                {
192                    layer->addChild(feature);
193                }
194            }
195            OGRFeature::DestroyFeature( ogrFeature );
196        }
197        return layer;
198    }
199
200    osg::Geometry* pointsToDrawable(const OGRPoint* points) const
201    {
202        osg::Geometry* pointGeom = new osg::Geometry();
203        osg::Vec3Array* vertices = new osg::Vec3Array();
204        vertices->push_back(osg::Vec3(points->getX(), points->getY(), points->getZ()));
205        pointGeom->setVertexArray(vertices);
206        pointGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 1));
207        return pointGeom;
208    }
209
210    osg::Geometry* linearRingToDrawable(OGRLinearRing* ring) const
211    {
212        osg::Geometry* contourGeom = new osg::Geometry();
213        osg::Vec3Array* vertices = new osg::Vec3Array();
214        OGRPoint point;
215        for(int j = 0; j < ring->getNumPoints(); j++)
216        {
217            ring->getPoint(j, &point);
218            vertices->push_back(osg::Vec3(point.getX(), point.getY(),point.getZ()));
219        }
220        contourGeom->setVertexArray(vertices);
221        contourGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, vertices->size()));
222        return contourGeom;
223    }
224
225    osg::Geometry* lineStringToDrawable(OGRLineString* lineString) const
226    {
227        osg::Geometry* contourGeom = new osg::Geometry();
228        osg::Vec3Array* vertices = new osg::Vec3Array();
229        OGRPoint point;
230        for(int j = 0; j < lineString->getNumPoints(); j++)
231        {
232            lineString->getPoint(j, &point);
233            vertices->push_back(osg::Vec3(point.getX(), point.getY(), point.getZ()));
234        }
235
236        contourGeom->setVertexArray(vertices);
237        contourGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertices->size()));
238        return contourGeom;
239    }
240
241    osg::Geometry* multiPointToDrawable(OGRMultiPoint* mpoint) const
242    {
243        osg::Geometry* geom = new osg::Geometry;
244
245        osg::Geometry* pointGeom = new osg::Geometry();
246        osg::Vec3Array* vertices = new osg::Vec3Array();
247       
248        vertices->reserve(mpoint->getNumGeometries());
249        for (int i = 0; i < mpoint->getNumGeometries(); i++ )
250        {
251            OGRGeometry* ogrGeom = mpoint->getGeometryRef(i);
252            OGRwkbGeometryType ogrGeomType = ogrGeom->getGeometryType();
253
254            if (wkbPoint != ogrGeomType && wkbPoint25D != ogrGeomType)
255                continue; // skip
256
257            OGRPoint* points = static_cast<OGRPoint*>(ogrGeom);
258       
259            vertices->push_back(osg::Vec3(points->getX(), points->getY(), points->getZ()));
260        }
261       
262        pointGeom->setVertexArray(vertices);
263        pointGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, vertices->size()));
264       
265        if (pointGeom->getVertexArray())
266        {
267            OSG_INFO << "osgOgrFeature::multiPointToDrawable " << geom->getVertexArray()->getNumElements() << " vertexes"<< std::endl;
268        }
269
270        return pointGeom;
271    }
272
273    osg::Geometry* multiPolygonToDrawable(OGRMultiPolygon* mpolygon) const
274    {
275        osg::Geometry* geom = new osg::Geometry;
276
277        for (int i = 0; i < mpolygon->getNumGeometries(); i++ )
278        {
279            OGRGeometry* ogrGeom = mpolygon->getGeometryRef(i);
280            OGRwkbGeometryType ogrGeomType = ogrGeom->getGeometryType();
281
282            if (wkbPolygon != ogrGeomType && wkbPolygon25D != ogrGeomType)
283                continue; // skip
284
285            OGRPolygon* polygon = static_cast<OGRPolygon*>(ogrGeom);
286            osg::ref_ptr<osg::Drawable> drw = polygonToDrawable(polygon);
287            osg::ref_ptr<osg::Geometry> geometry = drw->asGeometry();
288            if (geometry.valid() && geometry->getVertexArray() &&
289                geometry->getVertexArray()->getNumElements() &&
290                geometry->getNumPrimitiveSets() &&
291                geometry->getVertexArray()->getType() == osg::Array::Vec3ArrayType )
292            {
293
294                if (!geom->getVertexArray())
295                { // no yet data we put the first in
296                    geom->setVertexArray(geometry->getVertexArray());
297                    geom->setPrimitiveSetList(geometry->getPrimitiveSetList());
298
299                }
300                else 
301                { // already a polygon then append
302                    int size = geom->getVertexArray()->getNumElements();
303                    osg::Vec3Array* arrayDst = static_cast<osg::Vec3Array*>(geom->getVertexArray());
304                    osg::ref_ptr<osg::Vec3Array> triangulized = triangulizeGeometry(geometry.get());
305                    if (triangulized.valid())
306                    {
307                        arrayDst->insert(arrayDst->end(), triangulized->begin(), triangulized->end());
308                        // shift index
309                        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, size, triangulized->size()));
310                    }
311                }
312            }
313            else
314            {
315                OSG_WARN << "Warning something wrong with a polygon in a multi polygon" << std::endl;
316            }
317        }
318
319        if (geom->getVertexArray())
320        {
321            OSG_INFO << "osgOgrFeature::multiPolygonToDrawable " << geom->getVertexArray()->getNumElements() << " vertexes"<< std::endl;
322        }
323
324        return geom;
325    }
326
327    osg::Geometry* polygonToDrawable(OGRPolygon* polygon) const
328    {
329        osg::Geometry* geom = new osg::Geometry();
330        osg::Vec3Array* vertices = new osg::Vec3Array();
331        geom->setVertexArray(vertices);
332        {
333            OGRLinearRing *ring = polygon->getExteriorRing();
334            OGRPoint point;
335            for(int i = 0; i < ring->getNumPoints(); i++)
336            {
337                ring->getPoint(i, &point);
338                vertices->push_back(osg::Vec3(point.getX(), point.getY(), point.getZ()));
339            }
340            geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, vertices->size()));
341        }
342
343        if (polygon->getNumInteriorRings())
344        {
345            for (int i = 0; i < polygon->getNumInteriorRings(); i++)
346            {
347                OGRLinearRing *ring = polygon->getInteriorRing(i);
348                OGRPoint point;
349                for (int j = 0; j < ring->getNumPoints(); j++)
350                {
351                    ring->getPoint(j, &point);
352                    vertices->push_back(osg::Vec3(point.getX(), point.getY(), point.getZ()));
353                }
354                geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, vertices->size()-ring->getNumPoints() , ring->getNumPoints()));
355            }
356        }
357        osgUtil::Tessellator tsl;
358        tsl.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
359        tsl.setBoundaryOnly(false);
360        tsl.retessellatePolygons(*geom);
361
362        osg::Vec3Array* array = triangulizeGeometry(geom);
363        geom->setVertexArray(array);
364        geom->removePrimitiveSet(0,geom->getNumPrimitiveSets());
365        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, array->size()));
366 
367        return geom;
368    }
369    osg::Geometry* multiLineStringToDrawable(OGRMultiLineString* mlineString) const
370    {
371        osg::Geometry* geom = new osg::Geometry;
372
373        for (int i = 0; i < mlineString->getNumGeometries(); i++ )
374        {
375            OGRGeometry* ogrGeom = mlineString->getGeometryRef(i);
376            OGRwkbGeometryType ogrGeomType = ogrGeom->getGeometryType();
377
378            if (wkbLineString != ogrGeomType && wkbLineString25D != ogrGeomType)
379                continue; // skip
380
381            OGRLineString* lineString = static_cast<OGRLineString*>(ogrGeom);
382            osg::ref_ptr<osg::Geometry> geometry = lineStringToDrawable(lineString);
383            if (geometry.valid() &&
384                geometry->getVertexArray() &&
385                geometry->getNumPrimitiveSets() &&
386                geometry->getVertexArray()->getType() == osg::Array::Vec3ArrayType)
387            {
388
389                if (!geom->getVertexArray())
390                {
391                    geom->setVertexArray(geometry->getVertexArray());
392                    geom->setPrimitiveSetList(geometry->getPrimitiveSetList());
393
394                }
395                else 
396                {
397                    int size = geom->getVertexArray()->getNumElements();
398
399                    osg::Vec3Array* arraySrc = static_cast<osg::Vec3Array*>(geometry->getVertexArray());
400                    osg::Vec3Array* arrayDst = static_cast<osg::Vec3Array*>(geom->getVertexArray());
401                    arrayDst->insert(arrayDst->end(), arraySrc->begin(), arraySrc->end());
402                    // shift index
403                    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, size, arraySrc->size()));
404                }
405            }
406        }
407        return geom;
408    }
409
410    osg::Geode* readFeature(OGRFeature* ogrFeature, bool useRandomColorByFeature) const
411    {
412
413        if (!ogrFeature || !ogrFeature->GetGeometryRef())
414            return 0;
415         
416        osg::Geometry* drawable = 0;
417        bool disableCulling = false;
418
419        // Read the geometry
420        switch(ogrFeature->GetGeometryRef()->getGeometryType()) {
421        case wkbPoint:
422        case wkbPoint25D:
423            // point to drawable
424            drawable = pointsToDrawable(static_cast<OGRPoint *>(ogrFeature->GetGeometryRef()));
425            disableCulling = true;
426            break;
427
428        case wkbLinearRing:
429            drawable = linearRingToDrawable(static_cast<OGRLinearRing *>(ogrFeature->GetGeometryRef()));
430            break;
431
432        case wkbLineString:
433        case wkbLineString25D:
434            drawable = lineStringToDrawable(static_cast<OGRLineString*>(ogrFeature->GetGeometryRef()));
435            break;
436
437        case wkbPolygon:
438        case wkbPolygon25D:
439            drawable = polygonToDrawable(static_cast<OGRPolygon*>(ogrFeature->GetGeometryRef()));
440            break;
441
442        case wkbMultiPoint:
443        case wkbMultiPoint25D:
444            drawable = multiPointToDrawable(static_cast<OGRMultiPoint*>(ogrFeature->GetGeometryRef()));
445            disableCulling = true;
446            break;
447
448        case wkbMultiLineString:
449        case wkbMultiLineString25D:
450            drawable = multiLineStringToDrawable(static_cast<OGRMultiLineString*>(ogrFeature->GetGeometryRef()));
451            break;
452
453        case wkbMultiPolygon:
454        case wkbMultiPolygon25D:
455            drawable = multiPolygonToDrawable(static_cast<OGRMultiPolygon*>(ogrFeature->GetGeometryRef()));
456            break;
457
458        case wkbGeometryCollection:
459        case wkbGeometryCollection25D:
460            OSG_WARN << "This geometry is not yet implemented " << OGRGeometryTypeToName(ogrFeature->GetGeometryRef()->getGeometryType()) << std::endl;
461            break;
462
463        case wkbNone:
464            OSG_WARN << "No WKB Geometry " << OGRGeometryTypeToName(ogrFeature->GetGeometryRef()->getGeometryType()) << std::endl;
465            break;
466
467        case wkbUnknown:
468        default:
469            OSG_WARN << "Unknown WKB Geometry " << OGRGeometryTypeToName(ogrFeature->GetGeometryRef()->getGeometryType()) << std::endl;
470            break;
471        }
472
473        if (!drawable)
474            return 0;
475
476        osg::Geode* geode = new osg::Geode();
477        if (disableCulling)
478            geode->setCullingActive(false); // because culling on one points geode is always true, so i disable it
479        geode->addDrawable(drawable);
480        if (useRandomColorByFeature)
481            geode->getOrCreateStateSet()->setAttributeAndModes(createDefaultMaterial(),true);
482        for(int i = 0; i < ogrFeature->GetFieldCount(); i++) {
483            geode->addDescription(std::string(ogrFeature->GetFieldDefnRef(i)->GetNameRef()) + " : " + std::string(ogrFeature->GetFieldAsString(i)));
484        }
485        return geode;
486    }
487
488    mutable OpenThreads::ReentrantMutex _serializerMutex;
489    CPLErrorHandler oldHandler;
490};
491
492// now register with Registry to instantiate the above
493// reader/writer.
494REGISTER_OSGPLUGIN(ogr, ReaderWriterOGR)
Note: See TracBrowser for help on using the browser.