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

Revision 7648, 58.4 kB (checked in by robert, 7 years ago)

From Roland Smeenk, "Attached you will find a large set of small typo fixes (mainly in the comments)."

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