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 */
45 class WallConstraint: public osgUtil::DelaunayConstraint { // forces lines to eb edge
46     // wall constraint - can generate a wall at the coordinates of the constraint
47 public:
48 /** if you derive a class from DelaunayConstraint then you can create
49 *  a specific geometry creation routine.
50     */
WallConstraint()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 */
makeWall(void) const57     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;
getWallNormals(void) const65     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
setWallTexrep(const float w,const float h)95     void setWallTexrep(const float w,const float h) { txxrepWall=w;txyrepWall=h;}
96 
97     /** Wall Geometry will return with this texture applied: */
setTexture(const char * tx)98     void setTexture(const char *tx) { texture=tx;}
99     /** fence/wall height */
setHeight(const float h)100     void setHeight(const float h) { height=h;}
101 protected:
102     float height;
103     std::string texture;
104     float txxrepWall, txyrepWall;
105 };
106 class ArealConstraint: public osgUtil::DelaunayConstraint { // forces edges of an area to fit triangles
107     // areal constraint - general nonuniform field, forest, lake etc.
108 public:
109 /** if you derive a class from DelaunayConstraint then you can create
110 *  a specific geometry creation routine.
111     */
ArealConstraint()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
setTexrep(const float w,const float h)134     void setTexrep(const float w,const float h) { txxrepArea=w;txyrepArea=h;}
setWallTexrep(const float w,const float h)135     void setWallTexrep(const float w,const float h) { txxrepWall=w;txyrepWall=h;}
136     /** Geometry will return with this texture applied: */
setWallTexture(const char * tx)137     void setWallTexture(const char *tx) { walltexture=tx;}
138     /** Geometry will return with this texture applied: */
setTexture(const char * tx)139     void setTexture(const char *tx) { texture=tx;}
140     /** fence/wall height */
setHeight(const float h)141     void setHeight(const float h) { height=h;}
142     std::string walltexture;
143 protected:
144     float height;
145     std::string texture;
146     float txxrepArea, txyrepArea;
147     float txxrepWall, txyrepWall;
148 };
149 
150 class 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. */
154 public:
LinearConstraint()155     LinearConstraint() : osgUtil::DelaunayConstraint(), txxrepAlong(10), txyrepAcross(10), width(2) { }
156 
157     /** geometry creation parameters */
158     /* Width of linear feature (eg road, railway) */
setWidth(const float w)159     void setWidth(const float w) { width=w;}
160 
161     /** Texture repeat distance across linear (often equal to width) and along its length */
setTexrep(const float w,const float h)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: */
setTexture(const char * tx)181     void setTexture(const char *tx) { texture=tx;}
182 
183 protected:
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 
194 class 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. */
197 public:
pyramid()198     pyramid() : _side(100.) {}
199 
setpos(const osg::Vec3 p,const float size)200     void setpos(const osg::Vec3 p, const float size) { _pos=p;_side=size;}
201 
makeGeometry(void) const202     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::ref_ptr<osg::Image> image = osgDB::readRefImageFile("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     }
calcVertices(void)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     }
262 private:
263     osg::Vec3 _pos; // where the pyramid is
264     float _side ; // length of side
265 };
266 
getheight(const float x,const float y)267 float 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 }
getpt(const int np)271 osg::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 }
createHUD(const int ndcs,std::string what)283 osg::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 }
makedelaunay(const int ndcs)347 osg::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::ref_ptr<osg::Image> image = osgDB::readRefImageFile("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 
713 class KeyboardEventHandler : public osgGA::GUIEventHandler
714 { // extra event handler traps 'n' key to re-triangulate the basic terrain.
715 public:
716 
KeyboardEventHandler(osgViewer::Viewer & vr)717     KeyboardEventHandler(osgViewer::Viewer &vr):
718       viewer(vr), iview(0) {}
719 
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter &)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 
getWall(const float height) const746 osg::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 }
getWallTexcoords(const float height) const770 osg::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 }
makeWallGeometry() const816 osg::Geometry *WallConstraint::makeWallGeometry() const
817 {
818     osg::ref_ptr<osg::Geometry> gm=new osg::Geometry; // the wall
819     if (texture!="") {
820         osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(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 
getWallNormals() const844 osg::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 
getWall(const float height) const872 osg::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 
getWallTexcoords(const float height) const896 osg::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 }
makeCanopy(void) const941 osg::DrawArrays* ArealConstraint::makeCanopy( void ) const
942 {
943     return (new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,3*_interiorTris.size()));
944 }
getCanopy(const osg::Vec3Array * points,const float height) const945 osg::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 }
getCanopyNormals(const osg::Vec3Array * points) const958 osg::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 
getCanopyTexcoords(const osg::Vec3Array * points) const972 osg::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 
makeWall(void) const984 osg::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 
makeWallGeometry(osg::Vec3Array * pt)990 deprecated_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::ref_ptr<osg::Image> image = osgDB::readRefImageFile(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 
makeAreal(osg::Vec3Array * points)1054 deprecated_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::ref_ptr<osg::Image> image = osgDB::readRefImageFile(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 
setVertices(osg::Vec3Array * lp,const float w)1085 void 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 
makeRoad(void) const1120 osg::DrawArrays* LinearConstraint::makeRoad(void ) const
1121 {
1122     return     new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,2*_midline->size());
1123 
1124 }
1125 
getRoadNormals(const osg::Vec3Array *) const1126 osg::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 }
getRoadVertices() const1146 osg::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 
getRoadTexcoords(const osg::Vec3Array * points)1167 osg::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 }
getNormals(const osg::Vec3Array * points)1221 osg::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 
makeGeometry(const osg::Vec3Array * points)1235 deprecated_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::ref_ptr<osg::Image> image = osgDB::readRefImageFile(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 
main(int argc,char ** argv)1270 int 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 }
1302