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

Revision 5928, 58.0 kB (checked in by robert, 7 years ago)

From Paul Martz and Robert Osfield, renamed include/osgUtil/Tesselator and associated classes/references to Tessellator etc.

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