This file is indexed.

/usr/include/simgear/scene/tgdb/SGNodeTriangles.hxx is in libsimgear-dev 3.4.0-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
// future API - just run through once to convert from OSG to SG
// then we can use these triangle lists for random 
// trees/lights/buildings/objects
struct SGTexturedTriangle
{
public:
    std::vector<SGVec3f> vertices;
    std::vector<SGVec2f> texcoords;
};

struct SGBorderContour
{
public:
    SGVec3d start;
    SGVec3d end;
};

class SGTriangleInfo
{
public:
    SGTriangleInfo( const SGVec3d& center ) {
        gbs_center = center;
        mt_init(&seed, 123);
    }

    // API used to build the Info by the visitor
    void addGeometry( osg::Geometry* g ) { 
        geometries.push_back(g); 
    }
    
    void setMaterial( SGMaterial* m ) { 
        mat = m; 
    }

    SGMaterial* getMaterial( void ) const {
        return mat; 
    }
    
    // API used to get a specific texture or effect from a material.  Materials can have
    // multiple textures - use the floor of the x coordinate of the first vertes to select it.
    // This will be constant, and give the same result each time to select one effect/texture per drawable.
    int getTextureIndex( void ) const {
        int texInfo = 0;
        const osg::Vec3Array* vertices =  dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
        if ( vertices ) {
            const osg::Vec3 *v0 = &vertices->operator[](0);
            texInfo = floor(v0->x()); 
        }
        return texInfo;
    }
    
    // new API - TODO
    void getTriangles( std::vector<SGTexturedTriangle>& tris )
    {
        const osg::Vec3Array* vertices  = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
        const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
        
        int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
        if ( numPrimitiveSets > 0 ) {
            const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
            unsigned int numIndices = ps->getNumIndices();
            
            for ( unsigned int i=2; i<numIndices; i+= 3 ) {
                SGTexturedTriangle tri;
                
                tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-2))) );
                tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-1))) );
                tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-0))) );
                
                tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-2))) );
                tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-1))) );
                tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-0))) );
            }
        }
    }
    
    void getBorderContours( std::vector<SGBorderContour>& border )
    {
        // each structure contains a list of target indexes and a count
        int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
        if ( numPrimitiveSets > 0 ) {
            const osg::Vec3Array* vertices  = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());

            const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
            unsigned int numTriangles = ps->getNumIndices()/3;

            // use a map for fast lookup map the segment as a 64 bit int
            std::map<uint64_t, int> segCounter;
            uint32_t idx1, idx2;
            uint64_t key;
            
            for ( unsigned int i=0; i<numTriangles; i+= 3 ) {
                // first seg
                if ( ps->index(i+0) < ps->index(i+1) ) {
                    idx1 = ps->index(i+0);
                    idx2 = ps->index(i+1);
                } else {
                    idx1 = ps->index(i+1);
                    idx2 = ps->index(i+0);                    
                }
                
                key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
                SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
                segCounter[key]++;
                SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
                
                // second seg
                if ( ps->index(i+1) < ps->index(i+2) ) {
                    idx1 = ps->index(i+1);
                    idx2 = ps->index(i+2);
                } else {
                    idx1 = ps->index(i+2);
                    idx2 = ps->index(i+1);             
                }
                
                key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
                SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
                segCounter[key]++;
                SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
                
                // third seg
                if ( ps->index(i+2) < ps->index(i+0) ) {
                    idx1 = ps->index(i+2);
                    idx2 = ps->index(i+0);
                } else {
                    idx1 = ps->index(i+0);
                    idx2 = ps->index(i+2);                    
                }
                
                key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
                SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
                segCounter[key]++;
                SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
            }
            
            // return all segments with count = 1 ( border )
            std::map<uint64_t, int>::iterator segIt = segCounter.begin();            
            while ( segIt != segCounter.end() ) {
                if ( segIt->second == 1 ) {
                    SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << segIt->first << std::dec << " count is " << segIt->second );
                    
                    unsigned int iStart = segIt->first >> 32;
                    unsigned int iEnd   = segIt->first & 0x00000000FFFFFFFF;
                    
                    SGBorderContour bc;
                    
                    bc.start = toVec3d(toSG(vertices->operator[](iStart)));
                    bc.end   = toVec3d(toSG(vertices->operator[](iEnd)));
                    border.push_back( bc );
                }
                segIt++;
            }
            
#if 0
            // debug out - requires GDAL
            //
            //
            //
            SGGeod  geodPos = SGGeod::fromCart(gbs_center);
            SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);

            for ( unsigned int i=0; i<border.size(); i++ ){
                // de-rotate and translate : todo - create a paralell vertex list so we just do this 
                // once per vertex, not for every triangle's use of the vertex
                SGVec3d sgVStart = hlOr.backTransform( border[i].start) + gbs_center;
                SGVec3d sgVEnd   = hlOr.backTransform( border[i].end)   + gbs_center;
                    
                // convert from cartesian to Geodetic, and save as a list of Geods for output
                SGGeod gStart = SGGeod::fromCart(sgVStart);
                SGGeod gEnd   = SGGeod::fromCart(sgVEnd);
                
                SGShapefile::FromSegment( gStart, gEnd, true, "./borders", mat->get_names()[0], "border" );
            }
#endif            
        }
    }
        
    // Random buildings API - get num triangles, then get a triangle at index
    unsigned int getNumTriangles( void ) const {
        unsigned int num_triangles = 0;

        if ( !geometries.empty() ) {
            int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
            if ( numPrimitiveSets > 0 ) {
                const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
                unsigned int numIndices = ps->getNumIndices();
                num_triangles = numIndices/3;
            }
        }
        
        return num_triangles;
    }
    
    void getTriangle(unsigned int i, std::vector<SGVec3f>& triVerts, std::vector<SGVec2f>& triTCs) const {
        const osg::Vec3Array* vertices  = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
        const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));

        if ( !geometries.empty() ) {
            int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
            if ( numPrimitiveSets > 0 ) {
                const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
                int idxStart = i*3;
                
                triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+0))) );
                triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+1))) );
                triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+2))) );
                
                triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+0))) );
                triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+1))) );
                triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+2))) );
            }
        }
    }
    
    // random lights and trees - just get a list of points on where to add the light / tree
    // TODO move this out - and handle in the random light / tree code
    // just use generic triangle API.
    void addRandomSurfacePoints(float coverage, float offset,
                                osg::Texture2D* object_mask,
                                std::vector<SGVec3f>& points)
    {
        if ( !geometries.empty() ) {
            const osg::Vec3Array* vertices  = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
            const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
            
            int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
            if ( numPrimitiveSets > 0 ) {
                const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
                unsigned int numIndices = ps->getNumIndices();
                
                for ( unsigned int i=2; i<numIndices; i+= 3 ) {                    
                    SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
                    SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
                    SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
                    
                    SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
                    SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
                    SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
                    
                    SGVec3f normal = cross(v1 - v0, v2 - v0);
            
                    // Compute the area
                    float area = 0.5f*length(normal);
                    if (area <= SGLimitsf::min())
                        continue;
            
                    // For partial units of area, use a zombie door method to
                    // create the proper random chance of a light being created
                    // for this triangle
                    float unit = area + mt_rand(&seed)*coverage;
            
                    SGVec3f offsetVector = offset*normalize(normal);
                    // generate a light point for each unit of area
            
                    while ( coverage < unit ) {
                        float a = mt_rand(&seed);
                        float b = mt_rand(&seed);
                
                        if ( a + b > 1 ) {
                            a = 1 - a;
                            b = 1 - b;
                        }
                        float c = 1 - a - b;
                        SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
                
                        if (object_mask != NULL) {
                            SGVec2f texCoord = a*t0 + b*t1 + c*t2;
                    
                            // Check this random point against the object mask
                            // red channel.
                            osg::Image* img = object_mask->getImage();            
                            unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
                            unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
                    
                            if (mt_rand(&seed) < img->getColor(x, y).r()) {                
                                points.push_back(randomPoint);        
                            }                    
                        } else {      
                            // No object mask, so simply place the object  
                            points.push_back(randomPoint);        
                        }
                        unit -= coverage;        
                    }
                }
            }
        }
    }
    
    void addRandomTreePoints(float wood_coverage, 
                             osg::Texture2D* object_mask,
                             float vegetation_density,
                             float cos_max_density_angle,
                             float cos_zero_density_angle,
                             std::vector<SGVec3f>& points)
    {
        if ( !geometries.empty() ) {
            const osg::Vec3Array* vertices  = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
            const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
            
            int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
            if ( numPrimitiveSets > 0 ) {
                const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
                unsigned int numIndices = ps->getNumIndices();
                
                for ( unsigned int i=2; i<numIndices; i+= 3 ) {                    
                    SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
                    SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
                    SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
                    
                    SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
                    SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
                    SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
                    
                    SGVec3f normal = cross(v1 - v0, v2 - v0);
            
                    // Ensure the slope isn't too steep by checking the
                    // cos of the angle between the slope normal and the
                    // vertical (conveniently the z-component of the normalized
                    // normal) and values passed in.                   
                    float alpha = normalize(normal).z();
                    float slope_density = 1.0;
            
                    if (alpha < cos_zero_density_angle) 
                        continue; // Too steep for any vegetation      
                        
                    if (alpha < cos_max_density_angle) {
                        slope_density = 
                        (alpha - cos_zero_density_angle) / (cos_max_density_angle - cos_zero_density_angle);
                    }
                    
                    // Compute the area
                    float area = 0.5f*length(normal);
                    if (area <= SGLimitsf::min())
                        continue;
                
                    // Determine the number of trees, taking into account vegetation
                    // density (which is linear) and the slope density factor.
                    // Use a zombie door method to create the proper random chance 
                    // of a tree being created for partial values.
                    int woodcount = (int) (vegetation_density * vegetation_density * 
                    slope_density *
                    area / wood_coverage + mt_rand(&seed));
                    
                    for (int j = 0; j < woodcount; j++) {
                        float a = mt_rand(&seed);
                        float b = mt_rand(&seed);
                        
                        if ( a + b > 1.0f ) {
                            a = 1.0f - a;
                            b = 1.0f - b;
                        }
                        
                        float c = 1.0f - a - b;
                        
                        SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
                        
                        if (object_mask != NULL) {
                            SGVec2f texCoord = a*t0 + b*t1 + c*t2;
                            
                            // Check this random point against the object mask
                            // green (for trees) channel. 
                            osg::Image* img = object_mask->getImage();            
                            unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
                            unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
                            
                            if (mt_rand(&seed) < img->getColor(x, y).g()) {  
                                // The red channel contains the rotation for this object                                  
                                points.push_back(randomPoint);
                            }
                        } else {
                            points.push_back(randomPoint);
                        }                
                    }
                }
            }
        }
    }
    
#if 0    
    // debug : this will save the tile as a shapefile that can be viewed in QGIS.
    // NOTE: this is really slow....
    // remember - we need to de-rotate the tile, then translate back to gbs_center.
    void dumpBorder() {
        //dump the first triangle only of the first geometry, for now...
        SG_LOG(SG_TERRAIN, SG_ALERT, "effect geode has " << geometries.size() << " geometries" );
        
        const osg::Vec3Array* vertices =  dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
        if ( vertices ) {
            SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << vertices->getNumElements() << " vertices" );
        }
        
        if ( !geometries.empty() ) {
            int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
            SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << numPrimitiveSets << " primitive sets" );
            
            if ( numPrimitiveSets > 0 ) {
                const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
                unsigned int numIndices = ps->getNumIndices();

                // create the same quat we used to rotate here 
                // - use backTransform to go back to original node location
                SGGeod  geodPos = SGGeod::fromCart(gbs_center);
                SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
                
                SG_LOG(SG_TERRAIN, SG_ALERT, "  primitive set has has " << numIndices << " indices" );                
                for ( unsigned int i=2; i<numIndices; i+= 3 ) {
                    if ( numIndices >= 3 ) {                    
                        unsigned int v0i = ps->index(i-2);
                        unsigned int v1i = ps->index(i-1);
                        unsigned int v2i = ps->index(i-0);
                    
                        const osg::Vec3 *v0 = &vertices->operator[](v0i);
                        const osg::Vec3 *v1 = &vertices->operator[](v1i);
                        const osg::Vec3 *v2 = &vertices->operator[](v2i);
                   
                        // de-rotate and translate : todo - create a paralell vertex list so we just do this 
                        // once per vertex, not for every triangle's use of the vertex
                        SGVec3d vec0 = hlOr.backTransform( toVec3d(toSG(*v0))) + gbs_center;
                        SGVec3d vec1 = hlOr.backTransform( toVec3d(toSG(*v1))) + gbs_center;
                        SGVec3d vec2 = hlOr.backTransform( toVec3d(toSG(*v2))) + gbs_center;
                    
                        // convert from cartesian to Geodetic, and save as a list of Geods for output
                        std::vector<SGGeod> triangle;
                        triangle.push_back( SGGeod::fromCart(vec0) );
                        triangle.push_back( SGGeod::fromCart(vec1) );
                        triangle.push_back( SGGeod::fromCart(vec2) );
                    
                        SGShapefile::FromGeodList( triangle, true, "./triangles", mat->get_names()[0], "tri" );
                    }
                }
            }            
            
        }
    }
#endif    
    
private:
    mt seed;
    SGMaterial* mat;
    SGVec3d gbs_center;
    std::vector<osg::Geometry*> geometries;
    std::vector<int> polygon_border;    // TODO
};

// This visitor will generate an SGTriangleInfo.
// currently, it looks like it could save multiple lists, which could be the case
// if multiple osg::geods are found with osg::Geometry.
// But right now, we store a single PrimitiveSet under a single EffectGeod.  
// so the traversal should only find a single EffectGeod - building a single SGTriangleInfo
class GetNodeTriangles : public osg::NodeVisitor
{
public:
    GetNodeTriangles(const SGVec3d& c, std::vector<SGTriangleInfo>* nt) : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ), center(c), nodeTris(nt) {}
    
    // This method gets called for every node in the scene
    //   graph. Check each node to see if it has user
    //   out target. If so, save the node's address.
    virtual void apply( osg::Node& node )
    {
        EffectGeode* eg = dynamic_cast<EffectGeode*>(&node);
        if ( eg ) {
            // get the material from the user info
            SGTriangleInfo triInfo( center );
            triInfo.setMaterial( eg->getMaterial() );

            // let's find the drawables for this node
            int numDrawables = eg->getNumDrawables();
            for ( int i=0; i<numDrawables; i++ ) {
                triInfo.addGeometry( eg->getDrawable(i)->asGeometry() );
            }
            
            nodeTris->push_back( triInfo );
        }
        
        // Keep traversing the rest of the scene graph.
        traverse( node );
    }
    
protected:
    SGVec3d                         center;
    std::vector<SGTriangleInfo>*    nodeTris;
};