VR-Forces 4.0.4 Class Documentation
Modify Terrain Example

The Modify Terrain example demonstrates the following:

How to Run

This example demonstrates how to programmatically modify an existing GDB (VR-Forces native format) terrain database. It manipulates the polygons in a terrain database.

Usage

(in bin directory)

modifyTerrainDb

To run the example:

  1. Run createTerrainDb to create a new flat terrain database named data\terrain\simpleTerrain.gdb.
  2. Run modifyTerrainDb.

In step 1, a simple terrain database named data\terrain\simpleTerrain.gdb will be created. This database is flat area (altitude zero everywhere). The modifyTerrainDb loads this database, and manipulates several of the polygons to form a depression in one corner. It saves the modified terrain database as data\terrain\modifiedSimpleTerrain.gdb. To view the terrain, open the database in TDBTool or vrfGui. The altitude of the terrain will vary.

Main Application File

/*******************************************************************************
** Copyright (c) 2003 MAK Technologies, Inc.
** All rights reserved.
*******************************************************************************/
/*******************************************************************************
** $RCSfile: main.cxx,v $ $Revision: 1.12 $ $State: Exp $
*******************************************************************************/

#include "gdb/terrainDb.h"
#include "terrainCS/ser_utm.h"
#include "geometry/point.h"
#include "geometry/surface.h"
#include "gdb/triInd.h"
#include <vlutil/vlPrint.h>
#include "gdb/allPoly.h"
#include "geometry/chord.h"
#include "gdb/gdbChordIntersectionRecord.h"
#include "terrainDbFactory/tdbManager.h"

// This example demonstrates how to use the terrain API to modify a simple
// terrain database in code.  It takes a simple terrain database and creates a
// divot in the terrain in the lower right quandrant of the terrain database.
// It reads in the ..\data\terrain\\simpleTerrain.gdb created by the 
// createTerrainDb example, and saves out the modified terrain database to the
// file ..\data\terrain\modifiedTerrain.gdb.


int main(int argc, char** argv)
{
   DtTdbManager manager;

   // Load the terrain database using a terrain reader that knows how to load 
   // MAK gdb terrain files.

   if(!manager.load("..\\data\\terrain\\simpleTerrain.gdb"))
   {
      DtWarn("Couldn't load terrain database file -- please run the createTerrainDb example to create simpleTerrain.gdb\n");
      return 1;
   }

   // (The simpleTerrain.gdb file is a 1000 meter x 1000 meter square UTM database,
   // comprised of 8 - 500 x 500 meters square triangles, with zero elevations, 
   // forming 4 quadrants.  
   // Triangles and Polygons in the terrain database are all indirect, either
   // DtTriangleIndirect or DtPolygonIndirect.
   //
   // We will be removing the lower-right quadrant in the terrain (two triangles 
   // comprising a 500 x 500 meter square area.)  We'll do intersection tests 
   // to find the triangles. 
   
   // Get the closest intersection to the specified x,y locations,
   // along the up/down direction, 
   // (750, 200).
   // (750, 300).

   // Try to intersect the terrain to get the left triangle
   // Note, we can use closestIntersection because we know that there is only
   // one intersection.  If we needed the topmost intersection point if multiple
   // levels of terrain existed, we would have to create a chord and use it for
   // intersection tests manually.
   DtGdbChordIntersectionRecord intersectionRecord;
   if(!manager.terrainDatabase()->closestIntersection(DtVector(750,200,0), intersectionRecord))
   {
      // Unlikely to happen - we know the geometry of simpleTerrain.gdb
      DtWarn("Intersection test failed!\n");
      return 1;
   }

   // Try to intersect the terrain again to get the right triangle.
   DtGdbChordIntersectionRecord intersectionRecord2;
   if(!manager.terrainDatabase()->closestIntersection(DtVector(750, 300, 0), intersectionRecord2))
   {
      // Unlikely to happen - we know the geometry of simpleTerrain.gdb
      DtWarn("Intersection test failed!\n");
      return 1;
   }

   // Get the polygons (we know they're triangles) from 
   // the chord intersection records.
   DtAllTypesPolygon* leftPolygon = intersectionRecord.polygon();
   DtAllTypesPolygon* rightPolygon = intersectionRecord2.polygon();
   if(!leftPolygon || !rightPolygon)
   {
      // Again, this is unlikely to happen - we know the geometry of 
      // simpleTerrain.gdb
      DtWarn("At least one polygon not found at intersection!\n");
      return 1;
   }
   
   // This vertex will be the vertex at the base of the divot.
   DtPoint baseVertex(750.0, 250.0, -60.0);

   // We will be replacing the polygon we intersected with 4 new ones.  The
   // new polygons will be triangles attached to where the old polgon tied
   // in to the database, with a common vertex at the base of the hole (60 
   // meters deep, at x-y location (750, 250).
   
   // Get the vertices of the polygon we're going to remove
   DtPoint vertex0;
   DtPoint vertex1;
   DtPoint vertex2;
   DtPoint vertex3;

   leftPolygon->getVertex(vertex0, 0);
   leftPolygon->getVertex(vertex1, 1);
   leftPolygon->getVertex(vertex2, 2);
   rightPolygon->getVertex(vertex3, 2);
   
   DtSurface surface;
   surface.setIsGround(true);
   surface.setIsSoftSoil(true);
   // Different color than existing terrain created in createTerrainDb project...
   surface.setColor(DtColor(110, 95, 90, 0));

   // Create new polygons making up the depression in the terrain.
   DtTriangleIndirect* newTri0 = NULL;
   DtTriangleIndirect* newTri1 = NULL;
   DtTriangleIndirect* newTri2 = NULL;
   DtTriangleIndirect* newTri3 = NULL;

   // Create a new polygon (a triangle) with one side formed by edge of old
   // polygon and with one vertex at baseVertex (bottom of our new hole).
   newTri0 = manager.terrainDatabase()->createTriangle(vertex0, vertex1, baseVertex, surface);

   // Repeat for rest of the new polygons making up the hole.
   newTri1 = manager.terrainDatabase()->createTriangle(vertex1, vertex2, baseVertex, surface);
   newTri2 = manager.terrainDatabase()->createTriangle(vertex2, vertex3, baseVertex, surface);
   newTri3 = manager.terrainDatabase()->createTriangle(vertex3, vertex0, baseVertex, surface);

   if (newTri0 == NULL ||
       newTri1 == NULL ||
       newTri2 == NULL ||
       newTri3 == NULL)
   {
      DtWarn("Couldn't create new indirect triangles for divit in the ground.\n");
      return 1;
   }

   // remove old triangles from database
   manager.terrainDatabase()->removeTerrainNode(leftPolygon);
   manager.terrainDatabase()->removeTerrainNode(rightPolygon);

   // Eliminates duplicate vertices (introduced by the triangles we just added).
   // Specify tolerance of 0.01 meters - vertices within 0.01 meters of each 
   // other are considered duplicates of each other and compacted into one vertex.
   manager.terrainDatabase()->eliminateDuplicateVertices(0.01);

   // Eliminates duplicate surfaces in the same manner as eliminating duplicate
   // vertices.  No tolerance is used as surfaces are either equal or not.
   manager.terrainDatabase()->eliminateDuplicateSurfaces();

   // Save new terrain database to gdb format file
   manager.save("..\\data\\terrain\\modifiedSimpleTerrain.gdb");

   DtInfo << "Creating terrain " << DtFilename("..\\data\\terrain\\modifiedSimpleTerrain.gdb").c_str() << std::endl;

   return 0;
}


Document ID: Generated on Fri Jun 29 16:33:32 EDT 2012 from SVN revision 116588
Copyright © 2005-2012 VT MÄK Inc. All Rights Reserved (www.mak.com)