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

Revision 4611, 51.8 kB (checked in by robert, 9 years ago)

From Geoff Michel, added support for constrain delaunay triangultion, and osgdelaunay example.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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(const osg::Vec3Array *points) 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 osg::Vec3Array *points,const float height) const;
55        virtual osg::Vec2Array *getWallTexcoords(const osg::Vec3Array *points,const float height) const;
56        virtual osg::Vec3Array *getWallNormals(const osg::Vec3Array *points) 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 osg::Vec3Array *points,const float height) const;
115        virtual osg::Vec2Array *getWallTexcoords(const osg::Vec3Array *points,const float height) const;
116        virtual osg::Vec3Array *getWallNormals(const osg::Vec3Array *points) 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() : 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 osg::Vec3Array *points) 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(const osg::Vec3Array *points) 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("stoneWall.jpg");
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+0.00052*rand();
269        float y=3000.0/(maxp-1)*j+0.0005*rand();
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("Lands-Flowers-Small_Purple.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==1) { // 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(points)); // this fills the holes of each pyramid with geometry
628                }
629               
630                if (ndcs>2) {
631                        trig->removeInternalTriangles(dc.get());
632                       
633                        wc->setTexture("Brick-Norman-Brown.TGA"); // wall looks like brick
634                        geode->addDrawable(wc->makeWallGeometry(points)); // 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("Lands-Needles_2.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 ("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("forestRoof.png");
655                                                osg::ref_ptr<osg::Vec3Array> locpts=forest->getPoints(points);
656                                                geode->addDrawable(forest->makeAreal(locpts.get()));
657
658                                                forest->setWallTexture("forestEdge.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 ("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 ("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 ("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 ("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 ("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 ("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          virtual void accept(osgGA::GUIEventHandlerVisitor& v)
738          {
739                  v.visit(*this);
740          }
741         
742          osg::Node *_scene;
743          osgProducer::Viewer &viewer;
744          int iview;
745};
746int main( int argc, char **argv )
747{
748       
749    // use an ArgumentParser object to manage the program arguments.
750    osg::ArgumentParser arguments(&argc,argv);
751   
752    // set up the usage document, in case we need to print out how to use this program.
753    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
754    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
755    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
756    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
757    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
758    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line paramters");
759    arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
760    arguments.getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
761    arguments.getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindigs.");
762   
763       
764    // construct the viewer.
765    osgProducer::Viewer viewer(arguments);
766       
767    // set up the value with sensible default event handlers.
768    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
769       
770    // get details on keyboard and mouse bindings used by the viewer.
771    viewer.getUsage(*arguments.getApplicationUsage());
772       
773    // if user request help write it out to cout.
774    bool helpAll = arguments.read("--help-all");
775    unsigned int helpType = ((helpAll || arguments.read("-h") || arguments.read("--help"))? osg::ApplicationUsage::COMMAND_LINE_OPTION : 0 ) |
776                ((helpAll ||  arguments.read("--help-env"))? osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE : 0 ) |
777                ((helpAll ||  arguments.read("--help-keys"))? osg::ApplicationUsage::KEYBOARD_MOUSE_BINDING : 0 );
778    if (helpType)
779    {
780        arguments.getApplicationUsage()->write(std::cout, helpType);
781        return 1;
782    }
783       
784    // report any errors if they have occured when parsing the program aguments.
785    if (arguments.errors())
786    {
787        arguments.writeErrorMessages(std::cout);
788        return 1;
789    }
790   
791    if (arguments.argc()<1)
792    {
793        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
794        return 1;
795    }
796       
797    osg::Timer_t start_tick = osg::Timer::instance()->tick();
798       
799    // create the scene from internal specified terrain/constraints.
800    osg::ref_ptr<osg::Node> loadedModel = makedelaunay(0);
801       
802    // if no model has been successfully loaded report failure.
803    if (!loadedModel)
804    {
805        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
806        return 1;
807    }
808       
809       
810    // any option left unread are converted into errors to write out later.
811    arguments.reportRemainingOptionsAsUnrecognized();
812       
813    // report any errors if they have occured when parsing the program aguments.
814    if (arguments.errors())
815    {
816        arguments.writeErrorMessages(std::cout);
817    }
818       
819    osg::Timer_t end_tick = osg::Timer::instance()->tick();
820       
821    std::cout << "Time to load = "<<osg::Timer::instance()->delta_s(start_tick,end_tick)<<std::endl;
822       
823    // optimize the scene graph, remove rendundent nodes and state etc.
824    osgUtil::Optimizer optimizer;
825    optimizer.optimize(loadedModel.get());
826       
827    // pass the loaded scene graph to the viewer.
828    viewer.setSceneData(loadedModel.get());
829       
830    // copied from osgtessealte.cpp
831        // add event handler for keyboard 'n' to retriangulate
832    viewer.getEventHandlerList().push_front(new KeyboardEventHandler(loadedModel.get(), viewer));
833       
834    // create the windows and run the threads.
835    viewer.realize();
836       
837    while( !viewer.done() )
838    {
839        // wait for all cull and draw threads to complete.
840        viewer.sync();
841               
842        // update the scene by traversing it with the the update visitor which will
843        // call all node update callbacks and animations.
844        viewer.update();
845               
846        // fire off the cull and draw traversals of the scene.
847        viewer.frame();
848       
849    }
850   
851    // wait for all cull and draw threads to complete before exit.
852    viewer.sync();
853       
854    return 0;
855}
856
857osg::Vec3Array * WallConstraint::getWall(const osg::Vec3Array *points,const float height) const
858{ // return array of points for a wall height high around the constraint
859        osg::Vec3Array *wall=new osg::Vec3Array;
860        if (height>0.0) {
861                osg::Vec3 off(0,0,height);
862                const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
863                for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
864                        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
865                        if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP ||
866                                prset->getMode()==osg::PrimitiveSet::LINE_STRIP) { // nothing else loops
867                                // start with the last point on the loop
868                                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
869                                        const osg::Vec3 curp=(*vertices)[prset->index (i)];
870                                        wall->push_back(curp);
871                                        wall->push_back(curp+off);
872                                }
873                                const osg::Vec3 curp=(*vertices)[prset->index (0)];
874                                wall->push_back(curp);
875                                wall->push_back(curp+off);
876                        }
877                }
878        }
879        return wall;
880}
881osg::Vec2Array * WallConstraint::getWallTexcoords(const osg::Vec3Array *points,const float height) const
882{ // return array of points for a wall height high around the constraint
883        osg::Vec2Array *tcoords= NULL;
884        if (height>0.0) {
885                float texrepRound=txxrepWall;
886                tcoords= new osg::Vec2Array;
887                float circumference=0; // distance around wall to get exact number of repeats of texture
888                const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
889                for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
890                        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
891                        osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
892                        unsigned int i;
893                        for (i=0; i<prset->getNumIndices(); i++) {
894                                const osg::Vec3 curp=(*vertices)[prset->index (i)];
895                                circumference+=(curp-prevp).length();
896                                prevp=curp;
897                        }
898                        const osg::Vec3 curp=(*vertices)[prset->index (0)];
899                        circumference+=(curp-prevp).length();
900                       
901                        int nround=(int)(circumference/txxrepWall);
902                        if (nround<1) nround=1; // at least one repeat.
903                        texrepRound=circumference/nround;
904                       
905                        float ds=0;
906                        prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
907                        if (tcoords) {
908                                for (i=0; i<prset->getNumIndices(); i++) {
909                                        const osg::Vec3 curp=(*vertices)[prset->index (i)];
910                                        osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
911                                        tcoords->push_back(tci);
912                                        tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
913                                        tcoords->push_back(tci);
914                                        ds+=(curp-prevp).length();
915                                        prevp=curp;
916                                }
917                                osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
918                                tcoords->push_back(tci);
919                                tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
920                                tcoords->push_back(tci);
921                        }
922                } // per primitiveset
923               
924        }
925        return tcoords;
926}
927osg::Geometry *WallConstraint::makeWallGeometry(const osg::Vec3Array *points) const
928{
929        osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall
930        if (texture!="") {
931                osg::Image* image = osgDB::readImageFile(texture.c_str());
932                if (image)
933                {
934                        osg::Texture2D* txt = new osg::Texture2D;
935                        osg::StateSet* stateset = gm->getOrCreateStateSet();
936                        txt->setImage(image);
937                        txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
938                        txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
939                        stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
940                        osg::Material* material = new osg::Material;
941                        material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,0.0f,1.0f));
942                        material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
943                        stateset->setAttribute(material,osg::StateAttribute::ON);
944                        stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
945                }
946        }
947        gm->setVertexArray(getWall(points,height));
948        gm->addPrimitiveSet(makeWall());
949        gm->setTexCoordArray(0,getWallTexcoords(points,height));
950        gm->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
951        gm->setNormalArray(getWallNormals(points)); // this creates normals to walls
952       
953        return gm.release();
954}
955
956osg::Vec3Array *ArealConstraint::getWallNormals(const osg::Vec3Array *points) const
957{
958        osg::Vec3Array *nrms=new osg::Vec3Array;
959        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
960        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
961                const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
962                if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
963                        // start with the last point on the loop
964                        osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
965                        for (unsigned int i=0; i<prset->getNumIndices(); i++) {
966                                const osg::Vec3 curp=(*vertices)[prset->index (i)];
967                                osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
968                                nrm.normalize();
969                                nrms->push_back(nrm);
970                                nrms->push_back(nrm);
971                                prevp=curp;
972                        }
973                        const osg::Vec3 curp=(*vertices)[prset->index (0)];
974                        osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
975                        nrm.normalize();
976                        nrms->push_back(nrm);
977                        nrms->push_back(nrm);
978                }
979        }
980        return nrms;
981}
982
983
984osg::Vec3Array * ArealConstraint::getWall(const osg::Vec3Array* points,const float height) const
985{ // return array of points for a wall height high around the constraint
986        osg::Vec3Array *wall=new osg::Vec3Array;
987        if (height>0.0) {
988                osg::Vec3 off(0,0,height);
989                const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
990                for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
991                        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
992                        if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
993                                // start with the last point on the loop
994                                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
995                                        const osg::Vec3 curp=(*vertices)[prset->index (i)];
996                                        wall->push_back(curp);
997                                        wall->push_back(curp+off);
998                                }
999                                const osg::Vec3 curp=(*vertices)[prset->index (0)];
1000                                wall->push_back(curp);
1001                                wall->push_back(curp+off);
1002                        }
1003                }
1004        }
1005        return wall;
1006}
1007
1008osg::Vec2Array * ArealConstraint::getWallTexcoords(const osg::Vec3Array *points,const float height) const
1009{ // return array of points for a wall height high around the constraint
1010        osg::Vec2Array *tcoords= NULL;
1011        if (height>0.0) {
1012                float texrepRound=txxrepWall;
1013                tcoords= new osg::Vec2Array;
1014                float circumference=0; // distance around wall to get exact number of repeats of texture
1015                const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
1016                for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
1017                        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
1018                        osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
1019                        unsigned int i;
1020                        for (i=0; i<prset->getNumIndices(); i++) {
1021                                const osg::Vec3 curp=(*vertices)[prset->index (i)];
1022                                circumference+=(curp-prevp).length();
1023                                prevp=curp;
1024                        }
1025                        const osg::Vec3 curp=(*vertices)[prset->index (0)];
1026                        circumference+=(curp-prevp).length();
1027                       
1028                        int nround=(int)(circumference/txxrepWall);
1029                        if (nround<1) nround=1; // at least one repeat.
1030                        texrepRound=circumference/nround;
1031                       
1032                        float ds=0;
1033                        prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
1034                        if (tcoords) {
1035                                for (i=0; i<prset->getNumIndices(); i++) {
1036                                        const osg::Vec3 curp=(*vertices)[prset->index (i)];
1037                                        osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
1038                                        tcoords->push_back(tci);
1039                                        tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
1040                                        tcoords->push_back(tci);
1041                                        ds+=(curp-prevp).length();
1042                                        prevp=curp;
1043                                }
1044                                osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
1045                                tcoords->push_back(tci);
1046                                tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
1047                                tcoords->push_back(tci);
1048                        }
1049                } // per primitiveset
1050        }
1051        return tcoords;
1052}
1053osg::DrawArrays* ArealConstraint::makeCanopy( void ) const
1054{
1055        return (new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,3*_interiorTris.size()));
1056}
1057osg::Vec3Array *ArealConstraint::getCanopy(const osg::Vec3Array *points,const float height) const
1058{ // returns the array of vertices in the canopy
1059        osg::Vec3 off(0,0,height);
1060        osg::Vec3Array *internals=new osg::Vec3Array;
1061        trilist::const_iterator tritr;
1062        for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
1063                for (int i=0; i<3; i++) {
1064                        int index=(*tritr)[i];
1065                        internals->push_back((*points)[index]+off);
1066                }
1067        }
1068        return internals;
1069}
1070osg::Vec3Array *ArealConstraint::getCanopyNormals(const osg::Vec3Array *points) const
1071{
1072        osg::Vec3Array *nrms=new osg::Vec3Array;
1073        trilist::const_iterator tritr;
1074        for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
1075                osg::Vec3 e1=(*points)[(*tritr)[1]]-(*points)[(*tritr)[0]];
1076                osg::Vec3 e2=(*points)[(*tritr)[2]]-(*points)[(*tritr)[0]];
1077                osg::Vec3 nrm=e1^e2;
1078                nrm.normalize();
1079                nrms->push_back(nrm);
1080        }
1081        return nrms;
1082}
1083
1084osg::Vec2Array *ArealConstraint::getCanopyTexcoords(const osg::Vec3Array *points) const
1085{
1086        osg::Vec3Array::const_iterator tritr;
1087        osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
1088        for (tritr=points->begin(); tritr!=points->end();tritr++) {
1089                                // calculate tcoords for terrain from xy drape.
1090                osg::Vec2 tci=osg::Vec2f(tritr->x()/txxrepArea, tritr->y()/txyrepArea);
1091                tcoords->push_back(tci);
1092        }
1093        return tcoords.release();
1094}
1095
1096osg::DrawArrays * ArealConstraint::makeWall(void) const
1097{ // build a wall height high around the constraint
1098        const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
1099        return (new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2+2*_line->size()));
1100}
1101
1102osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt)
1103{
1104        osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall
1105        osg::ref_ptr<osg::Geometry> edges=new osg::Geometry; // edges of bounds
1106        edges->setVertexArray(pt);
1107        osg::DrawElementsUInt *trgeom=getTriangles();
1108        edges->addPrimitiveSet(trgeom);
1109       
1110        osg::ref_ptr<osgUtil::Tesselator> tscx=new osgUtil::Tesselator; // this assembles all the constraints
1111        tscx->setTesselationType(osgUtil::Tesselator::TESS_TYPE_GEOMETRY);
1112        tscx->setBoundaryOnly(true);
1113        tscx->setWindingType( osgUtil::Tesselator::TESS_WINDING_NONZERO);
1114        //  find all edges.
1115        const osg::Vec3Array *points=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1116       
1117        tscx->retesselatePolygons(*(edges)); // find all edges
1118       
1119        if (walltexture!="") {
1120                osg::Image* image = osgDB::readImageFile(walltexture.c_str());
1121                if (image)
1122                {
1123                        osg::Texture2D* txt = new osg::Texture2D;
1124                        osg::StateSet* stateset = gm->getOrCreateStateSet();
1125                        txt->setImage(image);
1126                        txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1127                        txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
1128                        stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1129                }
1130        }
1131        points=dynamic_cast<osg::Vec3Array*>(edges->getVertexArray());
1132        int nstart=0;
1133        osg::ref_ptr<osg::Vec3Array> coords=new osg::Vec3Array;
1134        osg::ref_ptr<osg::Vec2Array> tcoords=new osg::Vec2Array;
1135        for (unsigned int i=0; i<edges->getNumPrimitiveSets(); i++) {
1136                osg::PrimitiveSet *pr=edges->getPrimitiveSet(i);
1137                if (pr->getMode() == osg::PrimitiveSet::LINE_LOOP) {
1138                        float ds=0;
1139                        for (unsigned int icon=0; icon<pr->getNumIndices(); icon++) {
1140                                unsigned int ithis=pr->index(icon);
1141                                osg::Vec3 pt=                           (*points)[ithis];
1142                                coords->push_back(pt);
1143                                coords->push_back(pt+osg::Vec3(0,0,height));
1144                                tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1145                                tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1146                                if (icon<pr->getNumIndices()-1) ds+=((*points)[pr->index(icon+1)]-(*points)[ithis]).length();
1147                                else ds+=((*points)[pr->index(0)]-(*points)[ithis]).length();
1148                        }
1149                        // repeat first point
1150                        unsigned int ithis=pr->index(0);
1151                        coords->push_back((*points)[ithis]);
1152                        coords->push_back((*points)[ithis]+osg::Vec3(0,0,height));
1153                        tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1154                        tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1155                        gm->setVertexArray(coords.get());
1156                        gm->setTexCoordArray(0,tcoords.get());
1157                        gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nstart,2+2*pr->getNumIndices()));
1158                        nstart+=2+2*pr->getNumIndices();
1159                }
1160        }
1161       
1162        return gm.release();
1163}
1164
1165
1166osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points)
1167{
1168        osg::ref_ptr<osg::Geometry> gm; // the fill in area
1169        if (_interiorTris.size()>0) {
1170                gm =new osg::Geometry; // the forest roof
1171                gm->setVertexArray(points);
1172                osg::DrawElementsUInt *trgeom=getTriangles();
1173                gm->addPrimitiveSet(trgeom);
1174                gm->setTexCoordArray(0,getCanopyTexcoords(points));
1175                osg::Image* image = osgDB::readImageFile(texture);
1176                if (image)
1177                {
1178                        osg::Texture2D* txt = new osg::Texture2D;
1179                        osg::StateSet* stateset = gm->getOrCreateStateSet();
1180                        txt->setImage(image);
1181                        txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1182                        txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1183                        stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1184                        osg::Material* material = new osg::Material;
1185                        material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1186                        material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1187                        stateset->setAttribute(material,osg::StateAttribute::ON);
1188                        stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1189                }
1190        }
1191        return gm.release();
1192}
1193
1194
1195void LinearConstraint::setVertices( osg::Vec3Array *lp, const float w)
1196{ // generate constant width around line (calls setvertices(edges))
1197        osg::ref_ptr<osg::Vec3Array> edges=new osg::Vec3Array;
1198        _tcoords=new osg::Vec2Array; // texture coordinates for replacement geometry
1199        _edgecoords=new osg::Vec3Array; // posiiton coordinates for replacement geometry
1200        width=w;
1201        _midline=lp;
1202        float ds=0;
1203        for(unsigned int i=0;i<lp->size();i++) {
1204                osg::Vec3 valong;
1205                osg::Vec3 pos[2];
1206               
1207                if (i==0) {
1208                        valong=(*lp)[i+1]-(*lp)[i];
1209                } else if (i==lp->size()-1) {
1210                        valong=(*lp)[i]-(*lp)[i-1];
1211                } else {
1212                        valong=(*lp)[i+1]-(*lp)[i-1];
1213                }
1214                valong.normalize();
1215                osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1216                pos[0]=(*lp)[i]-vperp*.5*width;
1217                pos[1]=(*lp)[i]+vperp*.5*width;
1218                edges->push_back(pos[0]);
1219                _edgecoords->push_back(pos[0]);
1220                _tcoords->push_back(osg::Vec2(0/txyrepAcross,ds/txxrepAlong));
1221                edges->insert(edges->begin() ,pos[1]);
1222                _edgecoords->insert(_edgecoords->begin() ,pos[1]);
1223                _tcoords->insert(_tcoords->begin() ,osg::Vec2(width/txyrepAcross,ds/txxrepAlong));
1224                if (i<lp->size()-1) ds+=((*lp)[i+1]-(*lp)[i]).length();
1225        }
1226        setVertexArray(edges.get());
1227        addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,edges->size()) );
1228}
1229
1230osg::DrawArrays* LinearConstraint::makeRoad(void ) const
1231{
1232        return  new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_midline->size());
1233       
1234}
1235
1236osg::Vec3Array *LinearConstraint::getRoadNormals(const osg::Vec3Array *points) const
1237{
1238        osg::Vec3Array *nrms=new osg::Vec3Array;
1239        for(unsigned int i=0;i<_midline->size();i++) {
1240                osg::Vec3 valong; // vector along midline of road
1241                if (i==0) {
1242                        valong=(*_midline)[i+1]-(*_midline)[i];
1243                } else if (i==_midline->size()-1) {
1244                        valong=(*_midline)[i]-(*_midline)[i-1];
1245                } else {
1246                        valong=(*_midline)[i+1]-(*_midline)[i-1];
1247                }
1248                osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1249                osg::Vec3 nrm=vperp^valong; // normal to linear
1250                nrm.normalize();
1251                nrms->push_back(nrm); // repeated for each vertex of linear.
1252                nrms->push_back(nrm);
1253        }
1254        return nrms;
1255}
1256osg::Vec3Array *LinearConstraint::getRoadVertices(const osg::Vec3Array *points) const
1257{
1258        osg::Vec3Array *linearEdges=new osg::Vec3Array;
1259        for(unsigned int i=0;i<_midline->size();i++) {
1260                osg::Vec3 valong; // vector along midline of road
1261                if (i==0) {
1262                        valong=(*_midline)[i+1]-(*_midline)[i];
1263                } else if (i==_midline->size()-1) {
1264                        valong=(*_midline)[i]-(*_midline)[i-1];
1265                } else {
1266                        valong=(*_midline)[i+1]-(*_midline)[i-1];
1267                }
1268                valong.normalize();
1269                osg::Vec3 vperp=valong^osg::Vec3(0,0,1); // vector across road
1270                // sides of linear
1271                linearEdges->push_back((*_midline)[i]-vperp*.5*width);
1272                linearEdges->push_back((*_midline)[i]+vperp*.5*width);
1273        }
1274        return linearEdges;
1275}
1276
1277osg::Vec2Array *LinearConstraint::getRoadTexcoords(const osg::Vec3Array *points)  {
1278        // need to create a vec2 array from the coordinates that fits the road
1279        osg::Vec3Array::const_iterator tritr;
1280        osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
1281        for (tritr=points->begin(); tritr!=points->end();tritr++) {
1282                osg::Vec2 tci(-1.,-1.);
1283                int ib=0;
1284                // osg::Vec3Array *varr=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1285                bool ptfound=false;
1286                for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() && !ptfound; vit++) {
1287                        if ((*vit)==(*tritr)) {
1288                                tci=_tcoords->at(ib);
1289                                ptfound=true;
1290                        }
1291                        ib++;
1292                }
1293                if (!ptfound) { // search for surrounding points and interpolate
1294                        ib=0;
1295                        osg::Vec3 pminus=(_edgecoords->back()); // need pminus for interpolation
1296                        int ibm1=_edgecoords->size()-1;
1297                        for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() /*&& !ptfound*/; vit++) {
1298                                osg::Vec3 pplus=(*vit)-(*tritr);
1299                                osg::Vec3 dpm=pminus-(*tritr);
1300                                pplus.set (pplus.x(),pplus.y(),0);
1301                                dpm.set (dpm.x(),dpm.y(),0);
1302                                float dprod=pplus*dpm/(pplus.length() * dpm.length());
1303                                if (dprod<-0.9999) { // *tritr lies between....
1304                                        osg::Vec2 tminus=_tcoords->at(ibm1);
1305                                        osg::Vec2 tplus=_tcoords->at(ib);
1306                                        float frac=(dpm.length()/(dpm.length()+pplus.length()));
1307                                        tci=tminus+((tplus-tminus)*frac);
1308                                        ptfound=true;
1309                                }
1310                                ibm1=ib;
1311                                ib++;   
1312                                pminus=(*vit);
1313                        }
1314                }
1315                tcoords->push_back(tci);
1316        }
1317        // some extra points are not interpolated as they lie between 2 interpolated vertices
1318        for (tritr=points->begin(); tritr!=points->end();tritr++) {
1319                int ib=tritr-points->begin();
1320                osg::Vec2 tci=tcoords->at(ib);
1321                if (tci.x()<-.99 && tci.y()<-.99) {
1322                        // search through each of the primitivesets
1323                        osg::Vec3Array::const_iterator ptitr;
1324                        //      osg::notify(osg::WARN) << "Not calculated " <<  (*tritr).x() <<"," << (*tritr).y() << std::endl;
1325                        for (ptitr=points->begin(); ptitr!=points->end();ptitr++) {
1326                        }
1327                }
1328        }
1329        return tcoords.release();
1330}
1331osg::Vec3Array * LinearConstraint::getNormals(const osg::Vec3Array *points)
1332{
1333        osg::ref_ptr<osg::Vec3Array> norms=new osg::Vec3Array;
1334        for (osg::DrawElementsUInt::iterator uiitr=prim_tris_->begin(); uiitr!=prim_tris_->end();uiitr+=3) {
1335                osg::Vec3 e1=(*points)[*(uiitr+1)]-(*points)[(*uiitr)];
1336                osg::Vec3 e2=(*points)[*(uiitr+2)]-(*points)[*(uiitr+1)];
1337                osg::Vec3 n=e1^e2;
1338                n.normalize();
1339                //      if (n.z()<0) n=-n;
1340                norms->push_back(n);
1341        }
1342        return norms.release();
1343}
1344
1345osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points)
1346{
1347        osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the fill in road/railway
1348        if (_midline->size()>0) {
1349                osg::ref_ptr<osg::Vec3Array> locpts=getPoints(points);
1350                if (texture!="") {
1351                        osg::Image* image = osgDB::readImageFile(texture.c_str());
1352                        if (image)
1353                        {
1354                                osg::Texture2D* txt = new osg::Texture2D;
1355                                osg::StateSet* stateset = gm->getOrCreateStateSet();
1356                                txt->setImage(image);
1357                                txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1358                                txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1359                                stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1360                                osg::Material* material = new osg::Material;
1361                                material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1362                                material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1363                                stateset->setAttribute(material,osg::StateAttribute::ON);
1364                                stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1365                        }
1366                        gm->setTexCoordArray(0,getRoadTexcoords(locpts.get()));
1367                }
1368                gm->setVertexArray(locpts.get());
1369                gm->setNormalArray(getNormals(locpts.get()));
1370                gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
1371                gm->addPrimitiveSet(getTriangles());
1372        }
1373       
1374        return gm.release();
1375       
1376}
1377
Note: See TracBrowser for help on using the browser.