worldsim/src/sensorcontrollers.cpp

00001 /********************************************************************************
00002  *  FARSA Experiments Library                                                   *
00003  *  Copyright (C) 2007-2012                                                     *
00004  *  Gianluca Massera <emmegian@yahoo.it>                                        *
00005  *  Stefano Nolfi <stefano.nolfi@istc.cnr.it>                                   *
00006  *  Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it>                         *
00007  *  Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it>                           *
00008  *                                                                              *
00009  *  This program is free software; you can redistribute it and/or modify        *
00010  *  it under the terms of the GNU General Public License as published by        *
00011  *  the Free Software Foundation; either version 2 of the License, or           *
00012  *  (at your option) any later version.                                         *
00013  *                                                                              *
00014  *  This program is distributed in the hope that it will be useful,             *
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00017  *  GNU General Public License for more details.                                *
00018  *                                                                              *
00019  *  You should have received a copy of the GNU General Public License           *
00020  *  along with this program; if not, write to the Free Software                 *
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00022  ********************************************************************************/
00023 
00024 #include "sensorcontrollers.h"
00025 #include "logger.h"
00026 #include "mathutils.h"
00027 #include "phyobject.h"
00028 #include "graphicalwobject.h"
00029 
00030 namespace farsa {
00031 
00032 SensorController::SensorController(World* world) :
00033     Ownable(),
00034     m_world(world),
00035     m_enabled(true)
00036 {
00037 }
00038 
00039 SensorController::~SensorController()
00040 {
00041     // Nothing to do here
00042 }
00043 
00044 IRSensorController::IRSensorController(World* world, unsigned int numSensors) :
00045     SensorController(world),
00046     m_activations(numSensors)
00047 {
00048 }
00049 
00050 IRSensorController::~IRSensorController()
00051 {
00052     // Nothing to do here
00053 }
00054 
00055 namespace __SingleIR_internal {
00056     #ifndef GLMultMatrix
00057     #define GLMultMatrix glMultMatrixf
00058     // for double glMultMatrixd
00059     #endif
00060 
00064     const float sensorCubeSide = 0.005f;
00065 
00069     class SingleIRGraphic : public GraphicalWObject
00070     {
00071     public:
00099         SingleIRGraphic(WObject *object, const wMatrix& offset, const QVector<wVector>& startingRayPoints, const QVector<wVector>& endingRayPoints, bool drawRay, bool drawRealRay, QString name = "unamed") :
00100             GraphicalWObject(object->world(), name),
00101             m_object(object),
00102             m_offset(offset),
00103             m_startingRayPoints(startingRayPoints),
00104             m_endingRayPoints(endingRayPoints),
00105             m_drawRay(drawRay),
00106             m_drawRealRay(drawRealRay)
00107         {
00108             // Attaching to handPiece (which also becomes our owner)
00109             attachToObject(m_object, true);
00110 
00111             // We also use our own color and texture
00112             setUseColorTextureOfOwner(false);
00113             setTexture("");
00114             setColor(Qt::black);
00115         }
00116 
00120         ~SingleIRGraphic()
00121         {
00122         }
00123 
00124     protected:
00133         virtual void render(RenderWObject* renderer, QGLContext* gw)
00134         {
00135             // Pushing the transformation matrices separately because the box needs both of them
00136             // while rays doesn't need the offset (they are already in the solid frame of reference)
00137             // Bringing the coordinate system on the sensor
00138             wMatrix mtr = tm * m_offset;
00139 
00140             glPushMatrix();
00141             GLMultMatrix(&tm[0][0]);
00142 
00143             glPushMatrix();
00144             GLMultMatrix(&m_offset[0][0]);
00145 
00146             renderer->container()->setupColorTexture(gw, renderer);
00147 
00148             // First drawing the cube representing the sensor. The cube will just be drawn as
00149             // six quads for the sake of simplicity. For each face, we specify the quad normal
00150             // (for lighting), then specify the quad's 4 vertices. The top part of the front
00151             // face is drawn in green to understand if the sensor is mounted upside-down
00152             glBegin(GL_QUADS);
00153             const float hside = sensorCubeSide / 2.0;
00154 
00155             // front (top part)
00156             glColor3f(0.0, 1.0, 0.0);
00157             glNormal3f(0.0, 0.0, 1.0);
00158             glVertex3f(-hside,    0.0,  hside);
00159             glVertex3f( hside,    0.0,  hside);
00160             glVertex3f( hside,  hside,  hside);
00161             glVertex3f(-hside,  hside,  hside);
00162 
00163             // front (bottom part)
00164             glColor3f(0.0, 0.0, 0.0);
00165             glNormal3f(0.0, 0.0, 1.0);
00166             glVertex3f(-hside, -hside,  hside);
00167             glVertex3f( hside, -hside,  hside);
00168             glVertex3f( hside,    0.0,  hside);
00169             glVertex3f(-hside,    0.0,  hside);
00170 
00171             // back
00172             glNormal3f(0.0, 0.0, -1.0);
00173             glVertex3f( hside, -hside, -hside);
00174             glVertex3f(-hside, -hside, -hside);
00175             glVertex3f(-hside,  hside, -hside);
00176             glVertex3f( hside,  hside, -hside);
00177 
00178             // top
00179             glNormal3f(0.0, 1.0, 0.0);
00180             glVertex3f(-hside,  hside,  hside);
00181             glVertex3f( hside,  hside,  hside);
00182             glVertex3f( hside,  hside, -hside);
00183             glVertex3f(-hside,  hside, -hside);
00184 
00185             // bottom
00186             glNormal3f(0.0, -1.0, 0.0);
00187             glVertex3f(-hside, -hside, -hside);
00188             glVertex3f( hside, -hside, -hside);
00189             glVertex3f( hside, -hside,  hside);
00190             glVertex3f(-hside, -hside,  hside);
00191 
00192             // right
00193             glNormal3f(-1.0, 0.0, 0.0);
00194             glVertex3f(-hside, -hside, -hside);
00195             glVertex3f(-hside, -hside,  hside);
00196             glVertex3f(-hside,  hside,  hside);
00197             glVertex3f(-hside,  hside, -hside);
00198 
00199             // left
00200             glNormal3f(1.0, 0.0, 0.0);
00201             glVertex3f( hside, -hside,  hside);
00202             glVertex3f( hside, -hside, -hside);
00203             glVertex3f( hside,  hside, -hside);
00204             glVertex3f( hside,  hside,  hside);
00205 
00206             glEnd();
00207 
00208             // Popping only one matrix because ray need the other one
00209             glPopMatrix();
00210 
00211             // Disabling lighting here (we want pure red lines no matter from where we look ata them)
00212             glDisable(GL_LIGHTING);
00213 
00214             // Now drawing the ray if we have to
00215             if (m_drawRay) {
00216                 glLineWidth(2.5);
00217                 glColor3f(1.0, 0.0, 0.0);
00218 
00219                 glBegin(GL_LINES);
00220                 for (int i = 0; i < m_startingRayPoints.size(); i++) {
00221                     const wVector& s = m_startingRayPoints[i];
00222                     const wVector& e = m_endingRayPoints[i];
00223                     if (m_drawRealRay) {
00224                         glVertex3f(s.x, s.y, s.z);
00225                         glVertex3f(e.x, e.y, e.z);
00226                     } else {
00227                         const wVector d = (e - s).normalize().scale(sensorCubeSide * 5.0);
00228                         glVertex3f(m_offset.w_pos.x, m_offset.w_pos.y, m_offset.w_pos.z);
00229                         glVertex3f(m_offset.w_pos.x + d.x, m_offset.w_pos.y + d.y, m_offset.w_pos.z + d.z);
00230                     }
00231                 }
00232                 glEnd();
00233             }
00234 
00235             // Re-enable lighting
00236             glEnable(GL_LIGHTING);
00237 
00238             glPopMatrix();
00239         }
00240 
00245         WObject* const m_object;
00246 
00251         const wMatrix m_offset;
00252 
00259         const QVector<wVector> m_startingRayPoints;
00260 
00267         const QVector<wVector> m_endingRayPoints;
00268 
00273         const bool m_drawRay;
00274 
00282         const bool m_drawRealRay;
00283     };
00284 }
00285 
00286 using namespace __SingleIR_internal;
00287 
00288 SingleIR::SingleIR() :
00289     m_object(NULL),
00290     m_transformation(wMatrix::identity()),
00291     m_minDist(0.0),
00292     m_maxDist(0.0),
00293     m_aperture(0.0),
00294     m_numRays(0),
00295     m_drawSensor(false),
00296     m_drawRay(false),
00297     m_drawRealRay(false),
00298     m_startingRayPoints(),
00299     m_endingRayPoints(),
00300     m_rayCastHit(),
00301     m_sensorGraphics(NULL)
00302 {
00303     m_rayCastHit.object = NULL;
00304     m_rayCastHit.distance = 1.0;
00305 }
00306 
00307 SingleIR::SingleIR(WObject* obj, wMatrix mtr, double minDist, double maxDist, double aperture, unsigned int numRays) :
00308     m_object(obj),
00309     m_transformation(mtr),
00310     m_minDist(minDist),
00311     m_maxDist(maxDist),
00312     m_aperture(aperture),
00313     m_numRays(numRays),
00314     m_drawSensor(false),
00315     m_drawRay(false),
00316     m_drawRealRay(false),
00317     m_startingRayPoints(),
00318     m_endingRayPoints(),
00319     m_rayCastHit(),
00320     m_sensorGraphics(NULL)
00321 {
00322     m_rayCastHit.object = NULL;
00323     m_rayCastHit.distance = 1.0;
00324 
00325     if (m_numRays != 0) {
00326         m_startingRayPoints.resize(m_numRays);
00327         m_endingRayPoints.resize(m_numRays);
00328     }
00329 
00330     // computing the starting and ending point of rays and updating the graphical representation
00331     computeRayPoints();
00332     updateGraphicalRepresentation();
00333 }
00334 
00335 SingleIR::SingleIR(const SingleIR& other) :
00336     m_object(other.m_object),
00337     m_transformation(other.m_transformation),
00338     m_minDist(other.m_minDist),
00339     m_maxDist(other.m_maxDist),
00340     m_aperture(other.m_aperture),
00341     m_numRays(other.m_numRays),
00342     m_drawSensor(other.m_drawSensor),
00343     m_drawRay(other.m_drawRay),
00344     m_drawRealRay(other.m_drawRealRay),
00345     m_startingRayPoints(other.m_startingRayPoints),
00346     m_endingRayPoints(other.m_endingRayPoints),
00347     m_rayCastHit(other.m_rayCastHit),
00348     m_sensorGraphics(NULL)
00349 {
00350     updateGraphicalRepresentation();
00351 }
00352 
00353 SingleIR& SingleIR::operator=(const SingleIR& other)
00354 {
00355     if (&other == this) {
00356         return *this;
00357     }
00358 
00359     // Copying data members
00360     m_object = other.m_object;
00361     m_transformation = other.m_transformation;
00362     m_minDist = other.m_minDist;
00363     m_maxDist = other.m_maxDist;
00364     m_aperture = other.m_aperture;
00365     m_numRays = other.m_numRays;
00366     m_drawSensor = other.m_drawSensor;
00367     m_drawRay = other.m_drawRay;
00368     m_drawRealRay = other.m_drawRealRay;
00369     m_startingRayPoints = other.m_startingRayPoints;
00370     m_endingRayPoints = other.m_endingRayPoints;
00371     m_rayCastHit = other.m_rayCastHit;
00372 
00373     updateGraphicalRepresentation();
00374 
00375     return *this;
00376 }
00377 
00378 SingleIR::~SingleIR()
00379 {
00380     // Nothing to do here
00381 }
00382 
00383 void SingleIR::update()
00384 {
00385     // Checking if the sensor is valid
00386     if (!isValid()) {
00387         return;
00388     }
00389 
00390     // Resetting the current RayCastHit object
00391     m_rayCastHit.object = NULL;
00392     m_rayCastHit.distance = 1.0;
00393 
00394     // If we are attached to a phyobject, we ignore it in collisions
00395     QSet<PhyObject*> ignoredObjs;
00396     PhyObject* phyObj = dynamic_cast<PhyObject*>(m_object);
00397     if (phyObj != NULL) {
00398         ignoredObjs.insert(phyObj);
00399     }
00400 
00401     // The minimum distance (distances range from 0.0 to 1.0)
00402     double minDist = 2.0;
00403     for (unsigned int i = 0; i < m_numRays; i++) {
00404         // Computing the start and end point of the ray in the global frame of reference
00405         const wVector start = m_object->matrix().transformVector(m_startingRayPoints[i]);
00406         const wVector end = m_object->matrix().transformVector(m_endingRayPoints[i]);
00407 
00408         // Casting the ray
00409         const rayCastHitVector v = m_object->world()->worldRayCast(start, end, true, ignoredObjs);
00410 
00411         // Taking the lowest distance: this sensor only reposrts the distance of the closest
00412         // object
00413         if ((v.size() != 0) && (v[0].distance < minDist)) {
00414             minDist = v[0].distance;
00415             m_rayCastHit = v[0];
00416         }
00417     }
00418 }
00419 
00420 void SingleIR::set(WObject* obj, wMatrix mtr, double minDist, double maxDist, double aperture, unsigned int numRays)
00421 {
00422     // First of all saving the parameters
00423     m_object = obj;
00424     m_transformation = mtr;
00425     m_minDist = minDist;
00426     m_maxDist = maxDist;
00427     m_aperture = aperture;
00428     m_numRays = numRays;
00429     if (m_numRays != 0) {
00430         m_startingRayPoints.resize(m_numRays);
00431         m_endingRayPoints.resize(m_numRays);
00432     } else {
00433         m_startingRayPoints.clear();
00434         m_endingRayPoints.clear();
00435     }
00436     m_rayCastHit.object = NULL;
00437     m_rayCastHit.distance = 1.0;
00438 
00439     computeRayPoints();
00440     updateGraphicalRepresentation();
00441 }
00442 
00443 void SingleIR::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00444 {
00445     m_drawSensor = drawSensor;
00446     m_drawRay = drawRay;
00447     m_drawRealRay = drawRealRay;
00448 
00449     updateGraphicalRepresentation();
00450 }
00451 
00452 void SingleIR::computeRayPoints()
00453 {
00454     // Checking the sensor is valid
00455     if (!isValid()) {
00456         return;
00457     }
00458 
00459     // First of all we need to compute the starting angle of the rays and the angular distance
00460     // between them. If there is only one ray it is at angle 0.0 (i.e. along the local Z axis).
00461     // The angles computed here are in radiants.
00462     const double startAngle = (m_numRays == 1) ? 0.0 : -(deg2rad(m_aperture) / 2.0);
00463     const double angularIncrement = (m_numRays == 1) ? 0.0 : (deg2rad(m_aperture) / double(m_numRays - 1));
00464 
00465     // Now computing the angles in the object fame of reference
00466     for (unsigned int i = 0; i < m_numRays; i++) {
00467         const double curAngle = startAngle + i * angularIncrement;
00468 
00469         // To get the ray in the sensor frame of reference we have to rotate the Z axis
00470         // around the Y axis. Then we compute the starting and ending point
00471         const wVector localRay = wVector::Z().rotateAround(wVector::Y(), curAngle);
00472         const wVector localStart = localRay.scale(m_minDist);
00473         const wVector localEnd = localRay.scale(m_maxDist);
00474 
00475         // Finally we can compute the start and end in the object frame of reference
00476         m_startingRayPoints[i] = m_transformation.transformVector(localStart);
00477         m_endingRayPoints[i] = m_transformation.transformVector(localEnd);
00478     }
00479 }
00480 
00481 void SingleIR::updateGraphicalRepresentation()
00482 {
00483     delete m_sensorGraphics;
00484     m_sensorGraphics = NULL;
00485 
00486     // Checking the sensor is valid
00487     if (m_drawSensor && isValid()) {
00488         // creating the graphical representation of the sensor
00489         m_sensorGraphics = new SingleIRGraphic(m_object, m_transformation, m_startingRayPoints, m_endingRayPoints, m_drawRay, m_drawRealRay);
00490     }
00491 }
00492 
00493 SimulatedIRProximitySensorController::SimulatedIRProximitySensorController(World* world, const QVector<SingleIR>& sensors) :
00494     IRSensorController(world, sensors.size()),
00495     m_sensors(sensors)
00496 {
00497     // Nothing to do here
00498 }
00499 
00500 SimulatedIRProximitySensorController::~SimulatedIRProximitySensorController()
00501 {
00502     // Nothing to do here
00503 }
00504 
00505 void SimulatedIRProximitySensorController::update()
00506 {
00507     for (int i = 0; i < m_sensors.size(); i++) {
00508         m_sensors[i].update();
00509         // If there was no hit, distance is 1.0 and activation 0.0
00510         m_activations[i] = 1.0 - m_sensors[i].getRayCastHit().distance;
00511     }
00512 }
00513 
00514 void SimulatedIRProximitySensorController::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00515 {
00516     for (int i = 0; i < m_sensors.size(); i++) {
00517         m_sensors[i].setGraphicalProperties(drawSensor, drawRay, drawRealRay);
00518     }
00519 }
00520 
00521 SimulatedIRGroundSensorController::SimulatedIRGroundSensorController(World* world, const QVector<SingleIR>& sensors) :
00522     IRSensorController(world, sensors.size()),
00523     m_sensors(sensors)
00524 {
00525 }
00526 
00527 SimulatedIRGroundSensorController::~SimulatedIRGroundSensorController()
00528 {
00529     // Nothing to do here
00530 }
00531 
00532 void SimulatedIRGroundSensorController::update()
00533 {
00534     for (int i = 0; i < m_sensors.size(); i++) {
00535         m_sensors[i].update();
00536 
00537         // Now taking the color of the nearest solid, converting to HSL and taking
00538         // normalized lightness as activation
00539         if (m_sensors[i].getRayCastHit().object != NULL) {
00540             m_activations[i] = m_sensors[i].getRayCastHit().object->color().lightnessF();
00541         } else {
00542             m_activations[i] = 0.0;
00543         }
00544     }
00545 }
00546 
00547 void SimulatedIRGroundSensorController::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00548 {
00549     for (int i = 0; i < m_sensors.size(); i++) {
00550         m_sensors[i].setGraphicalProperties(drawSensor, drawRay, drawRealRay);
00551     }
00552 }
00553 
00554 } // end namespace farsa