genBuilding/main.cpp

Go to the documentation of this file.
00001 /*
00002  * main.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  * Quick program to autogenerate multi-zone buildings.
00008  */
00009 
00010 // includes --------------------------------------------------------------------
00011 #include <iostream>
00012 
00013 #include "datahash/datahash_text.h"
00014 #include "datahash/datahash_util.h"
00015 #include "geometry/geometry_3d.h"
00016 #include "geometry/matrix_4.h"
00017 #include "perf/perf.h"
00018 
00019 
00020 
00021 static const float s_radiansPerDegree           = M_PI / 180.0;
00022 
00023 
00024 // an axis determines a chain of rooms, with winding factors etc
00025 struct axis_t {
00026         // constructor, manipulators
00027         axis_t(void) throw() { this->clear(); }
00028         void clear(void) throw() {
00029                         windAngle.clear();
00030                         windStep.clear();
00031                         run = 0;
00032                 }
00033 
00034         // data fields
00035         point3d_t       windAngle;
00036         point3d_t       windStep;
00037         int             run;
00038 };
00039 
00040 
00041 typedef std::map<std::string, smart_ptr<axis_t> > axis_map_t;
00042 
00043 
00044 // this is the overall state of the building (or cluster thereof)
00045 struct state_t {
00046         // constructor, manipulators
00047         axis_t * getAxis(IN const char * name) {
00048                         ASSERT(name, "null");
00049                         axis_map_t::iterator i = axisMap.find(name);
00050                         ASSERT_THROW(axisMap.end() != i,
00051                             "No such axis: '" << name << "'");
00052                         ASSERT(i->second, "null axis in map?");
00053                         return i->second;
00054                 }
00055 
00056         // data fields
00057         axis_map_t      axisMap;
00058 };
00059 
00060 
00061 
00063 //
00064 //      static helper methods
00065 //
00067 
00068 static smart_ptr<axis_t>
00069 parseAxis
00070 (
00071 IN const Datahash * hash
00072 )
00073 {
00074         smart_ptr<axis_t> axis = new axis_t;
00075         ASSERT(axis, "out of memory");
00076 
00077         axis->run = getInt(hash, "run");
00078 
00079         // get axis winding parameters
00080         smart_ptr<Datahash> wind = getSubhash(hash, "winding");
00081         ASSERT(wind, "null");
00082 
00083         const char * rot = getOptionalString(wind, "rot", "");
00084         const char * step = getOptionalString(wind, "step", "");
00085 
00086         point3d_t rotateDegrees;
00087         parsePoint3d(rot, rotateDegrees);
00088         axis->windAngle = s_radiansPerDegree * rotateDegrees;
00089         parsePoint3d(step, axis->windStep);
00090 
00091         return axis;
00092 }
00093 
00094 
00095 
00096 static void
00097 getAxisRegistry
00098 (
00099 IN axis_map_t& map,
00100 IN const Datahash * input
00101 )
00102 {
00103         ASSERT(input, "null");
00104         map.clear();
00105 
00106         Datahash::iterator_t i;
00107         input->getIterator("axis", i);
00108         while (const hash_value_t * phv = input->getNextElementUnsafe(i)) {
00109                 if (!phv->hash)
00110                         continue;       // skip this one
00111         
00112                 smart_ptr<axis_t> axis = parseAxis(phv->hash);
00113                 if (axis) {
00114                         const char * name = getString(phv->hash, "name");
00115                         ASSERT_THROW(map.end() == map.find(name),
00116                             "Multiple axes with same name: '" << name << "'");
00117                         map[name] = axis;
00118                 }
00119         }
00120         DPRINTF("Parsed %d axes", map.size());
00121 }
00122 
00123 
00124 
00125 static void
00126 updateTransformation
00127 (
00128 IN const matrix4_t& rootT,
00129 IN const axis_t * axis,
00130 OUT matrix4_t& T
00131 )
00132 {
00133         ASSERT(axis, "null");
00134 
00135         // first, apply rotation
00136         matrix4_t rot;
00137         rot.setYRotation(axis->windAngle.y);
00138 
00139         // next, apply translation
00140         matrix4_t trans;
00141         trans.setTranslation(axis->windStep);
00142 
00143         matrix4_t next;
00144         next.setToProductOf(rot, trans);
00145 
00146         T.setToProductOf(rootT, next);
00147 }
00148 
00149 
00150 
00151 static void
00152 generateRooms
00153 (
00154 IN state_t& state,
00155 IN const matrix4_t& rootT,
00156 IN const axis_t * axis,
00157 IN int count
00158 )
00159 {
00160         ASSERT(axis, "null");
00161         ASSERT(axis->run >= 0, "bad run?");
00162         ASSERT(count >= 0, "invalid room count: %d", count);
00163 
00164         // recursive routine!
00165         if (count >= axis->run)
00166                 return;         // end of recursion
00167 
00168         // apply transformation
00169         matrix4_t T;
00170         updateTransformation(rootT, axis, T);
00171 
00172         // position of next room
00173         point3d_t p(0, 0, 0);
00174         point3d_t q = T * p;
00175 
00176         DPRINTF("Room %d:", count);
00177         q.dump("  position");
00178 
00179         // recurse
00180         generateRooms(state, T, axis, count + 1);
00181 }
00182 
00183 
00184 
00185 static void
00186 genBuilding
00187 (
00188 IN const Datahash * input
00189 )
00190 {
00191         ASSERT(input, "null");
00192 
00193         state_t state;
00194 
00195         // get registry of axes
00196         getAxisRegistry(state.axisMap, input);
00197 
00198         // what is the root axis name?
00199         const char * rootName = getString(input, "rootAxis");
00200         DPRINTF("Root axis name: '%s'", rootName);
00201 
00202         axis_t * axis = state.getAxis(rootName);
00203         ASSERT(axis, "null root axis");
00204 
00205         // first, generate rooms
00206         matrix4_t T;
00207         T.setIdentity();
00208         {
00209                 perf::Timer timer("room-generation");
00210                 generateRooms(state, T, axis, 0);
00211         }
00212 }
00213 
00214 
00215 
00217 //
00218 //      entry point
00219 //
00221 
00222 int
00223 main
00224 (
00225 IN int argc,
00226 IN const char * argv[]
00227 )
00228 {
00229         int retval = 0;
00230         ASSERT(2 == argc,
00231             "usage: genBuilding <input-file>");
00232         const char * infile = argv[1];
00233         DPRINTF("Using input file: '%s'", infile);
00234 
00235         try {
00236                 perf::Timer timer("overall timer");
00237 
00238                 smart_ptr<Datahash> input = readHashFromTextFile(infile);
00239                 ASSERT(input, "null");
00240 
00241                 genBuilding(input);
00242 
00243         } catch (std::exception& e) {
00244                 retval = 1;
00245                 DPRINTF("Exception: %s", e.what());
00246         }
00247 
00248         perf::dumpTimingSummary(std::cerr);
00249 
00250         return retval;
00251 }
00252