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