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

Revision 13574, 58.1 kB (checked in by robert, 12 hours ago)

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

  • 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->setNormalArray(getWallNormals(), osg::Array::BIND_PER_VERTEX); // this creates normals to walls
840
841    return gm.release();
842}
843
844osg::Vec3Array *ArealConstraint::getWallNormals() const
845{
846    osg::Vec3Array *nrms=new osg::Vec3Array;
847    const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
848    for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
849        const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
850        if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
851            // start with the last point on the loop
852            osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
853            for (unsigned int i=0; i<prset->getNumIndices(); i++) {
854                const osg::Vec3 curp=(*vertices)[prset->index (i)];
855                osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
856                nrm.normalize();
857                nrms->push_back(nrm);
858                nrms->push_back(nrm);
859                prevp=curp;
860            }
861            const osg::Vec3 curp=(*vertices)[prset->index (0)];
862            osg::Vec3 nrm=(curp-prevp)^osg::Vec3(0,0,1);
863            nrm.normalize();
864            nrms->push_back(nrm);
865            nrms->push_back(nrm);
866        }
867    }
868    return nrms;
869}
870
871
872osg::Vec3Array * ArealConstraint::getWall(const float height) const
873{ // return array of points for a wall height high around the constraint
874    osg::Vec3Array *wall=new osg::Vec3Array;
875    if (height>0.0) {
876        osg::Vec3 off(0,0,height);
877        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
878        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
879            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
880            if (prset->getMode()==osg::PrimitiveSet::LINE_LOOP) { // nothing else loops
881                // start with the last point on the loop
882                for (unsigned int i=0; i<prset->getNumIndices(); i++) {
883                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
884                    wall->push_back(curp);
885                    wall->push_back(curp+off);
886                }
887                const osg::Vec3 curp=(*vertices)[prset->index (0)];
888                wall->push_back(curp);
889                wall->push_back(curp+off);
890            }
891        }
892    }
893    return wall;
894}
895
896osg::Vec2Array * ArealConstraint::getWallTexcoords(const float height) const
897{ // return array of points for a wall height high around the constraint
898    osg::Vec2Array *tcoords= NULL;
899    if (height>0.0) {
900        float texrepRound=txxrepWall;
901        tcoords= new osg::Vec2Array;
902        float circumference=0; // distance around wall to get exact number of repeats of texture
903        const osg::Vec3Array *vertices= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
904        for (unsigned int ipr=0; ipr<getNumPrimitiveSets(); ipr++) {
905            const osg::PrimitiveSet* prset=getPrimitiveSet(ipr);
906            osg::Vec3 prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
907                        unsigned int i;
908            for (i=0; i<prset->getNumIndices(); i++) {
909                const osg::Vec3 curp=(*vertices)[prset->index (i)];
910                circumference+=(curp-prevp).length();
911                prevp=curp;
912            }
913            const osg::Vec3 curp=(*vertices)[prset->index (0)];
914            circumference+=(curp-prevp).length();
915
916            int nround=(int)(circumference/txxrepWall);
917            if (nround<1) nround=1; // at least one repeat.
918            texrepRound=circumference/nround;
919
920            float ds=0;
921            prevp=(*vertices)[prset->index (prset->getNumIndices()-1)];
922            if (tcoords) {
923                for (i=0; i<prset->getNumIndices(); i++) {
924                    const osg::Vec3 curp=(*vertices)[prset->index (i)];
925                    osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
926                    tcoords->push_back(tci);
927                    tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
928                    tcoords->push_back(tci);
929                    ds+=(curp-prevp).length();
930                    prevp=curp;
931                }
932                osg::Vec2 tci=osg::Vec2f(ds/texrepRound,0/txyrepWall);
933                tcoords->push_back(tci);
934                tci=osg::Vec2f(ds/texrepRound,height/txyrepWall);
935                tcoords->push_back(tci);
936            }
937        } // per primitiveset
938    }
939    return tcoords;
940}
941osg::DrawArrays* ArealConstraint::makeCanopy( void ) const
942{
943    return (new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,3*_interiorTris.size()));
944}
945osg::Vec3Array *ArealConstraint::getCanopy(const osg::Vec3Array *points,const float height) const
946{ // returns the array of vertices in the canopy
947    osg::Vec3 off(0,0,height);
948    osg::Vec3Array *internals=new osg::Vec3Array;
949    trilist::const_iterator tritr;
950    for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
951        for (int i=0; i<3; i++) {
952            int index=(*tritr)[i];
953            internals->push_back((*points)[index]+off);
954        }
955    }
956    return internals;
957}
958osg::Vec3Array *ArealConstraint::getCanopyNormals(const osg::Vec3Array *points) const
959{
960    osg::Vec3Array *nrms=new osg::Vec3Array;
961    trilist::const_iterator tritr;
962    for (tritr=_interiorTris.begin(); tritr!=_interiorTris.end();tritr++) {
963        osg::Vec3 e1=(*points)[(*tritr)[1]]-(*points)[(*tritr)[0]];
964        osg::Vec3 e2=(*points)[(*tritr)[2]]-(*points)[(*tritr)[0]];
965        osg::Vec3 nrm=e1^e2;
966        nrm.normalize();
967        nrms->push_back(nrm);
968    }
969    return nrms;
970}
971
972osg::Vec2Array *ArealConstraint::getCanopyTexcoords(const osg::Vec3Array *points) const
973{
974    osg::Vec3Array::const_iterator tritr;
975    osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
976    for (tritr=points->begin(); tritr!=points->end();tritr++) {
977                // calculate tcoords for terrain from xy drape.
978        osg::Vec2 tci=osg::Vec2f(tritr->x()/txxrepArea, tritr->y()/txyrepArea);
979        tcoords->push_back(tci);
980    }
981    return tcoords.release();
982}
983
984osg::DrawArrays * ArealConstraint::makeWall(void) const
985{ // build a wall height high around the constraint
986    const osg::Vec3Array *_line= dynamic_cast<const osg::Vec3Array*>(getVertexArray());
987    return (new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2+2*_line->size()));
988}
989
990deprecated_osg::Geometry *ArealConstraint::makeWallGeometry( osg::Vec3Array *pt)
991{
992    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; // the wall
993    osg::ref_ptr<deprecated_osg::Geometry> edges=new deprecated_osg::Geometry; // edges of bounds
994    edges->setVertexArray(pt);
995    osg::DrawElementsUInt *trgeom=getTriangles();
996    edges->addPrimitiveSet(trgeom);
997
998    osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator; // this assembles all the constraints
999    tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
1000    tscx->setBoundaryOnly(true);
1001    tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NONZERO);
1002    //  find all edges.
1003    const osg::Vec3Array *points=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1004
1005    tscx->retessellatePolygons(*(edges)); // find all edges
1006
1007    if (walltexture!="") {
1008        osg::Image* image = osgDB::readImageFile(walltexture.c_str());
1009        if (image)
1010        {
1011            osg::Texture2D* txt = new osg::Texture2D;
1012            osg::StateSet* stateset = gm->getOrCreateStateSet();
1013            txt->setImage(image);
1014            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1015            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
1016            stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1017        }
1018    }
1019    points=dynamic_cast<osg::Vec3Array*>(edges->getVertexArray());
1020    int nstart=0;
1021    osg::ref_ptr<osg::Vec3Array> coords=new osg::Vec3Array;
1022    osg::ref_ptr<osg::Vec2Array> tcoords=new osg::Vec2Array;
1023    for (unsigned int i=0; i<edges->getNumPrimitiveSets(); i++) {
1024        osg::PrimitiveSet *pr=edges->getPrimitiveSet(i);
1025        if (pr->getMode() == osg::PrimitiveSet::LINE_LOOP) {
1026            float ds=0;
1027            for (unsigned int icon=0; icon<pr->getNumIndices(); icon++) {
1028                unsigned int ithis=pr->index(icon);
1029                osg::Vec3 pt=                (*points)[ithis];
1030                coords->push_back(pt);
1031                coords->push_back(pt+osg::Vec3(0,0,height));
1032                tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1033                tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1034                if (icon<pr->getNumIndices()-1) ds+=((*points)[pr->index(icon+1)]-(*points)[ithis]).length();
1035                else ds+=((*points)[pr->index(0)]-(*points)[ithis]).length();
1036            }
1037            // repeat first point
1038            unsigned int ithis=pr->index(0);
1039            coords->push_back((*points)[ithis]);
1040            coords->push_back((*points)[ithis]+osg::Vec3(0,0,height));
1041            tcoords->push_back(osg::Vec2(ds/txxrepWall,0));
1042            tcoords->push_back(osg::Vec2(ds/txxrepWall,1.0));
1043            gm->setVertexArray(coords.get());
1044            gm->setTexCoordArray(0,tcoords.get());
1045            gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nstart,2+2*pr->getNumIndices()));
1046            nstart+=2+2*pr->getNumIndices();
1047        }
1048    }
1049
1050    return gm.release();
1051}
1052
1053
1054deprecated_osg::Geometry * ArealConstraint::makeAreal( osg::Vec3Array *points)
1055{
1056    osg::ref_ptr<deprecated_osg::Geometry> gm; // the fill in area
1057    if (_interiorTris.size()>0) {
1058        gm =new deprecated_osg::Geometry; // the forest roof
1059        gm->setVertexArray(points);
1060        osg::DrawElementsUInt *trgeom=getTriangles();
1061        gm->addPrimitiveSet(trgeom);
1062        gm->setNormalArray(getCanopyNormals(points));
1063        gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE);
1064        gm->setTexCoordArray(0,getCanopyTexcoords(points));
1065        osg::Image* image = osgDB::readImageFile(texture);
1066        if (image)
1067        {
1068            osg::Texture2D* txt = new osg::Texture2D;
1069            osg::StateSet* stateset = gm->getOrCreateStateSet();
1070            txt->setImage(image);
1071            txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1072            txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1073            stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1074            osg::Material* material = new osg::Material;
1075            material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1076            material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1077            stateset->setAttribute(material,osg::StateAttribute::ON);
1078            stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1079        }
1080    }
1081    return gm.release();
1082}
1083
1084
1085void LinearConstraint::setVertices( osg::Vec3Array *lp, const float w)
1086{ // generate constant width around line (calls setvertices(edges))
1087    osg::ref_ptr<osg::Vec3Array> edges=new osg::Vec3Array;
1088    _tcoords=new osg::Vec2Array; // texture coordinates for replacement geometry
1089    _edgecoords=new osg::Vec3Array; // posiiton coordinates for replacement geometry
1090    width=w;
1091    _midline=lp;
1092    float ds=0;
1093    for(unsigned int i=0;i<lp->size();i++) {
1094        osg::Vec3 valong;
1095        osg::Vec3 pos[2];
1096
1097        if (i==0) {
1098            valong=(*lp)[i+1]-(*lp)[i];
1099        } else if (i==lp->size()-1) {
1100            valong=(*lp)[i]-(*lp)[i-1];
1101        } else {
1102            valong=(*lp)[i+1]-(*lp)[i-1];
1103        }
1104        valong.normalize();
1105        osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1106        pos[0]=(*lp)[i]-vperp*.5*width;
1107        pos[1]=(*lp)[i]+vperp*.5*width;
1108        edges->push_back(pos[0]);
1109        _edgecoords->push_back(pos[0]);
1110        _tcoords->push_back(osg::Vec2(0/txyrepAcross,ds/txxrepAlong));
1111        edges->insert(edges->begin() ,pos[1]);
1112        _edgecoords->insert(_edgecoords->begin() ,pos[1]);
1113        _tcoords->insert(_tcoords->begin() ,osg::Vec2(width/txyrepAcross,ds/txxrepAlong));
1114        if (i<lp->size()-1) ds+=((*lp)[i+1]-(*lp)[i]).length();
1115    }
1116    setVertexArray(edges.get());
1117    addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,edges->size()) );
1118}
1119
1120osg::DrawArrays* LinearConstraint::makeRoad(void ) const
1121{
1122    return     new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_midline->size());
1123
1124}
1125
1126osg::Vec3Array *LinearConstraint::getRoadNormals(const osg::Vec3Array* /*points*/) const
1127{
1128    osg::Vec3Array *nrms=new osg::Vec3Array;
1129    for(unsigned int i=0;i<_midline->size();i++) {
1130        osg::Vec3 valong; // vector along midline of road
1131        if (i==0) {
1132            valong=(*_midline)[i+1]-(*_midline)[i];
1133        } else if (i==_midline->size()-1) {
1134            valong=(*_midline)[i]-(*_midline)[i-1];
1135        } else {
1136            valong=(*_midline)[i+1]-(*_midline)[i-1];
1137        }
1138        osg::Vec3 vperp=valong^osg::Vec3(0,0,1);
1139        osg::Vec3 nrm=vperp^valong; // normal to linear
1140        nrm.normalize();
1141        nrms->push_back(nrm); // repeated for each vertex of linear.
1142        nrms->push_back(nrm);
1143    }
1144    return nrms;
1145}
1146osg::Vec3Array *LinearConstraint::getRoadVertices() const
1147{
1148    osg::Vec3Array *linearEdges=new osg::Vec3Array;
1149    for(unsigned int i=0;i<_midline->size();i++) {
1150        osg::Vec3 valong; // vector along midline of road
1151        if (i==0) {
1152            valong=(*_midline)[i+1]-(*_midline)[i];
1153        } else if (i==_midline->size()-1) {
1154            valong=(*_midline)[i]-(*_midline)[i-1];
1155        } else {
1156            valong=(*_midline)[i+1]-(*_midline)[i-1];
1157        }
1158        valong.normalize();
1159        osg::Vec3 vperp=valong^osg::Vec3(0,0,1); // vector across road
1160        // sides of linear
1161        linearEdges->push_back((*_midline)[i]-vperp*.5*width);
1162        linearEdges->push_back((*_midline)[i]+vperp*.5*width);
1163    }
1164    return linearEdges;
1165}
1166
1167osg::Vec2Array *LinearConstraint::getRoadTexcoords(const osg::Vec3Array *points)  {
1168    // need to create a vec2 array from the coordinates that fits the road
1169    osg::Vec3Array::const_iterator tritr;
1170    osg::ref_ptr<osg::Vec2Array> tcoords= new osg::Vec2Array ;
1171    for (tritr=points->begin(); tritr!=points->end();tritr++) {
1172        osg::Vec2 tci(-1.,-1.);
1173        int ib=0;
1174        // osg::Vec3Array *varr=dynamic_cast<osg::Vec3Array*>(getVertexArray());
1175        bool ptfound=false;
1176        for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() && !ptfound; vit++) {
1177            if ((*vit)==(*tritr)) {
1178                tci=_tcoords->at(ib);
1179                ptfound=true;
1180            }
1181            ib++;
1182        }
1183        if (!ptfound) { // search for surrounding points and interpolate
1184            ib=0;
1185            osg::Vec3 pminus=(_edgecoords->back()); // need pminus for interpolation
1186            int ibm1=_edgecoords->size()-1;
1187            for (osg::Vec3Array::iterator vit=_edgecoords->begin(); vit!= _edgecoords->end() /*&& !ptfound*/; vit++) {
1188                osg::Vec3 pplus=(*vit)-(*tritr);
1189                osg::Vec3 dpm=pminus-(*tritr);
1190                pplus.set (pplus.x(),pplus.y(),0);
1191                dpm.set (dpm.x(),dpm.y(),0);
1192                float dprod=pplus*dpm/(pplus.length() * dpm.length());
1193                if (dprod<-0.9999) { // *tritr lies between....
1194                    osg::Vec2 tminus=_tcoords->at(ibm1);
1195                    osg::Vec2 tplus=_tcoords->at(ib);
1196                    float frac=(dpm.length()/(dpm.length()+pplus.length()));
1197                    tci=tminus+((tplus-tminus)*frac);
1198                    ptfound=true;
1199                }
1200                ibm1=ib;
1201                ib++;
1202                pminus=(*vit);
1203            }
1204        }
1205        tcoords->push_back(tci);
1206    }
1207    // some extra points are not interpolated as they lie between 2 interpolated vertices
1208    for (tritr=points->begin(); tritr!=points->end();tritr++) {
1209        int ib=tritr-points->begin();
1210        osg::Vec2 tci=tcoords->at(ib);
1211        if (tci.x()<-.99 && tci.y()<-.99) {
1212            // search through each of the primitivesets
1213            osg::Vec3Array::const_iterator ptitr;
1214            //    osg::notify(osg::WARN) << "Not calculated " <<  (*tritr).x() <<"," << (*tritr).y() << std::endl;
1215            for (ptitr=points->begin(); ptitr!=points->end();ptitr++) {
1216            }
1217        }
1218    }
1219    return tcoords.release();
1220}
1221osg::Vec3Array * LinearConstraint::getNormals(const osg::Vec3Array *points)
1222{
1223    osg::ref_ptr<osg::Vec3Array> norms=new osg::Vec3Array;
1224    for (osg::DrawElementsUInt::iterator uiitr=prim_tris_->begin(); uiitr!=prim_tris_->end();uiitr+=3) {
1225        osg::Vec3 e1=(*points)[*(uiitr+1)]-(*points)[(*uiitr)];
1226        osg::Vec3 e2=(*points)[*(uiitr+2)]-(*points)[*(uiitr+1)];
1227        osg::Vec3 n=e1^e2;
1228        n.normalize();
1229        //    if (n.z()<0) n=-n;
1230        norms->push_back(n);
1231    }
1232    return norms.release();
1233}
1234
1235deprecated_osg::Geometry * LinearConstraint::makeGeometry(const osg::Vec3Array *points)
1236{
1237    osg::ref_ptr<deprecated_osg::Geometry> gm=new deprecated_osg::Geometry; // the fill in road/railway
1238    if (_midline->size()>0) {
1239        osg::ref_ptr<osg::Vec3Array> locpts=getPoints(points);
1240        if (texture!="") {
1241            osg::Image* image = osgDB::readImageFile(texture.c_str());
1242            if (image)
1243            {
1244                osg::Texture2D* txt = new osg::Texture2D;
1245                osg::StateSet* stateset = gm->getOrCreateStateSet();
1246                txt->setImage(image);
1247                txt->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
1248                txt->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
1249                stateset->setTextureAttributeAndModes(0,txt,osg::StateAttribute::ON);
1250                osg::Material* material = new osg::Material;
1251                material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1252                material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1253                stateset->setAttribute(material,osg::StateAttribute::ON);
1254                stateset->setMode( GL_LIGHTING, osg::StateAttribute::ON );
1255            }
1256            gm->setTexCoordArray(0,getRoadTexcoords(locpts.get()));
1257        }
1258        gm->setVertexArray(locpts.get());
1259        gm->setNormalArray(getNormals(locpts.get()));
1260        gm->setNormalBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE);
1261        gm->addPrimitiveSet(getTriangles());
1262    }
1263
1264    return gm.release();
1265
1266}
1267
1268
1269
1270int main( int argc, char **argv )
1271{
1272
1273    // use an ArgumentParser object to manage the program arguments.
1274    osg::ArgumentParser arguments(&argc,argv);
1275
1276    // construct the viewer.
1277    osgViewer::Viewer viewer;
1278
1279    // create the scene from internal specified terrain/constraints.
1280    osg::ref_ptr<osg::Node> loadedModel = makedelaunay(0);
1281
1282    // if no model has been successfully loaded report failure.
1283    if (!loadedModel)
1284    {
1285        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
1286        return 1;
1287    }
1288
1289    // optimize the scene graph, remove redundant nodes and state etc.
1290    osgUtil::Optimizer optimizer;
1291    optimizer.optimize(loadedModel.get());
1292
1293    // pass the loaded scene graph to the viewer.
1294    viewer.setSceneData(loadedModel.get());
1295
1296    // copied from osgtessealte.cpp
1297    // add event handler for keyboard 'n' to retriangulate
1298    viewer.addEventHandler(new KeyboardEventHandler(viewer));
1299
1300    return viewer.run();
1301}
Note: See TracBrowser for help on using the browser.