00001
00002
00003
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 ¢er, 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
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()
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 ¢er)
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);
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);
00238 dBodySetMass(body, &m);
00239 }