root/OpenSceneGraph/trunk/examples/osgdelaunay/osgdelaunay.cpp @ 5636

Revision 5636, 62.0 kB (checked in by robert, 8 years ago)

Removed deprecated GUIEventHandler method

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2*
3* This application is open source and may be redistributed and/or modified   
4* freely and without restriction, both in commericial and non commericial applications,
5* as long as this copyright notice is maintained.
6*
7* This application is distributed in the hope that it will be useful,
8* but WITHOUT ANY WARRANTY; without even the implied warranty of
9* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10*/
11
12/** Example of use of delaunay triangulator with constraints.
13* this could be a method of generating terrains, a constraint forces certain edges to
14* exist in the triangulation.
15*/
16
17#include <osgDB/ReadFile>
18#include <osgUtil/Optimizer>
19#include <osgProducer/Viewer>
20#include <osg/CoordinateSystemNode>
21#include <osgUtil/DelaunayTriangulator>
22#include <osg/Material>
23#include <osg/Texture2D>
24#include <osg/Projection>
25#include <osg/MatrixTransform>
26#include <osgUtil/Tesselator> // tesselator triangulates the constrained triangles
27
28#include <osgText/Text>
29#include <sstream>
30
31
32/** here are 2 common types of constraint
33*  Area - forces an area to be filled; replacement geometry is a canopy and optional wall
34*  Linear - constructs a closed loop of constant width around a line.
35*/
36class WallConstraint: public osgUtil::DelaunayConstraint { // forces lines to eb edge
37    // wall constraint - can generate a wall at the coordinates of the constraint
38public:
39/** if you derive a class from DelaunayConstraint then you can create
40*  a specific geometry creation routine.
41    */
42    WallConstraint() : height(0), txxrepWall(10), txyrepWall(10)  { }
43   
44    /** or create a wall around the constraint area: */
45    virtual osg::Geometry * makeWallGeometry(void) const;
46   
47    /** for basic purposes, you can call these routines to make simple fill in geometries */
48    virtual osg::DrawArrays* makeWall(void ) const { // build a wall height high around the constraint
49        const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
50        return (new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_line->size()));
51    }
52   
53   
54    virtual osg::Vec3Array *getWall(const float height) const;
55    virtual osg::Vec2Array *getWallTexcoords(const float height) const;
56    virtual osg::Vec3Array *getWallNormals(void) const {
57        osg::ref_ptr<osg::Vec3Array> nrms=new osg::Vec3Array;
58        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
59        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
60            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
61            if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP ||
62                prset->getMode()==osg::PrimitiveSet::LINE_STRIP) { // loops and walls
63                // start with the last point on the loop
64                osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
65                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
66                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
67                    osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
68                    nrm.normalize();
69                    nrms->push_back(nrm);
70                    nrms->push_back(nrm);
71                    prevp=curp;
72                }
73                const osg::Vec3 curp=(*vertices)[prset->index (0)];
74                osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
75                nrm.normalize();
76                nrms->push_back(nrm);
77                nrms->push_back(nrm);
78            }
79        }
80        return nrms.release();
81    }
82   
83   
84   
85    // geometry creation parameters
86    void setWallTexrep(const float w,const float h) { txxrepWall=w;txyrepWall=h;}
87   
88    /** Wall Geometry will return with this texture applied: */
89    void setTexture(const char *tx) { texture=tx;}
90    /** fence/wall height */
91    void setHeight(const float h) { height=h;}
92protected:
93    float height;
94    std::string texture;
95    float txxrepWall, txyrepWall;
96};
97class ArealConstraint: public osgUtil::DelaunayConstraint { // forces edges of an area to fit triangles
98    // areal constraint - general nonuniform field, forest, lake etc.
99public:
100/** if you derive a class from DelaunayConstraint then you can create
101*  a specific geometry creation routine.
102    */
103    ArealConstraint() : txxrepArea(10), txyrepArea(10),txxrepWall(10), txyrepWall(10) { }
104   
105    /** return a geometry that fills the constraint.
106    */
107    virtual osg::Geometry * makeAreal( osg::Vec3Array *points);
108   
109    /** or create a wall around the constraint area: */
110    virtual osg::Geometry * makeWallGeometry( osg::Vec3Array *points) ;
111   
112    /** for basic purposes, you can call these routines to make simple fill in geometries */
113    virtual osg::DrawArrays* makeWall(void ) const;
114    virtual osg::Vec3Array *getWall(const float height) const;
115    virtual osg::Vec2Array *getWallTexcoords(const float height) const;
116    virtual osg::Vec3Array *getWallNormals(void) const;
117    /** Canopies are the same triangles as the terrain but offset by height above
118    * (height might be 0). */
119    virtual osg::DrawArrays* makeCanopy(void ) const;
120    virtual osg::Vec3Array *getCanopy(const osg::Vec3Array *points,const float height) const;
121    virtual osg::Vec2Array *getCanopyTexcoords(const osg::Vec3Array *points) const;
122    virtual osg::Vec3Array *getCanopyNormals(const osg::Vec3Array *points) const;
123   
124    // geometry creation parameters
125    void setTexrep(const float w,const float h) { txxrepArea=w;txyrepArea=h;}
126    void setWallTexrep(const float w,const float h) { txxrepWall=w;txyrepWall=h;}
127    /** Geometry will return with this texture applied: */
128    void setWallTexture(const char *tx) { walltexture=tx;}
129    /** Geometry will return with this texture applied: */
130    void setTexture(const char *tx) { texture=tx;}
131    /** fence/wall height */
132    void setHeight(const float h) { height=h;}
133    std::string walltexture;
134protected:
135    float height;
136    std::string texture;
137    float txxrepArea, txyrepArea;
138    float txxrepWall, txyrepWall;
139};
140
141class LinearConstraint: public osgUtil::DelaunayConstraint {
142/** forces edges of a "road" to fit triangles
143*  if 2 roads cross, then the overlap will be replaced by a 'cross road'
144    *  and the roads built up to the cross roads with a texture along its length. */
145public:
146    LinearConstraint() : osgUtil::DelaunayConstraint(), txxrepAlong(10), txyrepAcross(10), width(2) { }
147   
148    /** geometry creation parameters */
149    /* Width of linear feature (eg road, railway) */
150    void setWidth(const float w) { width=w;}
151   
152    /** Texture repeat distance across linear (often equal to width) and along its length */
153    virtual void setTexrep(const float w,const float h) { txyrepAcross=h;txxrepAlong=w; }
154   
155    /** generate constant width around line - creates the area to be cut into the terrain. */
156    virtual void setVertices( osg::Vec3Array *lp, const float width);
157   
158    /** return a geometry that fills the constraint.
159    */
160    virtual osg::Geometry *makeGeometry(const osg::Vec3Array *points) ;
161   
162    /** return normals array - flat shaded */
163    osg::Vec3Array* getNormals(const osg::Vec3Array *points);
164   
165    /** Roads apply a texture proportional to length along the road line. */
166    virtual osg::DrawArrays* makeRoad( ) const;
167    virtual osg::Vec3Array *getRoadVertices() const;
168    virtual osg::Vec2Array *getRoadTexcoords(const osg::Vec3Array *points) ;
169   
170    virtual osg::Vec3Array *getRoadNormals(const osg::Vec3Array *points) const;
171    /** Geometry will return with this texture applied: */
172    void setTexture(const char *tx) { texture=tx;}
173   
174protected:
175    osg::ref_ptr<osg::Vec2Array> _tcoords;
176    osg::ref_ptr<osg::Vec3Array> _edgecoords;
177    float txxrepAlong, txyrepAcross;
178    std::string texture;
179    float width; // width of a linear feature
180    osg::ref_ptr<osg::Vec3Array> _midline; // defines the midline of a road, rail etc.
181};
182
183/** a specific type of constaint - that replaces an area with a pyramid */
184
185class pyramid : public osgUtil::DelaunayConstraint {
186/** sample user constriant - creates hole in terrain to fit base of pyramid, and
187    *  geometry of an Egyptian pyramid to fit the hole. */
188public:
189    pyramid() : _side(100.) {}
190   
191    void setpos(const osg::Vec3 p, const float size) { _pos=p;_side=size;}
192   
193    virtual osg::Geometry * makeGeometry(void) const
194        {
195        // create pyramid geometry. Centre plus points around base
196        const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
197        osg::Geometry *gm=new osg::Geometry;
198        osg::Vec3Array *pts=new osg::Vec3Array;
199        osg::Vec3Array *norms=new osg::Vec3Array;
200        osg::Vec2Array *tcoords=new osg::Vec2Array;
201        int ip;
202       
203        pts->push_back(_pos+osg::Vec3(0,0,_side)*0.5);
204        for (ip=0; ip<4; ip++) {
205            pts->push_back((*_line)[ip]);
206        }
207        for (ip=1; ip<5; ip++) {
208            osg::Vec3 nrm=((*pts)[ip]-(*pts)[0])^((*pts)[ip==4?0:ip+1]-(*pts)[ip]);
209            nrm.normalize(  );
210            norms->push_back(nrm);
211        }
212       
213        gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
214        gm->setVertexArray(pts);
215        osg::StateSet *dstate=   gm->getOrCreateStateSet(  );
216        dstate->setMode( GL_LIGHTING, osg::StateAttribute::ON );
217       
218        osg::Image* image = osgDB::readImageFile("Images/Brick-Std-Orange.TGA");
219        if (image)
220        {
221            osg::Texture2D* txt = new osg::Texture2D;
222            txt->setImage(image);
223            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
224            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
225            dstate->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
226        }
227        gm->setNormalArray(norms);
228        ////        gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,0,6));
229        osg::DrawElementsUInt *dui=new osg::DrawElementsUInt(GL_TRIANGLES);
230        for (ip=0; ip<4; ip++) {
231            dui->push_back(0);
232            dui->push_back(ip+1);
233            dui->push_back(ip==3?1:ip+2);
234        }
235        tcoords->push_back(osg::Vec2(2,4));
236        tcoords->push_back(osg::Vec2(0,0));
237        tcoords->push_back(osg::Vec2(4,0));
238        tcoords->push_back(osg::Vec2(0,0));
239        tcoords->push_back(osg::Vec2(4,0));
240        gm->setTexCoordArray(0,tcoords);
241        gm->addPrimitiveSet(dui);
242        return gm;
243    }
244    virtual void calcVertices( void) { // must have a position first
245        osg::Vec3Array *edges=new osg::Vec3Array;
246        osg::Vec3 valong;
247        edges->push_back(_pos+osg::Vec3(0.5,0.5,0)*_side);
248        edges->push_back(_pos+osg::Vec3(-0.5,0.5,0)*_side);
249        edges->push_back(_pos+osg::Vec3(-0.5,-0.5,0)*_side);
250        edges->push_back(_pos+osg::Vec3(0.5,-0.5,0)*_side);
251        setVertexArray(edges);
252    }
253private:
254    osg::Vec3 _pos; // where the pyramid is
255    float _side ; // length of side
256};
257
258float getheight(const float x, const float y)
259{ // returns the x,y,height of terrain
260    return 150*sin(x*.0020)*cos(y*.0020);
261}
262osg::Vec3d getpt(const int np)
263{ // returns the x,y,height of terrain up to maxp^2 points
264    static int maxp =40;
265    int i=np/maxp;
266    int j=np%maxp;
267    // make the random scale 0.00 if you want an equispaced XY grid.
268    float x=3000.0/(maxp-1)*i+16.*(float)rand()/RAND_MAX;
269    float y=3000.0/(maxp-1)*j+16.*(float)rand()/RAND_MAX;
270    float z=getheight(x,y);
271    if (np>=maxp*maxp) z=-1.e32;
272    return osg::Vec3d(x,y,z);
273}
274osg::Node* createHUD(const int ndcs,std::string what)
275{ // add a string reporting the type of winding rule tesselation applied
276    osg::Geode* geode = new osg::Geode();
277   
278    std::string timesFont("fonts/arial.ttf");
279   
280    // turn lighting off for the text and disable depth test to ensure its always ontop.
281    osg::StateSet* stateset = geode->getOrCreateStateSet();
282    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
283   
284    // Disable depth test, and make sure that the hud is drawn after everything
285    // else so that it always appears ontop.
286    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
287    stateset->setRenderBinDetails(11,"RenderBin");
288   
289    osg::Vec3 position(50.0f,900.0f,0.0f);
290    osg::Vec3 delta(0.0f,-35.0f,0.0f);
291   
292    {
293        osgText::Text* text = new  osgText::Text;
294        geode->addDrawable( text );
295        std::ostringstream cue;
296        cue<<"Delaunay triangulation with constraints level "<<ndcs <<"\n"<< what;
297       
298        text->setFont(timesFont);
299        text->setPosition(position);
300        text->setText(cue.str());
301        text->setColor(osg::Vec4(1.0,1.0,0.8,1.0));
302        position += delta*(ndcs+2);
303       
304        text = new  osgText::Text;
305        geode->addDrawable( text );
306       
307        text->setFont(timesFont);
308        text->setPosition(position);
309        text->setText("(use 'W' wireframe & 'T' texture to visualise mesh)");
310        text->setColor(osg::Vec4(1.0,1.0,0.8,1.0));
311        position += delta;
312       
313    }   
314    {
315        osgText::Text* text = new  osgText::Text;
316        geode->addDrawable( text );
317       
318        text->setFont(timesFont);
319        text->setPosition(position);
320        text->setText("Press 'n' to add another constraint.");
321       
322    }   
323   
324    // create the hud.
325    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
326    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
327    modelview_abs->setMatrix(osg::Matrix::identity());
328    modelview_abs->addChild(geode);
329   
330    osg::Projection* projection = new osg::Projection;
331    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
332    projection->addChild(modelview_abs);
333   
334    return projection;
335   
336}
337osg::Group *makedelaunay(const int ndcs)
338{ // create a terrain tile. This is just an example!
339    // ndcs is the number of delaunay constraints to be applied
340    osg::ref_ptr<osg::Group> grp=new osg::Group;
341    osg::ref_ptr<osg::Geode> geode=new osg::Geode;
342    osg::ref_ptr<osgUtil::DelaunayTriangulator> trig=new osgUtil::DelaunayTriangulator();
343    osg::StateSet *stateset=geode->getOrCreateStateSet();
344   
345    osg::Vec3Array *points=new osg::Vec3Array;
346   
347    osg::Image* image = osgDB::readImageFile("Images/blueFlowers.png");
348    if (image)
349    {
350        osg::Texture2D* texture = new osg::Texture2D;
351        texture->setImage(image);
352        texture->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
353        texture->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
354        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
355    }
356   
357    geode->setStateSet( stateset );
358    unsigned int i;
359   
360    int eod=0;
361    while (eod>=0) {
362        osg::Vec3d pos=getpt(eod);
363        if (pos.z()>-10000) {
364            points->push_back(pos);
365            eod++;
366        } else {
367            eod=-9999;
368        }
369    }
370    std::vector < pyramid* > pyrlist;
371    osg::ref_ptr<WallConstraint> wc; // This example does not remove the interior
372    osg::ref_ptr<ArealConstraint> dc2;
373    osg::ref_ptr<ArealConstraint> forest;
374    osg::ref_ptr<LinearConstraint> dc3;
375    osg::ref_ptr<LinearConstraint> dc6;
376    osg::ref_ptr<LinearConstraint> dc6a;
377    osg::ref_ptr<LinearConstraint> dc8;
378    osg::ref_ptr<LinearConstraint> forestroad;
379    osg::ref_ptr<LinearConstraint> forestroad2;
380    osg::ref_ptr<LinearConstraint> forestroad3;
381    osg::ref_ptr<osgUtil::DelaunayConstraint> dc;
382    std::ostringstream what;
383    if (1==0) { // add a simple constraint of few points
384        osg::ref_ptr<osgUtil::DelaunayConstraint> dc=new osgUtil::DelaunayConstraint;
385        osg::Vec3Array *bounds=new osg::Vec3Array;
386        unsigned int nmax=4;
387        for (i=0 ; i<nmax; i++) {
388            float x=910.0+800.0*(i)/(float)nmax,y=810.0+6000*(i-1)*(i-1)/(float)(nmax*nmax);
389            bounds->push_back(osg::Vec3(x,y,getheight(x,y)));
390        }
391        dc->setVertexArray(bounds);
392        dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,nmax) );
393       
394        trig->addInputConstraint(dc.get());
395        what << nmax << " point simple constraint\n";
396    }
397    if (ndcs>0) { // add 5 pyramids
398        for (unsigned int ipy=0; ipy<5/*5*/; ipy++) {
399            osg::ref_ptr<pyramid> pyr=new pyramid;
400            float x=2210+ipy*120, y=1120+ipy*220;
401            pyr->setpos(osg::Vec3(x,y,getheight(x,y)),125.0+10*ipy);
402            pyr->calcVertices(); // make vertices
403            pyr->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4) );
404            trig->addInputConstraint(pyr.get());
405            pyrlist.push_back(pyr.get());
406        }
407        what << 5 << " pyramids\n";
408        if (ndcs>1) {
409            // add a simple constraint feature - this can cut holes in the terrain or just leave the triangles
410            // with edges forced to the constraint.
411            dc=new osgUtil::DelaunayConstraint;
412            osg::Vec3Array *bounds=new osg::Vec3Array;
413            for (i=0 ; i<12; i++) {
414                float x=610.0+420*sin(i/3.0),y=610.0+420*cos(i/3.0);
415                bounds->push_back(osg::Vec3(x,y,getheight(x,y)));
416            }
417            dc->setVertexArray(bounds);
418            dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,12) );
419           
420            trig->addInputConstraint(dc.get());
421            what << 12 << " point closed loop";
422           
423            if (ndcs>2) {
424                wc=new WallConstraint; // This example does not remove the interior
425                // eg to force terrain edges that are on ridges in the terrain etc.
426                // use wireframe to see the constrained edges.
427                // NB this is not necessarily a closed loop of edges.
428                // we do however build a wall at the coordinates.
429                bounds=new osg::Vec3Array;
430                for (i=0 ; i<5; i++) {
431                    float x=1610.0+420*sin(i/1.0),y=1610.0+420*cos(i/1.0);
432                    bounds->push_back(osg::Vec3(x,y,getheight(x,y)));
433                }
434                wc->setVertexArray(bounds);
435                wc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,5) );
436                wc->setHeight(12.0);
437                trig->addInputConstraint(wc.get());
438                what << " with interior removed\n";
439                what << 5 << " point wall derived constraint\n";
440               
441                if (ndcs>3) {
442                    // add a removed area and replace it with a different texture
443                    dc2=new ArealConstraint;
444                    bounds=new osg::Vec3Array;
445                    for (i=0 ; i<18; i++) {
446                        float x=1610.0+420*sin(i/3.0),y=610.0+220*cos(i/3.0);
447                        bounds->push_back(osg::Vec3(x,y,getheight(x,y)));
448                    }
449                    dc2->setVertexArray(bounds);
450                    dc2->setTexrep(100,100); // texture is repeated at this frequency
451                    dc2->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,18) );
452                    trig->addInputConstraint(dc2.get());
453                    what << 18 << " point area replaced\n";
454                   
455                    if (ndcs>4) {
456                        dc3=new LinearConstraint;
457                        // a linear feature or 'road'
458                        osg::Vec3Array *verts=new osg::Vec3Array;
459                        for (i=0 ; i<32; i++) {
460                            float x=610.0+50*i+90*sin(i/5.0),y=1110.0+90*cos(i/5.0);
461                            verts->push_back(osg::Vec3(x,y,getheight(x,y)));
462                        }
463                        dc3->setVertices(verts,9.5); // width of road
464                        for (osg::Vec3Array::iterator vit=points->begin(); vit!=points->end(); ) {
465                            if (dc3->contains(*vit)) {
466                                vit=points->erase(vit);
467                            } else {
468                                vit++;
469                            }
470                        }
471                        trig->addInputConstraint(dc3.get());
472                        what << 32 << " point road constraint\n";
473                        if (ndcs>5) {
474                            // add a removed area and replace it with a 'forest' with textured roof and walls
475                            forest=new ArealConstraint;
476                            bounds=new osg::Vec3Array;
477                            for (i=0 ; i<12; i++) {
478                                float x=610.0+420*sin(i/2.0),y=1810.0+420*cos(i/2.0);
479                                bounds->push_back(osg::Vec3(x,y,getheight(x,y)));
480                            }
481                            forest->setVertexArray(bounds);
482                            forest->setHeight(50);
483                            forest->setWallTexrep(100,50);
484                            forest->setTexrep(100,100); // texture is repeated at this frequency
485                            forest->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,12) );
486                            if (ndcs==6) trig->addInputConstraint(forest.get());
487                            what << 12 << " point forest constraint\n";
488                           
489                            if (ndcs>6) { // add roads that intersect forest
490                                osg::ref_ptr<osgUtil::DelaunayConstraint> forestplus=new osgUtil::DelaunayConstraint;
491                                forestroad=new LinearConstraint;
492                                verts=new osg::Vec3Array;
493                                for (i=0 ; i<12; i++) {
494                                    int ip=(i-6)*(i-6);
495                                    float xp=410.0+20.0*ip;
496                                    float y=1210.0+150*i;
497                                    verts->push_back(osg::Vec3(xp,y,getheight(xp,y)));
498                                }
499                                forestroad->setVertices(verts,22); // add road
500                                forestplus->merge(forestroad.get());
501                                forestroad2=new LinearConstraint;
502                                verts=new osg::Vec3Array;
503                                for (i=0 ; i<12; i++) {
504                                    int ip=(i-6)*(i-6);
505                                    float xp=810.0-10.0*ip;
506                                    float y=1010.0+150*i;
507                                    verts->push_back(osg::Vec3(xp,y,getheight(xp,y)));
508                                }
509                                forestroad2->setVertices(verts,22); // add road
510                                forestplus->merge(forestroad2.get());
511                                forestroad3=new LinearConstraint;
512                                verts=new osg::Vec3Array;
513                                for (i=0 ; i<6; i++) {
514                                    int ip=(i-6)*(i-6);
515                                    float xp=210.0+140.0*i+ip*10.0;
516                                    float y=1510.0+150*i;
517                                    verts->push_back(osg::Vec3(xp,y,getheight(xp,y)));
518                                }
519                                forestroad3->setVertices(verts,22); // add road
520                                forestplus->merge(forestroad3.get());
521                                forestplus->merge(forest.get());
522                                forestplus->handleOverlaps();
523                                for (osg::Vec3Array::iterator vit=points->begin(); vit!=points->end(); ) {
524                                    if (forestroad->contains(*vit)) {
525                                        vit=points->erase(vit);
526                                    } else if (forestroad2->contains(*vit)) {
527                                        vit=points->erase(vit);
528                                    } else if (forestroad3->contains(*vit)) {
529                                        vit=points->erase(vit);
530                                    } else {
531                                        vit++;
532                                    }
533                                }
534                                trig->addInputConstraint(forestplus.get());
535                                what << " roads intersect forest constraint\n";
536                                if (ndcs>7) {
537                                    // this option adds a more complex DC
538                                    // made of several (ok 2 - extend your own way) overlapping DC's
539                                    osg::ref_ptr<osgUtil::DelaunayConstraint> dcoverlap=new osgUtil::DelaunayConstraint;
540                                    float x=1200; float y=1900;
541                                    {
542                                        verts=new osg::Vec3Array;
543                                        dc6=new LinearConstraint;
544                                        verts->push_back(osg::Vec3(x-180,y,getheight(x-180,y)));
545                                        verts->push_back(osg::Vec3(x+180,y,getheight(x+180,y)));
546                                        dc6->setVertices(verts,22); // width of road
547                                        dcoverlap->merge(dc6.get());
548                                    }
549                                    {
550                                        dc6a= new LinearConstraint;
551                                        verts=new osg::Vec3Array;
552                                        verts->push_back(osg::Vec3(x,y-180,getheight(x,y-180)));
553                                        verts->push_back(osg::Vec3(x-20,y,getheight(x,y)));
554                                        verts->push_back(osg::Vec3(x,y+180,getheight(x,y+180)));
555                                        dc6a->setVertices(verts,22); // width of road
556                                        dcoverlap->merge(dc6a.get());
557                                    }
558                                    what << "2 intersecting roads, with added points\n";
559                                    if (ndcs>9) {
560                                        // add yet more roads
561                                        dc8= new LinearConstraint;
562                                        verts=new osg::Vec3Array;
563                                        float rad=60.0;
564                                        for (float theta=0; theta<4*osg::PI; theta+=0.1*osg::PI) {
565                                            float xp=x+rad*cos(theta), yp=y+rad*sin(theta);
566                                            verts->push_back(osg::Vec3(xp,yp,getheight(xp,yp)));
567                                            rad+=2.5;
568                                        }
569                                        dc8->setVertices(verts,16); // width of road
570                                        dcoverlap->merge(dc8.get());
571                                        what << "Spiral road crosses several other constraints.";
572                                    }
573                                    dcoverlap->handleOverlaps();
574                                    if (ndcs>8) {
575                                        // remove vertices cleans up the texturing at the intersection.
576                                        dcoverlap->removeVerticesInside(dc6.get());
577                                        dcoverlap->removeVerticesInside(dc6a.get());
578                                        if (dc8.valid()) dcoverlap->removeVerticesInside(dc8.get());
579                                        what << "    remove internal vertices to improve texturing.";
580                                    }
581                                    for (osg::Vec3Array::iterator vit=points->begin(); vit!=points->end(); ) {
582                                        if (dcoverlap->contains(*vit)) {
583                                            vit=points->erase(vit);
584                                        } else {
585                                            vit++;
586                                        }
587                                    }
588                                    trig->addInputConstraint(dcoverlap.get());
589                                }
590                            }
591                        }
592                    }
593                }
594            }
595        }
596    } // ndcs>0
597    trig->setInputPointArray(points);
598   
599    /** NB you need to supply a vec3 array for the triangulator to calculate normals into */
600    osg::Vec3Array *norms=new osg::Vec3Array;
601    trig->setOutputNormalArray(norms);
602   
603    trig->triangulate();
604    osg::notify(osg::WARN) << " End of trig\n " <<std::endl;
605   
606    // Calculate the texture coordinates after triangulation as
607    //the points may get disordered by the triangulate function
608    osg::ref_ptr<osg::Geometry> gm=new osg::Geometry;
609    gm->setVertexArray(points); // points may have been modified in order by triangulation.
610    /** calculate texture coords for terrain points */
611    if (image) {
612        float repeat=150.0, ry=150.0; // how often to repeat texture
613        osg::Vec2Array *tcoords=new osg::Vec2Array;
614        for (osg::Vec3Array::iterator itr=points->begin(); itr!=points->end(); itr++) {
615            osg::Vec2 tcatxy((*itr).x()/repeat,(*itr).y()/ry);
616            tcoords->push_back(tcatxy);
617        }
618        gm->setTexCoordArray(0,tcoords);
619    }
620    gm->addPrimitiveSet(trig->getTriangles());
621    gm->setNormalArray(trig->getOutputNormalArray());
622    gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
623    geode->addDrawable(gm.get());
624    if (ndcs>0) {
625        for ( std::vector < pyramid* >::iterator itr=pyrlist.begin(); itr!=pyrlist.end(); itr++) {
626            trig->removeInternalTriangles(*itr);
627            geode->addDrawable((*itr)->makeGeometry()); // this fills the holes of each pyramid with geometry
628        }
629       
630        if (ndcs>2) {
631            trig->removeInternalTriangles(dc.get());
632           
633            wc->setTexture("Images/Brick-Norman-Brown.TGA"); // wall looks like brick
634            geode->addDrawable(wc->makeWallGeometry()); // this creates wall at wc drawarrays
635            if (ndcs>3) {
636                trig->removeInternalTriangles(dc2.get());
637                osg::ref_ptr<osg::Vec3Array> arpts=dc2->getPoints(points);
638                dc2->setTexture("Images/purpleFlowers.png");
639                geode->addDrawable(dc2->makeAreal(arpts.get())); // this creates fill in geometry
640               
641                if (ndcs>4) { // a simple "road"
642                    trig->removeInternalTriangles(dc3.get());
643                    dc3->setTexture ("Images/road.png");
644                    dc3->setTexrep(40,9.5); // texture is repeated at this frequency
645                    geode->addDrawable(dc3->makeGeometry(points)); // this creates road geometry
646                   
647                    if (ndcs>5) {
648                        if (ndcs>6) { //  road & forest overlap - order of removal is important
649                            trig->removeInternalTriangles(forestroad.get());
650                            trig->removeInternalTriangles(forestroad2.get());
651                            trig->removeInternalTriangles(forestroad3.get());
652                        }
653                        trig->removeInternalTriangles(forest.get());
654                        forest->setTexture("Images/forestRoof.png");
655                        osg::ref_ptr<osg::Vec3Array> locpts=forest->getPoints(points);
656                        geode->addDrawable(forest->makeAreal(locpts.get()));
657
658                        forest->setWallTexture("Images/forestWall.png");
659                        geode->addDrawable(forest->makeWallGeometry(locpts.get()) );
660                        for (osg::Vec3Array::iterator vit=(*locpts).begin(); vit!=(*locpts).end(); vit++) {
661                            (*vit)+=osg::Vec3(0,0,30);
662                        }
663
664                        if (ndcs>6) {//  road & forest overlap
665                            forestroad->setTexture ("Images/road.png");
666                            forestroad->setTexrep(40,22); // texture is repeated at this frequency
667                            geode->addDrawable(forestroad->makeGeometry(points)); // this creates road geometry
668                            forestroad2->setTexture ("Images/road.png");
669                            forestroad2->setTexrep(40,22); // texture is repeated at this frequency
670                            geode->addDrawable(forestroad2->makeGeometry(points)); // this creates road geometry
671                            forestroad3->setTexture ("Images/road.png");
672                            forestroad3->setTexrep(40,22); // texture is repeated at this frequency
673                            geode->addDrawable(forestroad3->makeGeometry(points)); // this creates road geometry
674                            if (ndcs>7) {//  several overlapping DC's - add geom
675                                trig->removeInternalTriangles(dc6.get());
676                                //                            dc6->makeDrawable();
677                                //                            dc6a->makeDrawable();
678                                dc6->setTexture ("Images/road.png");
679                                dc6->setTexrep(40,22); // texture is repeated at this frequency
680                                geode->addDrawable(dc6->makeGeometry(points)); // this creates road geometry
681                                trig->removeInternalTriangles(dc6a.get());
682                                dc6a->setTexture ("Images/road.png");
683                                dc6a->setTexrep(40,22); // texture is repeated at this frequency
684                                geode->addDrawable(dc6a->makeGeometry(points)); // this creates road geometry
685                                if (dc8.valid()) {
686                                    trig->removeInternalTriangles(dc8.get());
687                                    dc8->setTexture ("Images/road.png");
688                                    dc8->setTexrep(40,16); // texture is repeated at this frequency
689                                    geode->addDrawable(dc8->makeGeometry(points)); // this creates road geometry
690                                }
691                            }
692                        }
693                    }
694                }
695            }
696        }
697    }
698    grp->addChild(geode.get());
699    grp->addChild(createHUD(ndcs,what.str()));
700    return grp.release();
701}
702
703class KeyboardEventHandler : public osgGA::GUIEventHandler
704{ // extra event handler traps 'n' key to re-triangulate the basic terrain.
705public:
706   
707    KeyboardEventHandler(osg::Node *nd,osgProducer::Viewer &vr):
708      _scene(nd), viewer(vr), iview(0) {}
709     
710      virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
711      {
712          switch(ea.getEventType())
713          {
714          case(osgGA::GUIEventAdapter::KEYDOWN):
715              {
716                  if (_scene && ea.getKey()=='n')
717                  {
718                      // re-tesselate the scene graph.
719                      // the same contours are re-tesselated using a new method. Old contours
720                      // & tesselation type are held internally in the derived Geode class tesselateDemoGeometry.
721                      //     cxTesselateVisitor tsv;
722                      //   _scene->accept(tsv);
723                      iview++;
724                      if (iview>10) iview=0;
725                      osg::ref_ptr<osg::Node> loadedModel = makedelaunay(iview);
726                      viewer.setSceneData(loadedModel.get());
727                      return true;
728                  }
729                  break;
730              }
731          default:
732              break;
733          }
734          return false;
735      }
736     
737      osg::Node *_scene;
738      osgProducer::Viewer &viewer;
739      int iview;
740};
741
742osg::Vec3Array * WallConstraint::getWall(const float height) const
743{ // return array of points for a wall height high around the constraint
744    osg::Vec3Array *wall=new osg::Vec3Array;
745    if (height>0.0) {
746        osg::Vec3 off(0,0,height);
747        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
748        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
749            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
750            if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP ||
751                prset->getMode()==osg::PrimitiveSet::LINE_STRIP) { // nothing else loops
752                // start with the last point on the loop
753                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
754                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
755                    wall->push_back(curp);
756                    wall->push_back(curp+off);
757                }
758                const osg::Vec3 curp=(*vertices)[prset->index (0)];
759                wall->push_back(curp);
760                wall->push_back(curp+off);
761            }
762        }
763    }
764    return wall;
765}
766osg::Vec2Array * WallConstraint::getWallTexcoords(const float height) const
767{ // return array of points for a wall height high around the constraint
768    osg::Vec2Array *tcoords= NULL;
769    if (height>0.0) {
770        float texrepRound=txxrepWall;
771        tcoords= new osg::Vec2Array;
772        float circumference=0; // distance around wall to get exact number of repeats of texture
773        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
774        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
775            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
776            osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
777                        unsigned int i;
778            for (i=0; i<prset->getNumIndices(); i++) {
779                const osg::Vec3 curp=(*vertices)[prset->index (i)];
780                circumference+=(curp-prevp).length();
781                prevp=curp;
782            }
783            const osg::Vec3 curp=(*vertices)[prset->index (0)];
784            circumference+=(curp-prevp).length();
785           
786            int nround=(int)(circumference/txxrepWall);
787            if (nround<1) nround=1; // at least one repeat.
788            texrepRound=circumference/nround;
789           
790            float ds=0;
791            prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
792            if (tcoords) {
793                for (i=0; i<prset->getNumIndices(); i++) {
794                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
795                    osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
796                    tcoords->push_back(tci);
797                    tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
798                    tcoords->push_back(tci);
799                    ds+=(curp-prevp).length();
800                    prevp=curp;
801                }
802                osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
803                tcoords->push_back(tci);
804                tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
805                tcoords->push_back(tci);
806            }
807        } // per primitiveset
808       
809    }
810    return tcoords;
811}
812osg::Geometry *WallConstraint::makeWallGeometry() const
813{
814    osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall
815    if (texture!="") {
816        osg::Image* image = osgDB::readImageFile(texture.c_str());
817        if (image)
818        {
819            osg::Texture2D* txt = new osg::Texture2D;
820            osg::StateSet* stateset = gm->getOrCreateStateSet();
821            txt->setImage(image);
822            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
823            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
824            stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
825            osg::Material* material = new osg::Material;
826            material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,0.0f,1.0f));
827            material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
828            stateset->setAttribute(material,osg::StateAttribute::ON);
829            stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
830        }
831    }
832    gm->setVertexArray(getWall(height));
833    gm->addPrimitiveSet(makeWall());
834    gm->setTexCoordArray(0,getWallTexcoords(height));
835    gm->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
836    gm->setNormalArray(getWallNormals()); // this creates normals to walls
837   
838    return gm.release();
839}
840
841osg::Vec3Array *ArealConstraint::getWallNormals() const
842{
843    osg::Vec3Array *nrms=new osg::Vec3Array;
844    const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
845    for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
846        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
847        if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
848            // start with the last point on the loop
849            osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
850            for (unsigned int i=0; i<prset->getNumIndices(); i++) {
851                const osg::Vec3 curp=(*vertices)[prset->index (i)];
852                osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
853                nrm.normalize();
854                nrms->push_back(nrm);
855                nrms->push_back(nrm);
856                prevp=curp;
857            }
858            const osg::Vec3 curp=(*vertices)[prset->index (0)];
859            osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
860            nrm.normalize();
861            nrms->push_back(nrm);
862            nrms->push_back(nrm);
863        }
864    }
865    return nrms;
866}
867
868
869osg::Vec3Array * ArealConstraint::getWall(const float height) const
870{ // return array of points for a wall height high around the constraint
871    osg::Vec3Array *wall=new osg::Vec3Array;
872    if (height>0.0) {
873        osg::Vec3 off(0,0,height);
874        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
875        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
876            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
877            if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
878                // start with the last point on the loop
879                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
880                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
881                    wall->push_back(curp);
882                    wall->push_back(curp+off);
883                }
884                const osg::Vec3 curp=(*vertices)[prset->index (0)];
885                wall->push_back(curp);
886                wall->push_back(curp+off);
887            }
888        }
889    }
890    return wall;
891}
892
893osg::Vec2Array * ArealConstraint::getWallTexcoords(const float height) const
894{ // return array of points for a wall height high around the constraint
895    osg::Vec2Array *tcoords= NULL;
896    if (height>0.0) {
897        float texrepRound=txxrepWall;
898        tcoords= new osg::Vec2Array;
899        float circumference=0; // distance around wall to get exact number of repeats of texture
900        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
901        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
902            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
903            osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
904                        unsigned int i;
905            for (i=0; i<prset->getNumIndices(); i++) {
906                const osg::Vec3 curp=(*vertices)[prset->index (i)];
907                circumference+=(curp-prevp).length();
908                prevp=curp;
909            }
910            const osg::Vec3 curp=(*vertices)[prset->index (0)];
911            circumference+=(curp-prevp).length();
912           
913            int nround=(int)(circumference/txxrepWall);
914            if (nround<1) nround=1; // at least one repeat.
915            texrepRound=circumference/nround;
916           
917            float ds=0;
918            prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
919            if (tcoords) {
920                for (i=0; i<prset->getNumIndices(); i++) {
921                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
922                    osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
923                    tcoords->push_back(tci);
924                    tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
925                    tcoords->push_back(tci);
926                    ds+=(curp-prevp).length();
927                    prevp=curp;
928                }
929                osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
930                tcoords->push_back(tci);
931                tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
932                tcoords->push_back(tci);
933            }
934        } // per primitiveset
935    }
936    return tcoords;
937}
938osg::DrawArrays* ArealConstraint::makeCanopy( void ) const
939{
940    return (new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,3*_interiorTris.size()));
941}
942osg::Vec3Array *ArealConstraint::getCanopy(const osg::Vec3Array *points,const float height) const
943{ // returns the array of vertices in the canopy
944    osg::Vec3 off(0,0,height);
945    osg::Vec3Array *internals=new osg::Vec3Array;
946    trilist::const_iterator tritr;
947    for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
948        for (int i=0; i<3; i++) {
949            int index=(*tritr)[i];
950            internals->push_back((*points)[index]+off);
951        }
952    }
953    return internals;
954}
955osg::Vec3Array *ArealConstraint::getCanopyNormals(const osg::Vec3Array *points) const
956{
957    osg::Vec3Array *nrms=new osg::Vec3Array;
958    trilist::const_iterator tritr;
959    for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
960        osg::Vec3 e1=(*points)[(*tritr)[1]]-(*points)[(*tritr)[0]];
961        osg::Vec3 e2=(*points)[(*tritr)[2]]-(*points)[(*tritr)[0]];
962        osg::Vec3 nrm=e1^e2;
963        nrm.normalize();
964        nrms->push_back(nrm);
965    }
966    return nrms;
967}
968
969osg::Vec2Array *ArealConstraint::getCanopyTexcoords(const osg::Vec3Array *points) const
970{
971    osg::Vec3Array::const_iterator tritr;
972    osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
973    for (tritr=points->begin(); tritr!=points->end();tritr++) {
974                // calculate tcoords for terrain from xy drape.
975        osg::Vec2 tci=osg::Vec2f(tritr->x()/txxrepArea, tritr->y()/txyrepArea);
976        tcoords->push_back(tci);
977    }
978    return tcoords.release();
979}
980
981osg::DrawArrays * ArealConstraint::makeWall(void) const
982{ // build a wall height high around the constraint
983    const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
984    return (new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2+2*_line->size()));
985}
986
987osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt)
988{
989    osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall
990    osg::ref_ptr<osg::Geometry> edges=new osg::Geometry; // edges of bounds
991    edges->setVertexArray(pt);
992    osg::DrawElementsUInt *trgeom=getTriangles();
993    edges->addPrimitiveSet(trgeom);
994   
995    osg::ref_ptr<osgUtil::Tesselator> tscx=new osgUtil::Tesselator; // this assembles all the constraints
996    tscx->setTesselationType(osgUtil::Tesselator::TESS_TYPE_GEOMETRY);
997    tscx->setBoundaryOnly(true);
998    tscx->setWindingType( osgUtil::Tesselator::TESS_WINDING_NONZERO);
999    //  find all edges.
1000    const osg::Vec3Array *points=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1001   
1002    tscx->retesselatePolygons(*(edges)); // find all edges
1003   
1004    if (walltexture!="") {
1005        osg::Image* image = osgDB::readImageFile(walltexture.c_str());
1006        if (image)
1007        {
1008            osg::Texture2D* txt = new osg::Texture2D;
1009            osg::StateSet* stateset = gm->getOrCreateStateSet();
1010            txt->setImage(image);
1011            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1012            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
1013            stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1014        }
1015    }
1016    points=dynamic_cast<osg::Vec3Array*>(edges->getVertexArray());
1017    int nstart=0;
1018    osg::ref_ptr<osg::Vec3Array> coords=new osg::Vec3Array;
1019    osg::ref_ptr<osg::Vec2Array> tcoords=new osg::Vec2Array;
1020    for (unsigned int i=0; i<edges->getNumPrimitiveSets(); i++) {
1021        osg::PrimitiveSet *pr=edges->getPrimitiveSet(i);
1022        if (pr->getMode() == osg::PrimitiveSet::LINE_LOOP) {
1023            float ds=0;
1024            for (unsigned int icon=0; icon<pr->getNumIndices(); icon++) {
1025                unsigned int ithis=pr->index(icon);
1026                osg::Vec3 pt=                (*points)[ithis];
1027                coords->push_back(pt);
1028                coords->push_back(pt+osg::Vec3(0,0,height));
1029                tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1030                tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1031                if (icon<pr->getNumIndices()-1) ds+=((*points)[pr->index(icon+1)]-(*points)[ithis]).length();
1032                else ds+=((*points)[pr->index(0)]-(*points)[ithis]).length();
1033            }
1034            // repeat first point
1035            unsigned int ithis=pr->index(0);
1036            coords->push_back((*points)[ithis]);
1037            coords->push_back((*points)[ithis]+osg::Vec3(0,0,height));
1038            tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1039            tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1040            gm->setVertexArray(coords.get());
1041            gm->setTexCoordArray(0,tcoords.get());
1042            gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nstart,2+2*pr->getNumIndices()));
1043            nstart+=2+2*pr->getNumIndices();
1044        }
1045    }
1046   
1047    return gm.release();
1048}
1049
1050
1051osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points)
1052{
1053    osg::ref_ptr<osg::Geometry> gm; // the fill in area
1054    if (_interiorTris.size()>0) {
1055        gm =new osg::Geometry; // the forest roof
1056        gm->setVertexArray(points);
1057        osg::DrawElementsUInt *trgeom=getTriangles();
1058        gm->addPrimitiveSet(trgeom);
1059        gm->setNormalArray(getCanopyNormals(points));
1060        gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
1061        gm->setTexCoordArray(0,getCanopyTexcoords(points));
1062        osg::Image* image = osgDB::readImageFile(texture);
1063        if (image)
1064        {
1065            osg::Texture2D* txt = new osg::Texture2D;
1066            osg::StateSet* stateset = gm->getOrCreateStateSet();
1067            txt->setImage(image);
1068            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1069            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1070            stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1071            osg::Material* material = new osg::Material;
1072            material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1073            material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1074            stateset->setAttribute(material,osg::StateAttribute::ON);
1075            stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1076        }
1077    }
1078    return gm.release();
1079}
1080
1081
1082void LinearConstraint::setVertices( osg::Vec3Array *lp, const float w)
1083{ // generate constant width around line (calls setvertices(edges))
1084    osg::ref_ptr<osg::Vec3Array> edges=new osg::Vec3Array;
1085    _tcoords=new osg::Vec2Array; // texture coordinates for replacement geometry
1086    _edgecoords=new osg::Vec3Array; // posiiton coordinates for replacement geometry
1087    width=w;
1088    _midline=lp;
1089    float ds=0;
1090    for(unsigned int i=0;i<lp->size();i++) {
1091        osg::Vec3 valong;
1092        osg::Vec3 pos[2];
1093       
1094        if (i==0) {
1095            valong=(*lp)[i+1]-(*lp)[i];
1096        } else if (i==lp->size()-1) {
1097            valong=(*lp)[i]-(*lp)[i-1];
1098        } else {
1099            valong=(*lp)[i+1]-(*lp)[i-1];
1100        }
1101        valong.normalize();
1102        osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1103        pos[0]=(*lp)[i]-vperp*.5*width;
1104        pos[1]=(*lp)[i]+vperp*.5*width;
1105        edges->push_back(pos[0]);
1106        _edgecoords->push_back(pos[0]);
1107        _tcoords->push_back(osg::Vec2(0/txyrepAcross,ds/txxrepAlong));
1108        edges->insert(edges->begin() ,pos[1]);
1109        _edgecoords->insert(_edgecoords->begin() ,pos[1]);
1110        _tcoords->insert(_tcoords->begin() ,osg::Vec2(width/txyrepAcross,ds/txxrepAlong));
1111        if (i<lp->size()-1) ds+=((*lp)[i+1]-(*lp)[i]).length();
1112    }
1113    setVertexArray(edges.get());
1114    addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,edges->size()) );
1115}
1116
1117osg::DrawArrays* LinearConstraint::makeRoad(void ) const
1118{
1119    return     new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_midline->size());
1120   
1121}
1122
1123osg::Vec3Array *LinearConstraint::getRoadNormals(const osg::Vec3Array* /*points*/) const
1124{
1125    osg::Vec3Array *nrms=new osg::Vec3Array;
1126    for(unsigned int i=0;i<_midline->size();i++) {
1127        osg::Vec3 valong; // vector along midline of road
1128        if (i==0) {
1129            valong=(*_midline)[i+1]-(*_midline)[i];
1130        } else if (i==_midline->size()-1) {
1131            valong=(*_midline)[i]-(*_midline)[i-1];
1132        } else {
1133            valong=(*_midline)[i+1]-(*_midline)[i-1];
1134        }
1135        osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1136        osg::Vec3 nrm=vperp^valong; // normal to linear
1137        nrm.normalize();
1138        nrms->push_back(nrm); // repeated for each vertex of linear.
1139        nrms->push_back(nrm);
1140    }
1141    return nrms;
1142}
1143osg::Vec3Array *LinearConstraint::getRoadVertices() const
1144{
1145    osg::Vec3Array *linearEdges=new osg::Vec3Array;
1146    for(unsigned int i=0;i<_midline->size();i++) {
1147        osg::Vec3 valong; // vector along midline of road
1148        if (i==0) {
1149            valong=(*_midline)[i+1]-(*_midline)[i];
1150        } else if (i==_midline->size()-1) {
1151            valong=(*_midline)[i]-(*_midline)[i-1];
1152        } else {
1153            valong=(*_midline)[i+1]-(*_midline)[i-1];
1154        }
1155        valong.normalize();
1156        osg::Vec3 vperp=valong^osg::Vec3(0,0,1); // vector across road
1157        // sides of linear
1158        linearEdges->push_back((*_midline)[i]-vperp*.5*width);
1159        linearEdges->push_back((*_midline)[i]+vperp*.5*width);
1160    }
1161    return linearEdges;
1162}
1163
1164osg::Vec2Array *LinearConstraint::getRoadTexcoords(const osg::Vec3Array *points)  {
1165    // need to create a vec2 array from the coordinates that fits the road
1166    osg::Vec3Array::const_iterator tritr;
1167    osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
1168    for (tritr=points->begin(); tritr!=points->end();tritr++) {
1169        osg::Vec2 tci(-1.,-1.);
1170        int ib=0;
1171        // osg::Vec3Array *varr=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1172        bool ptfound=false;
1173        for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() && !ptfound; vit++) {
1174            if ((*vit)==(*tritr)) {
1175                tci=_tcoords->at(ib);
1176                ptfound=true;
1177            }
1178            ib++;
1179        }
1180        if (!ptfound) { // search for surrounding points and interpolate
1181            ib=0;
1182            osg::Vec3 pminus=(_edgecoords->back()); // need pminus for interpolation
1183            int ibm1=_edgecoords->size()-1;
1184            for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() /*&& !ptfound*/; vit++) {
1185                osg::Vec3 pplus=(*vit)-(*tritr);
1186                osg::Vec3 dpm=pminus-(*tritr);
1187                pplus.set (pplus.x(),pplus.y(),0);
1188                dpm.set (dpm.x(),dpm.y(),0);
1189                float dprod=pplus*dpm/(pplus.length() * dpm.length());
1190                if (dprod<-0.9999) { // *tritr lies between....
1191                    osg::Vec2 tminus=_tcoords->at(ibm1);
1192                    osg::Vec2 tplus=_tcoords->at(ib);
1193                    float frac=(dpm.length()/(dpm.length()+pplus.length()));
1194                    tci=tminus+((tplus-tminus)*frac);
1195                    ptfound=true;
1196                }
1197                ibm1=ib;
1198                ib++;   
1199                pminus=(*vit);
1200            }
1201        }
1202        tcoords->push_back(tci);
1203    }
1204    // some extra points are not interpolated as they lie between 2 interpolated vertices
1205    for (tritr=points->begin(); tritr!=points->end();tritr++) {
1206        int ib=tritr-points->begin();
1207        osg::Vec2 tci=tcoords->at(ib);
1208        if (tci.x()<-.99 && tci.y()<-.99) {
1209            // search through each of the primitivesets
1210            osg::Vec3Array::const_iterator ptitr;
1211            //    osg::notify(osg::WARN) << "Not calculated " <<  (*tritr).x() <<"," << (*tritr).y() << std::endl;
1212            for (ptitr=points->begin(); ptitr!=points->end();ptitr++) {
1213            }
1214        }
1215    }
1216    return tcoords.release();
1217}
1218osg::Vec3Array * LinearConstraint::getNormals(const osg::Vec3Array *points)
1219{
1220    osg::ref_ptr<osg::Vec3Array> norms=new osg::Vec3Array;
1221    for (osg::DrawElementsUInt::iterator uiitr=prim_tris_->begin(); uiitr!=prim_tris_->end();uiitr+=3) {
1222        osg::Vec3 e1=(*points)[*(uiitr+1)]-(*points)[(*uiitr)];
1223        osg::Vec3 e2=(*points)[*(uiitr+2)]-(*points)[*(uiitr+1)];
1224        osg::Vec3 n=e1^e2;
1225        n.normalize();
1226        //    if (n.z()<0) n=-n;
1227        norms->push_back(n);
1228    }
1229    return norms.release();
1230}
1231
1232osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points)
1233{
1234    osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the fill in road/railway
1235    if (_midline->size()>0) {
1236        osg::ref_ptr<osg::Vec3Array> locpts=getPoints(points);
1237        if (texture!="") {
1238            osg::Image* image = osgDB::readImageFile(texture.c_str());
1239            if (image)
1240            {
1241                osg::Texture2D* txt = new osg::Texture2D;
1242                osg::StateSet* stateset = gm->getOrCreateStateSet();
1243                txt->setImage(image);
1244                txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1245                txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1246                stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1247                osg::Material* material = new osg::Material;
1248                material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1249                material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1250                stateset->setAttribute(material,osg::StateAttribute::ON);
1251                stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1252            }
1253            gm->setTexCoordArray(0,getRoadTexcoords(locpts.get()));
1254        }
1255        gm->setVertexArray(locpts.get());
1256        gm->setNormalArray(getNormals(locpts.get()));
1257        gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
1258        gm->addPrimitiveSet(getTriangles());
1259    }
1260   
1261    return gm.release();
1262   
1263}
1264
1265
1266
1267int main( int argc, char **argv )
1268{
1269   
1270    // use an ArgumentParser object to manage the program arguments.
1271    osg::ArgumentParser arguments(&argc,argv);
1272   
1273    // set up the usage document, in case we need to print out how to use this program.
1274    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
1275    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example interactive demonstrates constrained delaunay traingulation of point dataset.");
1276    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
1277    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
1278    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
1279    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
1280    arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display environment variables available");
1281    arguments.getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
1282    arguments.getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindings");
1283   
1284   
1285    // construct the viewer.
1286    osgProducer::Viewer viewer(arguments);
1287   
1288    // set up the value with sensible default event handlers.
1289    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
1290   
1291    // get details on keyboard and mouse bindings used by the viewer.
1292    viewer.getUsage(*arguments.getApplicationUsage());
1293   
1294    // if user request help write it out to cout.
1295    bool helpAll = arguments.read("--help-all");
1296    unsigned int helpType = ((helpAll || arguments.read("-h") || arguments.read("--help"))? osg::ApplicationUsage::COMMAND_LINE_OPTION : 0 ) |
1297        ((helpAll ||  arguments.read("--help-env"))? osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE : 0 ) |
1298        ((helpAll ||  arguments.read("--help-keys"))? osg::ApplicationUsage::KEYBOARD_MOUSE_BINDING : 0 );
1299    if (helpType)
1300    {
1301        arguments.getApplicationUsage()->write(std::cout, helpType);
1302        return 1;
1303    }
1304   
1305    // report any errors if they have occured when parsing the program aguments.
1306    if (arguments.errors())
1307    {
1308        arguments.writeErrorMessages(std::cout);
1309        return 1;
1310    }
1311   
1312    if (arguments.argc()<1)
1313    {
1314        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
1315        return 1;
1316    }
1317   
1318    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1319   
1320    // create the scene from internal specified terrain/constraints.
1321    osg::ref_ptr<osg::Node> loadedModel = makedelaunay(0);
1322   
1323    // if no model has been successfully loaded report failure.
1324    if (!loadedModel)
1325    {
1326        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
1327        return 1;
1328    }
1329   
1330   
1331    // any option left unread are converted into errors to write out later.
1332    arguments.reportRemainingOptionsAsUnrecognized();
1333   
1334    // report any errors if they have occured when parsing the program aguments.
1335    if (arguments.errors())
1336    {
1337        arguments.writeErrorMessages(std::cout);
1338    }
1339   
1340    osg::Timer_t end_tick = osg::Timer::instance()->tick();
1341   
1342    std::cout << "Time to load = "<<osg::Timer::instance()->delta_s(start_tick,end_tick)<<std::endl;
1343   
1344    // optimize the scene graph, remove rendundent nodes and state etc.
1345    osgUtil::Optimizer optimizer;
1346    optimizer.optimize(loadedModel.get());
1347   
1348    // pass the loaded scene graph to the viewer.
1349    viewer.setSceneData(loadedModel.get());
1350   
1351    // copied from osgtessealte.cpp
1352    // add event handler for keyboard 'n' to retriangulate
1353    viewer.getEventHandlerList().push_front(new KeyboardEventHandler(loadedModel.get(), viewer));
1354   
1355    // create the windows and run the threads.
1356    viewer.realize();
1357   
1358    while( !viewer.done() )
1359    {
1360        // wait for all cull and draw threads to complete.
1361        viewer.sync();
1362       
1363        // update the scene by traversing it with the the update visitor which will
1364        // call all node update callbacks and animations.
1365        viewer.update();
1366       
1367        // fire off the cull and draw traversals of the scene.
1368        viewer.frame();
1369       
1370    }
1371   
1372    // wait for all cull and draw threads to complete.
1373    viewer.sync();
1374
1375    // run a clean up frame to delete all OpenGL objects.
1376    viewer.cleanup_frame();
1377
1378    // wait for all the clean up frame to complete.
1379    viewer.sync();
1380   
1381    return 0;
1382}
Note: See TracBrowser for help on using the browser.