Flatland

Documentation

SourceForge.net Logo

shapes.cpp

Go to the documentation of this file.
00001 // Summary: Defines methods for Quad, Wall, Block, Circle, Line, Terrain.
00002 // Copyright: 2007  Philip Rideout.  All rights reserved.
00003 // License: see bsd-license.txt
00004 
00005 #include <ode/ode.h>
00006 #include <flatland/shapes.hpp>
00007 #include <flatland/intersection.hpp>
00008 #include <cassert>
00009 #include <algorithm>
00010 
00011 using namespace Flatland;
00012 
00013 Quad::Quad(float width, float height)
00014 {
00015     extent[0] = width / 2;
00016     extent[1] = height / 2;
00017     UpdateBounds();
00018 }
00019 
00020 Block::Block(vec2 topleft, vec2 bottomright) : Quad(bottomright.x - topleft.x, bottomright.y - topleft.y)
00021 {
00022     SetCenter(vec2(topleft.x + bottomright.x, topleft.y + bottomright.y) / 2);
00023     SetAxis(vec2(1, 0));
00024     UpdateBounds();
00025 }
00026 
00027 Block::Block(vec2 center, float width, float height) : Quad(width, height)
00028 {
00029     SetCenter(center);
00030     SetAxis(vec2(1, 0));
00031     UpdateBounds();
00032 }
00033 
00034 Block::Block(float left, float top, float right, float bottom) : Quad(right - left, bottom - top)
00035 {
00036     SetCenter(vec2(right + left, top + bottom) / 2);
00037     SetAxis(vec2(1, 0));
00038     UpdateBounds();
00039 }
00040 
00041 Line::Line(vec2 a, vec2 b) : Quad((b - a).length(), 0)
00042 {
00043     SetCenter((a + b) / 2);
00044     SetAxis((b - a).hat());
00045     UpdateBounds();
00046 }
00047 
00048 Terrain::Terrain(const vec2 &start) : previous(start)
00049 {
00050     vertices.push_back(start);
00051     spans[start.x] = 0;
00052 }
00053 
00054 Circle::Circle(const vec2 &center, float radius) : radius(radius)
00055 {
00056     SetCenter(center);
00057     UpdateBounds();
00058 }
00059 
00060 void Quad::UpdateBounds()
00061 {
00062     vec2 eaxis[2] = {EAxis(0), EAxis(1)};
00063 
00064     corners[0] = center - eaxis[0] - eaxis[1];
00065     corners[1] = center + eaxis[0] - eaxis[1];
00066     corners[2] = center + eaxis[0] + eaxis[1];
00067     corners[3] = center - eaxis[0] + eaxis[1];
00068 
00069     bounds.left = std::min(std::min(std::min(corners[0].x, corners[1].x), corners[2].x), corners[3].x);
00070     bounds.top = std::min(std::min(std::min(corners[0].y, corners[1].y), corners[2].y), corners[3].y);
00071     bounds.right = std::max(std::max(std::max(corners[0].x, corners[1].x), corners[2].x), corners[3].x);
00072     bounds.bottom = std::max(std::max(std::max(corners[0].y, corners[1].y), corners[2].y), corners[3].y);
00073 }
00074 
00075 bool Quad::Contains(const vec2 &v) const
00076 {
00077     vec2 p = v - center;
00078     p = p.rotate(axis);
00079     return fabsf(p.x) < extent[0] && fabsf(p.y) < extent[1];
00080 }
00081 
00082 /// add a vertex to the terrain shape.
00083 void Terrain::push_back(const vec2 &v)
00084 {
00085     assert(v.x > previous.x && "terrains must be built in left-to-right order");
00086     lines.push_back(Line(previous, v));
00087     spans[v.x] = lines.size();
00088     previous = v;
00089     vertices.push_back(v);
00090 }
00091 
00092 bool Terrain::GetIndexRange(float left, float right, int &lower, int &upper) const
00093 {
00094     SpanMap::const_iterator lowerBound = spans.lower_bound(left);
00095     if (lowerBound == spans.end())
00096         return false;
00097 
00098     lower = lowerBound->second - 1;
00099     if (lower < 0)
00100         lower = 0;
00101     assert(lower < (int) lines.size());
00102 
00103     SpanMap::const_iterator upperBound = spans.upper_bound(right);
00104     if (upperBound == spans.end())
00105         upper = lines.size() - 1;
00106     else
00107         upper = upperBound->second - 1;
00108     assert(upper >= 0 && upper < (int) lines.size());
00109 
00110     return true;
00111 }
00112 
00113 void Terrain::UpdateBounds()
00114 {
00115     bounds.left = HUGE_VAL;
00116     bounds.top = HUGE_VAL;
00117     bounds.right = -HUGE_VAL;
00118     bounds.bottom = -HUGE_VAL;
00119     if (lines.empty())
00120         return;
00121 
00122     const Line &front = lines.front();
00123     bounds.left = std::min(bounds.left, front.Origin().x);
00124 
00125     for (LineStrip::const_iterator l = lines.begin(); l != lines.end(); ++l)
00126     {
00127         bounds.top = std::min(bounds.top, l->Origin().y);
00128         bounds.bottom = std::max(bounds.bottom, l->Origin().y);
00129     }
00130 
00131     const Line &back = lines.back();
00132     bounds.top = std::min(bounds.top, back.End().y);
00133     bounds.bottom = std::max(bounds.bottom, back.End().y);
00134     bounds.right = std::max(bounds.right, back.End().x);
00135 }
00136 
00137 void Circle::UpdateBounds()
00138 {
00139     bounds.left = center.x - radius;
00140     bounds.top = center.y - radius;
00141     bounds.right = center.x + radius;
00142     bounds.bottom = center.y + radius;
00143 }
00144 
00145 
00146 Composite::Composite(vec2 centroid)
00147 {
00148     SetCenter(centroid);
00149     UpdateBounds();
00150 }
00151 
00152 Composite::~Composite() // TODO make sure this gets called
00153 {
00154     for (iterator g = geometries.begin(); g != geometries.end(); ++g)
00155         delete &(*g);
00156 }
00157 
00158 void Composite::UpdateBounds()
00159 {
00160     bounds.left = HUGE_VAL;
00161     bounds.top = HUGE_VAL;
00162     bounds.right = -HUGE_VAL;
00163     bounds.bottom = -HUGE_VAL;
00164     if (geometries.empty())
00165         return;
00166 
00167     for (iterator g = geometries.begin(); g != geometries.end(); ++g)
00168     {
00169         (*g)->UpdateBounds();
00170         const aabb &b = (*g)->GetBounds();
00171         if (b.left < bounds.left)
00172             bounds.left = b.left;
00173         if (b.right > bounds.right)
00174             bounds.right = b.right;
00175         if (b.top < bounds.top)
00176             bounds.top = b.top;
00177         if (b.bottom > bounds.bottom)
00178             bounds.bottom = b.bottom;
00179     }
00180 }
00181 
00182 void Composite::push_back(Geometry *geometry)
00183 {
00184     geometries.push_back(geometry);
00185 }
00186 
00187 void Composite::SetCenter(const vec2 &center)
00188 {
00189     vec2 delta = center - this->center;
00190     Geometry::SetCenter(center);
00191     for (const_iterator g = begin(); g != end(); ++g)
00192         (*g)->SetCenter((*g)->Center() + delta);
00193 }
00194 
00195 void Composite::SetAxis(const vec2 &axis)
00196 {
00197     vec2 rotation = this->axis.rotate(axis);
00198 
00199     for (const_iterator g = begin(); g != end(); ++g)
00200     {
00201         vec2 oldAxis = (*g)->Axis();
00202         vec2 oldCenter = (*g)->Center();
00203 
00204         vec2 newAxis = oldAxis.rotate(rotation);
00205         (*g)->SetAxis(newAxis);
00206 
00207         vec2 delta = oldCenter - center;
00208         if (!delta.x && !delta.y)
00209             continue;
00210 
00211         vec2 newCenter = center + delta.rotate(rotation);
00212         (*g)->SetCenter(newCenter);
00213     }
00214     Geometry::SetAxis(axis);
00215 }
00216 
00217 void Quad::SetMass(Body body, float density) const
00218 {
00219     dMass m;
00220     if (extent[1])
00221         dMassSetBox(&m, density, 2 * extent[0], 2 * extent[1], 1);
00222     else
00223         dMassSetBox(&m, density, 2 * extent[0], 1, 1);
00224     dBodySetMass(body, &m);
00225 }
00226 
00227 void Circle::SetMass(Body body, float density) const
00228 {
00229     dMass m;
00230     dMassSetBox(&m, density, radius, radius, 1); // TODO
00231     dBodySetMass(body, &m);
00232 }
00233 
00234 void Composite::SetMass(Body body, float density) const
00235 {
00236     dMass m;
00237     dMassSetBox(&m, density, 100, 100, 1); // TODO
00238     dBodySetMass(body, &m);
00239 }

Generated on Sat Jan 13 17:20:21 2007 for Flatland by doxygen 1.5.1