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

Revision 13557, 58.2 kB (checked in by robert, 6 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

  • 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 deprecated_osg::Geometry * makeAreal( osg::Vec3Array *points);
117
118    /** or create a wall around the constraint area: */
119    virtual deprecated_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 deprecated_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        deprecated_osg::Geometry *gm=new deprecated_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(deprecated_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<deprecated_osg::Geometry> gm=new deprecated_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(deprecated_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
991deprecated_osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt)
992{
993    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; // the wall
994    osg::ref_ptr<deprecated_osg::Geometry> edges=new deprecated_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
1055deprecated_osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points)
1056{
1057    osg::ref_ptr<deprecated_osg::Geometry> gm; // the fill in area
1058    if (_interiorTris.size()>0) {
1059        gm =new deprecated_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(deprecated_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
1236deprecated_osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points)
1237{
1238    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_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(deprecated_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.