arena.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it> *
6  * Gianluca Massera <emmegian@yahoo.it> *
7  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the Free Software *
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
22  ********************************************************************************/
23 
24 #include "arena.h"
25 #include "configurationhelper.h"
26 #include "phybox.h"
27 #include "logger.h"
28 
29 namespace farsa {
30 
31 // This anonymous namespace contains some constants used throughout the code
32 #ifdef __GNUC__
33  #warning QUESTE COSTANTI DEVONO PROBABILMENTE DIVENTARE DEI PARAMETRI
34 #endif
35 namespace {
41  const real defaultHeight = 0.3f;
42 
48  const real planeThickness = 0.1;
49 
55  const real smallCylinderRadius = 0.03;
56 
62  const real bigCylinderRadius = 0.06;
63 
69  const real targetAreasHeight = 0.001;
70 
76  const real targetAreasProtrusion = 0.0005;
77 }
78 
79 Arena::Arena(ConfigurationParameters& params, QString prefix) :
80  ParameterSettableInConstructor(params, prefix),
82  m_z(ConfigurationHelper::getDouble(params, prefix + "z", 0.0)),
83  m_plane(createPlane(params, prefix, m_z)),
84  m_objects2DList(QVector<PhyObject2DWrapper*>() << m_plane),
85  m_world(NULL)
86 {
87  // The list of resources we observe here
88  usableResources(QStringList() << "world");
89 }
90 
92 {
93  // Removing all wrappers
94  for (int i = 0; i < m_objects2DList.size(); i++) {
95  delete m_objects2DList[i];
96  }
97 }
98 
100 {
101  Logger::error("NOT IMPLEMENTED (Arena::save)");
102  abort();
103 }
104 
105 void Arena::describe(QString type)
106 {
107  // The parent class is ParameterSettableInConstructor, no need to call
108  // its describe function (which does nothing)
109 
110  Descriptor d = addTypeDescription(type, "The class modelling an arena in which robots can live");
111  d.describeReal("z").def(0.0).help("The z coordinate of the plane in the world frame of reference", "This is the z coordinate of the upper part of the plane in the world frame of reference");
112  d.describeReal("planeWidth").def(2.5).limits(0.01, +Infinity).help("The width of the arena");
113  d.describeReal("planeHeight").def(0.0).limits(0.01, +Infinity).help("The height of the arena");
114 }
115 
116 void Arena::addRobots(QStringList robots)
117 {
118 #ifdef __GNUC__
119  #warning IMPLEMENTARE QUESTA!!!
120 #endif
121  // Qui ricordarsi di aggiungere i robots alle risorse che si osservano
122 }
123 
125 {
126  return m_plane;
127 }
128 
129 Box2DWrapper* Arena::createWall(QColor color, wVector start, wVector end, real thickness, real height)
130 {
131  ResourcesLocker locker(this);
132 
133  // Changing parameters
134  start.z = m_z;
135  end.z = m_z;
136 
137  // Creating the box, then we have to change its position and make it static
138  Box2DWrapper* b = createBox(color, (end - start).norm(), thickness, height, Box2DWrapper::Wall);
139 
140  // Moving the wall and setting the texture. We have to compute the rotation around the Z axis of the
141  // wall and the position of its center to build its transformation matrix
142  const real angle = atan2(end.y - start.y, end.x - start.x);
143  const wVector centerPosition = start + (end - start).scale(0.5);
144  wMatrix mtr = wMatrix::roll(angle);
145  mtr.w_pos = centerPosition + wVector(0.0, 0.0, b->phyObject()->matrix().w_pos.z);
146  b->phyObject()->setMatrix(mtr);
147  b->setTexture("tile2");
148 
149  return b;
150 }
151 
153 {
154  return createCylinder(color, smallCylinderRadius, height, Cylinder2DWrapper::SmallCylinder);
155 }
156 
157 Cylinder2DWrapper* Arena::createBigCylinder(QColor color, real height)
158 {
159  return createCylinder(color, bigCylinderRadius, height, Cylinder2DWrapper::BigCylinder);
160 }
161 
163 {
164  ResourcesLocker locker(this);
165 
166  // Creating the cylinder, then we only have to change its z position and set the material to nonCollidable
167  Cylinder2DWrapper* c = createCylinder(color, radius, targetAreasHeight, Cylinder2DWrapper::CircularTargetArea);
168 
169  wMatrix mtr = c->phyObject()->matrix();
170  mtr.w_pos = wVector(0.0, 0.0, m_z - (targetAreasHeight / 2.0) + targetAreasProtrusion);
171  c->phyObject()->setMatrix(mtr);
172  c->phyObject()->setMaterial("nonCollidable");
173 
174  return c;
175 }
176 
177 Box2DWrapper* Arena::createRectangularTargetArea(real width, real depth, QColor color)
178 {
179  ResourcesLocker locker(this);
180 
181  // Creating the box, then we only have to change its z position and set the material to nonCollidable
182  Box2DWrapper* b = createBox(color, width, depth, targetAreasHeight, Box2DWrapper::RectangularTargetArea);
183 
184  wMatrix mtr = b->phyObject()->matrix();
185  mtr.w_pos = wVector(0.0, 0.0, m_z - (targetAreasHeight / 2.0) + targetAreasProtrusion);
186  b->phyObject()->setMatrix(mtr);
187  b->phyObject()->setMaterial("nonCollidable");
188 
189  return b;
190 }
191 
192 Cylinder2DWrapper* Arena::createCylinder(QColor color, real radius, real height, Cylinder2DWrapper::Type type)
193 {
194  ResourcesLocker locker(this);
195 
196  // Changing parameters
197  if (height < 0.0) {
198  height = defaultHeight;
199  }
200 
201  PhyCylinder* cylinder = new PhyCylinder(radius, height, m_world, "cylinder");
202  wMatrix mtr = wMatrix::yaw(PI_GRECO / 2.0);
203  mtr.w_pos = wVector(0.0, 0.0, m_z + (height / 2.0));
204  cylinder->setMatrix(mtr);
205  cylinder->setUseColorTextureOfOwner(false);
206  cylinder->setColor(color);
207  cylinder->setTexture("");
208 
209  // Creating the wrapper
210  Cylinder2DWrapper* wrapper = new Cylinder2DWrapper(cylinder, type);
211 
212  // Appending the wrapper to the list
213  m_objects2DList.append(wrapper);
214 
215  return wrapper;
216 }
217 
218 Box2DWrapper* Arena::createBox(QColor color, real width, real depth, real height, Box2DWrapper::Type type)
219 {
220  ResourcesLocker locker(this);
221 
222  // Changing parameters
223  if (height < 0.0) {
224  height = defaultHeight;
225  }
226 
227  PhyBox* box = new PhyBox(width, depth, height, m_world, "box");
228 
229  // Moving the box so that it lies on the plane
230  wMatrix mtr = wMatrix::identity();
231  mtr.w_pos = wVector(0.0, 0.0, m_z + (height / 2.0));
232  box->setMatrix(mtr);
233  box->setUseColorTextureOfOwner(false);
234  box->setColor(color);
235  box->setTexture("");
236 
237  // Creating the wrapper
238  Box2DWrapper* wrapper = new Box2DWrapper(box, type);
239 
240  // Appending the wrapper to the list
241  m_objects2DList.append(wrapper);
242 
243  return wrapper;
244 }
245 
246 void Arena::resourceChanged(QString resourceName, ResourceChangeType changeType)
247 {
248  if (resourceName == "world") {
249  switch (changeType) {
250  case Created:
251  case Modified:
252  m_world = getResource<World>();
253  break;
254  case Deleted:
255  m_world = NULL;
256  break;
257  }
258  } else {
259  Logger::info("Unknown resource " + resourceName + " for Arena");
260  }
261 }
262 
263 Box2DWrapper* Arena::createPlane(ConfigurationParameters& params, QString prefix, real z)
264 {
265  // First of all getting the dimensions of the plane
266  const real planeWidth = ConfigurationHelper::getDouble(params, prefix + "planeWidth", 2.5);
267  const real planeHeight = ConfigurationHelper::getDouble(params, prefix + "planeHeight", 2.5);
268 
269  // Also getting the world from the ResourcesUser associated with param
270  SimpleResourcesUser* r = params.getResourcesUserForResource("world");
271  if (r == NULL) {
272  ConfigurationHelper::throwUserMissingResourceError("world", "We need a world to create the arena!");
273  }
274  World* world = r->getResource<World>("world");
275 
276  PhyBox* plane = new PhyBox(planeWidth, planeHeight, planeThickness, world, "plane");
277  plane->setPosition(wVector(0.0, 0.0, z - (planeThickness / 2.0)));
278  plane->setStatic(true);
279  plane->setColor(Qt::white);
280  plane->setTexture("tile2");
281 
282  // Also resizing world to comfortably fit the arena
283  world->setSize(wVector(-planeWidth, -planeHeight, -planeThickness), wVector(planeWidth, planeHeight, +6.0));
284 
285  // Creating the wrapper and returning it
286  return new Box2DWrapper(plane, Box2DWrapper::Plane);
287 }
288 
289 } // end namespace farsa