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

Revision 13502, 58.6 kB (checked in by robert, 9 hours ago)

Added NodeVisitor::INTERSECTION_VISITOR VisitorType?

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