block.cc
Go to the documentation of this file.
1 #include "region.hh"
2 #include "worldfile.hh"
3 
4 using namespace Stg;
5 using std::vector;
6 
7 static void canonicalize_winding(vector<point_t> &pts);
8 
12 Block::Block(BlockGroup *group, const std::vector<point_t> &pts, const Bounds &zrange)
13  : group(group), pts(pts), local_z(zrange), global_z(), rendered_cells()
14 {
15  assert(group);
16  // canonicalize_winding(this->pts);
17 }
18 
21  : group(group), pts(), local_z(), global_z(), rendered_cells()
22 {
23  assert(group);
24  assert(wf);
25  assert(entity);
26 
27  Load(wf, entity);
28 }
29 
31 {
32  UnMap(0);
33  UnMap(1);
34 }
35 
36 void Block::Translate(double x, double y)
37 {
38  FOR_EACH (it, pts) {
39  it->x += x;
40  it->y += y;
41  }
42 
44 }
45 
50 {
51  // assume the polygon fits in a square a billion m a side
52  double min = billion;
53  double max = -billion;
54 
55  FOR_EACH (it, pts) {
56  if (it->y > max)
57  max = it->y;
58  if (it->y < min)
59  min = it->y;
60  }
61 
62  // return the value half way between max and min
63  return (min + (max - min) / 2.0);
64 }
65 
70 {
71  // assume the polygon fits in a square a billion m a side
72  double min = billion;
73  double max = -billion;
74 
75  FOR_EACH (it, pts) {
76  if (it->x > max)
77  max = it->x;
78  if (it->x < min)
79  min = it->x;
80  }
81 
82  // return the value half way between maxx and min
83  return (min + (max - min) / 2.0);
84 }
85 
88 void Block::SetCenter(double x, double y)
89 {
90  Translate(x - CenterX(), y - CenterY());
91 }
92 
95 void Block::SetCenterY(double y)
96 {
97  Translate(0, y - CenterY());
98 }
99 
102 void Block::SetCenterX(double x)
103 {
104  Translate(x - CenterX(), 0);
105 }
106 
107 void Block::SetZ(double min, double max)
108 {
109  local_z.min = min;
110  local_z.max = max;
111 
112  // force redraw
114 }
115 
116 void Block::AppendTouchingModels(std::set<Model *> &touchers)
117 {
118  unsigned int layer = group->mod.world->updates % 2;
119 
120  // for every cell we are rendered into
121  FOR_EACH (cell_it, rendered_cells[layer])
122  // for every block rendered into that cell
123  FOR_EACH (block_it, (*cell_it)->GetBlocks(layer)) {
124  if (!group->mod.IsRelated(&(*block_it)->group->mod))
125  touchers.insert(&(*block_it)->group->mod);
126  }
127 }
128 
130 {
131  // printf( "model %s block %p test collision...\n", mod->Token(), this );
132 
133  // find the set of cells we would render into given the current global pose
134  // GenerateCandidateCells();
135 
136  if (group->mod.vis.obstacle_return) {
137  if (global_z.min < 0)
138  return group->mod.world->GetGround();
139 
140  unsigned int layer = group->mod.world->updates % 2;
141 
142  // for every cell we may be rendered into
143  FOR_EACH (cell_it, rendered_cells[layer]) {
144  // for every block rendered into that cell
145  FOR_EACH (block_it, (*cell_it)->GetBlocks(layer)) {
146  Block *testblock = *block_it;
147  Model *testmod = &testblock->group->mod;
148 
149  // printf( " testing block %p of model %s\n", testblock,
150  // testmod->Token() );
151 
152  // if the tested model is an obstacle and it's not attached to this
153  // model
154  if ((testmod != &group->mod) && testmod->vis.obstacle_return
155  && (!group->mod.IsRelated(testmod)) &&
156  // also must intersect in the Z range
157  testblock->global_z.min <= global_z.max && testblock->global_z.max >= global_z.min) {
158  // puts( "HIT");
159  return testmod; // bail immediately with the bad news
160  }
161  }
162  }
163  }
164 
165  // printf( "model %s block %p collision done. no hits.\n", mod->Token(), this
166  // );
167  return NULL; // no hit
168 }
169 
170 void Block::Map(unsigned int layer)
171 {
172  // calculate the global pixel coords of the block vertices
173  // and render this block's polygon into the world
174  group->mod.world->MapPoly(group->mod.LocalToPixels(pts), this, layer);
175 
176  // update the block's absolute z bounds at this rendering
177  Pose gpose(group->mod.GetGlobalPose());
178  gpose.z += group->mod.geom.pose.z;
179  global_z.min = local_z.min + gpose.z;
180  global_z.max = local_z.max + gpose.z;
181 }
182 
183 void Block::UnMap(unsigned int layer)
184 {
185  FOR_EACH (it, rendered_cells[layer])
186  (*it)->RemoveBlock(this, layer);
187 
188  rendered_cells[layer].clear();
189 }
190 
191 void swap(int &a, int &b)
192 {
193  int tmp = a;
194  a = b;
195  b = tmp;
196 }
197 
198 void Block::Rasterize(uint8_t *data, unsigned int width, unsigned int height, meters_t cellwidth,
199  meters_t cellheight)
200 {
201  // printf( "rasterize block %p : w: %u h: %u scale %.2f %.2f offset %.2f
202  // %.2f\n",
203  // this, width, height, scalex, scaley, offsetx, offsety );
204 
205  const size_t pt_count = pts.size();
206  for (size_t i = 0; i < pt_count; ++i) {
207  // convert points from local to model coords
208  point_t mpt1 = pts[i]; // BlockPointToModelMeters( pts[i] );
209  point_t mpt2 = pts[(i + 1) % pt_count]; // BlockPointToModelMeters( pts[(i+1)%pt_count] );
210 
211  // record for debug visualization
212  group->mod.rastervis.AddPoint(mpt1.x, mpt1.y);
213 
214  // shift to the bottom left of the model
215  mpt1.x += group->mod.geom.size.x / 2.0;
216  mpt1.y += group->mod.geom.size.y / 2.0;
217  mpt2.x += group->mod.geom.size.x / 2.0;
218  mpt2.y += group->mod.geom.size.y / 2.0;
219 
220  // convert from meters to cells
221  point_int_t a(floor(mpt1.x / cellwidth), floor(mpt1.y / cellheight));
222  point_int_t b(floor(mpt2.x / cellwidth), floor(mpt2.y / cellheight));
223 
224  // render a line in the output bitmap for this edge, from mpt1
225  // to mpt2
226  bool steep = abs(b.y - a.y) > abs(b.x - a.x);
227  if (steep) {
228  swap(a.x, a.y);
229  swap(b.x, b.y);
230  }
231 
232  if (a.x > b.x) {
233  swap(a.x, b.x);
234  swap(a.y, b.y);
235  }
236 
237  double dydx = (double)(b.y - a.y) / (double)(b.x - a.x);
238  double y = a.y;
239  for (int x = a.x; x <= b.x; ++x) {
240  if (steep) {
241  if (!(floor(y) >= 0))
242  continue;
243  if (!(floor(y) < (int)width))
244  continue;
245  if (!(x >= 0))
246  continue;
247  if (!(x < (int)height))
248  continue;
249  } else {
250  if (!(x >= 0))
251  continue;
252  if (!(x < (int)width))
253  continue;
254  if (!(floor(y) >= 0))
255  continue;
256  if (!(floor(y) < (int)height))
257  continue;
258  }
259 
260  if (steep)
261  data[(int)floor(y) + (x * width)] = 1;
262  else
263  data[x + ((int)floor(y) * width)] = 1;
264  y += dydx;
265  }
266  }
267 }
268 
270 {
271  // draw the top of the block - a polygon at the highest vertical
272  // extent
273 
274  glBegin(GL_POLYGON);
275  FOR_EACH (it, pts)
276  glVertex3f(it->x, it->y, local_z.max);
277  glEnd();
278 }
279 
281 {
282  // construct a strip that wraps around the polygon
283  glBegin(GL_QUAD_STRIP);
284 
285  FOR_EACH (it, pts) {
286  glVertex3f(it->x, it->y, local_z.max);
287  glVertex3f(it->x, it->y, local_z.min);
288  }
289  // close the strip
290  glVertex3f(pts[0].x, pts[0].y, local_z.max);
291  glVertex3f(pts[0].x, pts[0].y, local_z.min);
292  glEnd();
293 }
294 
296 {
297  glBegin(GL_POLYGON);
298  FOR_EACH (it, pts)
299  glVertex2f(it->x, it->y);
300  glEnd();
301 }
302 
304 {
305  DrawSides();
306  DrawTop();
307 }
308 
309 void Block::Load(Worldfile *wf, int entity)
310 {
311  const size_t pt_count = wf->ReadInt(entity, "points", 0);
312 
313  char key[256];
314  for (size_t p = 0; p < pt_count; ++p) {
315  snprintf(key, sizeof(key), "point[%d]", (int)p);
316 
317  point_t pt(0, 0);
318  wf->ReadTuple(entity, key, 0, 2, "ll", &pt.x, &pt.y);
319  pts.push_back(pt);
320  }
321 
323 
324  wf->ReadTuple(entity, "z", 0, 2, "ll", &local_z.min, &local_z.max);
325 }
326 
328 // utility functions to ensure block winding is consistent and matches OpenGL's
329 // default
330 
331 static
333  void
335 {
336  while (angle < 0)
337  angle += 2 * M_PI;
338 }
339 
340 static
342  void
344 {
345  while (angle < -M_PI)
346  angle += 2 * M_PI;
347  while (M_PI < angle)
348  angle -= 2 * M_PI;
349 }
350 
351 static
353  radians_t
355 {
356  radians_t a1 = atan2(v1.y, v1.x);
357  positivize(a1);
358 
359  radians_t a2 = atan2(v2.y, v2.x);
360  positivize(a2);
361 
362  radians_t angle_change = a2 - a1;
363  pi_ize(angle_change);
364 
365  return angle_change;
366 }
367 
368 static
370  vector<point_t>
371  find_vectors(vector<point_t> const &pts)
372 {
373  vector<point_t> vs;
374  assert(2 <= pts.size());
375  for (unsigned i = 0, n = pts.size(); i < n; ++i) {
376  unsigned j = (i + 1) % n;
377  vs.push_back(point_t(pts[j].x - pts[i].x, pts[j].y - pts[i].y));
378  }
379  assert(vs.size() == pts.size());
380  return vs;
381 }
382 
383 static
386  radians_t
387  angles_sum(vector<point_t> const &vs)
388 {
389  radians_t angle_sum = 0;
390  for (unsigned i = 0, n = vs.size(); i < n; ++i) {
391  unsigned j = (i + 1) % n;
392  angle_sum += angle_change(vs[i], vs[j]);
393  }
394  return angle_sum;
395 }
396 
397 static
399  bool
400  is_canonical_winding(vector<point_t> const &ps)
401 {
402  return (0 < angles_sum(find_vectors(ps)));
403 }
404 
405 static
409  // Note that a simple line that doubles back on itself has an
410  // angle sum of 0, but that's intrinsic to a line - its winding could
411  // be either way.
412  void
413  canonicalize_winding(vector<point_t> &ps)
414 {
415  if (not is_canonical_winding(ps)) {
416  std::reverse(ps.begin(), ps.end());
417  }
418 }
Bounds local_z
z extent in local coords.
Definition: stage.hh:1193
Model class
Definition: stage.hh:1651
void swap(int &a, int &b)
Definition: block.cc:191
void BuildDisplayList()
Definition: blockgroup.cc:176
static radians_t angle_change(point_t v1, point_t v2)
util; How much was v1 rotated to get to v2?
Definition: block.cc:354
static bool is_canonical_winding(vector< point_t > const &ps)
Util.
Definition: block.cc:400
void DrawSides()
Definition: block.cc:280
double CenterY()
Definition: block.cc:49
uint64_t updates
the number of simulated time steps executed so far
Definition: stage.hh:856
double max
largest value in range, initially zero
Definition: stage.hh:412
Pose GetGlobalPose() const
Definition: model.cc:1200
The Stage library uses its own namespace.
Definition: canvas.hh:8
Block(BlockGroup *group, const std::vector< point_t > &pts, const Bounds &zrange)
Definition: block.cc:12
void DrawTop()
Definition: block.cc:269
meters_t x
Definition: stage.hh:243
Model & mod
Definition: stage.hh:1216
Geom geom
Definition: stage.hh:1777
double CenterX()
Definition: block.cc:69
int ReadTuple(const int entity, const char *name, const unsigned int first, const unsigned int num, const char *format,...)
Definition: worldfile.cc:1572
double min
smallest value in range, initially zero
Definition: stage.hh:410
const double billion
Definition: stage.hh:148
void Map(unsigned int layer)
Definition: block.cc:170
Size size
extent
Definition: stage.hh:379
std::vector< point_int_t > LocalToPixels(const std::vector< point_t > &local) const
Definition: model.cc:469
void SetCenter(double x, double y)
Definition: block.cc:88
void DrawSolid(bool topview)
Definition: block.cc:303
meters_t z
location in 3 axes
Definition: stage.hh:259
static void canonicalize_winding(vector< point_t > &pts)
Definition: block.cc:413
void Load(Worldfile *wf, int entity)
Definition: block.cc:309
Bounds global_z
z extent in global coordinates.
Definition: stage.hh:1194
std::vector< point_t > pts
points defining a polygon.
Definition: stage.hh:1192
Pose pose
position
Definition: stage.hh:378
void SetCenterY(double y)
Definition: block.cc:95
meters_t y
Definition: stage.hh:446
double meters_t
Definition: stage.hh:191
meters_t x
Definition: stage.hh:446
meters_t y
Definition: stage.hh:243
Model * TestCollision()
Definition: block.cc:129
bool IsRelated(const Model *testmod) const
Definition: model.cc:441
void SetZ(double min, double max)
Definition: block.cc:107
static void pi_ize(radians_t &angle)
util; puts angle into -pi/2, pi/2
Definition: block.cc:343
static vector< point_t > find_vectors(vector< point_t > const &pts)
util; find vectors between adjacent points, pts[next] - pts[cur]
Definition: block.cc:371
void AddPoint(meters_t x, meters_t y)
Definition: model.cc:984
class Stg::Model::Visibility vis
void AppendTouchingModels(std::set< Model *> &touchers)
Definition: block.cc:116
void Rasterize(uint8_t *data, unsigned int width, unsigned int height, meters_t cellwidth, meters_t cellheight)
Definition: block.cc:198
Stg::Model::RasterVis rastervis
static void positivize(radians_t &angle)
util; puts angle into [0, 2pi)
Definition: block.cc:334
std::vector< Cell * > rendered_cells[2]
Definition: stage.hh:1199
World * world
Pointer to the world in which this model exists.
Definition: stage.hh:1901
void Translate(double x, double y)
Definition: block.cc:36
int ReadInt(int entity, const char *name, int value)
Definition: worldfile.cc:1470
static radians_t angles_sum(vector< point_t > const &vs)
Definition: block.cc:387
void SetCenterX(double y)
Definition: block.cc:102
#define FOR_EACH(I, C)
Definition: stage.hh:580
~Block()
Definition: block.cc:30
void DrawFootPrint()
Definition: block.cc:295
double radians_t
Definition: stage.hh:194
void MapPoly(const std::vector< point_int_t > &poly, Block *block, unsigned int layer)
Definition: world.cc:990
BlockGroup * group
The BlockGroup to which this Block belongs.
Definition: stage.hh:1190
Model * GetGround()
Definition: stage.hh:1125
void UnMap(unsigned int layer)
Definition: block.cc:183


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Mon Feb 28 2022 23:48:55