Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PerceptionSearch.cc

Go to the documentation of this file.
00001 // INCLUDES
00002 // tekkotsu
00003 #include "DualCoding/AprilTagData.h"
00004 using namespace DualCoding;
00005 
00006 // Tekkodu Library
00007 #include "Kodu/Primitives/PerceptionSearch.h"
00008 
00009 namespace Kodu {
00010 
00011     bool HasAprilTagID::operator()(const ShapeRoot& kShape) const {
00012         return (kShape->getType() == aprilTagDataType
00013             && static_cast<const AprilTagData&>(kShape.getData()).getTagID() == id);
00014     }
00015 
00016     bool IsMatchForTargetObject::operator()(const ShapeRoot& kShape) const {
00017         // check if the objects match each other
00018         return (targetObject->isMatchFor(kShape));
00019     }
00020 
00021 /*
00022     bool IsNotStar::operator()(const ShapeRoot& kWShape) const {
00023         return (!(kWShape->getType() && ShapeRootTypeConst(kWShape, AprilTagData)->getTagID() <= 4));
00024     }
00025 */
00026   bool IsNotWorldShape::operator()(const ShapeRoot& kWShape) const {
00027     switch (kWShape->getType()) {
00028       // if it's a cylinder, it must have a radius within some range
00029     case cylinderDataType: {
00030       const Shape<CylinderData>& kCyl = ShapeRootTypeConst(kWShape, CylinderData);
00031       if ((kCyl->getRadius() < 40.0f) || (kCyl->getRadius() > 75.0f))
00032         return true;
00033       break;
00034     }
00035 
00036       // if it's an april tag, it must be the north star
00037     case aprilTagDataType:
00038       return (!IsStar()(kWShape));
00039 
00040       // the following should not be included in the vector
00041     case localizationParticleDataType:
00042     case polygonDataType:
00043     case agentDataType:
00044       return false;
00045 
00046     default:
00047       return true;
00048     }
00049     return false;
00050   }
00051 
00052     bool IsStar::operator()(const ShapeRoot& kWShape) const {
00053         return (kWShape.isValid() && kWShape->getType() == aprilTagDataType
00054                 && static_cast<const AprilTagData&>(kWShape.getData()).getTagID() >= 24);  // was <= 4
00055     }
00056 
00057     bool IsShapeOfType::operator()(const ShapeRoot& kShape) const {
00058         return (kShape->getType() == targetShapeType);
00059     }
00060 
00061     bool IsNotExcludedShape::operator()(const ShapeRoot& kShape) const {
00062       return ( kShape.getId() != excludedShape.getId()  && (kShape->getName() != "AgentData") &&
00063                ( kShape->getType() == cylinderDataType || kShape->getType() == agentDataType ) );
00064     }
00065 
00066     bool ClearSelfShape::operator()(const ShapeRoot& kShape) const {
00067                         return (kShape->getName() != "AgentData");
00068     }
00069     
00070     bool IsLeftOfAgent::operator()(const ShapeRoot& kShape) const {
00071         // get the bearing from the agent to the shape and return the result
00072         return (bearingFromAgentToObject(kShape) > 0.0f ? true : false);
00073     }
00074 
00075     bool IsRightOfAgent::operator()(const ShapeRoot& kShape) const {
00076         // is right of agent is simply the opposite of what is left of agent would return
00077         return (!(IsLeftOfAgent()(kShape)));
00078     }
00079 
00080     bool IsInFrontAgent::operator()(const ShapeRoot& kShape) const {
00081         // get the bearing from the agent to the shape
00082         AngSignPi dtheta = bearingFromAgentToObject(kShape);
00083         // since the last calculation would produce a value between -pi/2 and +pi/2,
00084         // add pi/2 to the last calculation. the result will give a position angle
00085         // if the object is in front the agent
00086         dtheta += AngSignPi(M_PI / 2.0f);
00087         // check the value of theta
00088         return (dtheta > 0.0f ? true : false);
00089     }
00090 
00091     bool IsBehindAgent::operator()(const ShapeRoot& kShape) const {
00092         // is behind agent is simply the opposite of what is in front agent would return
00093         return (!(IsInFrontAgent()(kShape)));
00094     }
00095 
00096     bool IsCloseByAgent::operator()(const ShapeRoot& kShape) const {
00097         // get the distance between the shape and the agent
00098         return (distanceFromAgentToObject(kShape) <= 700.0f);
00099     }
00100 
00101     bool IsFarAwayFromAgent::operator()(const ShapeRoot& kShape) const {
00102         // get the distance between the shape and the agent
00103         return (distanceFromAgentToObject(kShape) >= 1050.0f);
00104     }
00105 
00106     float bearingFromAgentToPoint(const Point& kPoint) {
00107         float dtheta = 0.0f;
00108         switch (kPoint.getRefFrameType()) {
00109             // take the agent's centroid into consideration if the point is allocentric
00110             case allocentric:
00111             {
00112                 // calculate the bearing between some point "kPoint" and the agent's position
00113                 // bearing2ThisPoint = arctan(dy/dx)
00114                 const Point& kAgentPt = VRmixin::theAgent->getCentroid();
00115                 AngSignPi bearing2ThisPoint = (kPoint - kAgentPt).atanYX();
00116                 // subtract the agent's orientation (heading) from the bearing to get the point's angle
00117                 // relative ot the agent
00118                 dtheta = bearing2ThisPoint - AngSignPi(VRmixin::theAgent->getOrientation());
00119                 break;
00120             }
00121             // simply calculate the arctan of the point...
00122             case egocentric:
00123             {
00124                 dtheta = kPoint.atanYX();
00125                 break;
00126             }
00127             // handles all other Reference Frame Types...
00128             default:
00129                 std::cout << "WARNING: Used unhandled reference frame in bearingFromAgentToPoint(...)\n";
00130                 break;
00131         }
00132         // return the angle between the agent and the target point
00133         return dtheta;
00134     }
00135 
00136     float bearingFromAgentToObject(const ShapeRoot& kShape) {
00137         return bearingFromAgentToPoint(kShape->getCentroid());
00138     }
00139 
00140     float distanceFromAgentToPoint(const Point& kPoint) {
00141         float dx = kPoint.coordX();
00142         float dy = kPoint.coordY();
00143         switch (kPoint.getRefFrameType()) {
00144             // since the point is allocentric, take the agent's centroid into consideration.
00145             case allocentric:
00146             {
00147                 // get the agent's point
00148                 Point agentPoint = VRmixin::theAgent->getCentroid();
00149                 // calculate the differences in the shape's and agent's positions
00150                 dx = dx - agentPoint.coordX();
00151                 dy = dy - agentPoint.coordY();
00152                 break;
00153             }
00154             // since the point is egocentric, there is nothing more to calculate (the agent's centroid
00155             // is { 0, 0 }).
00156             case egocentric:
00157                 break;
00158 
00159             // this handles all other Reference Frame Types...
00160             default:
00161                 std::cout << "WARNING: Used unhandled reference frame in distanceFromAgentToPoint(...)\n";
00162                 return (0.0f);
00163         }
00164         // return the distance
00165         return sqrt((dx * dx) + (dy * dy));
00166     }
00167 
00168     float distanceFromAgentToObject(const ShapeRoot& kShape) {
00169         return distanceFromAgentToPoint(kShape->getCentroid());
00170     }
00171 
00172     float distanceInBetweenAgentAndObject(const ShapeRoot& kShape) {
00173         // approx. measurements based on the iRobot CREATE (measured on/before Dec. 5, 2013)
00174         static float const kRobotInflatedRadius = 205.0f;
00175         float distBtwObjects = 0.0f;
00176         switch(kShape->getType()) {
00177             case cylinderDataType:
00178             {
00179                 // get the radius of the cylinder
00180                 float radius = objectRadius(kShape);
00181                 // calculate the distance between the objects
00182                 float distBetweenCentroids = distanceFromAgentToObject(kShape);
00183                 distBtwObjects = distBetweenCentroids - kRobotInflatedRadius - radius;
00184                 break;
00185             }
00186             case agentDataType:
00187             {
00188                 // calculate the distance between the objects
00189                 float distBetweenCentroids = distanceFromAgentToObject(kShape);
00190                 distBtwObjects = distBetweenCentroids - 2*kRobotInflatedRadius;
00191                 break;
00192             }
00193             default:
00194               std::cout << "WARNING: Used unhandled shape type " << kShape << " in "
00195                           << "distanceInBetweenAgentAndObject(...)\n";
00196                 return (0.0f);
00197         }
00198         return (distBtwObjects > 0.0f ? distBtwObjects : 0.0f);
00199     }
00200 
00201     float objectRadius(const ShapeRoot& kShape) {
00202         static float const kErrValue = -1.0f;
00203         float radius = 0.0f;
00204         switch(kShape->getType()) {
00205             case cylinderDataType:
00206                 radius = ShapeRootTypeConst(kShape, CylinderData)->getRadius();
00207                 break;
00208 
00209             case agentDataType:
00210                 radius = 205.0f;  // for iRobot Create
00211                 break;
00212 
00213             default:
00214                 std::cout << "WARNING: Used unhandled shape type in objectRadius(...)\n";
00215                 return kErrValue;
00216         }
00217         return radius;
00218     }
00219 
00220     ShapeRoot getClosestObject(const std::vector<ShapeRoot>& kObjects) {
00221         const std::size_t kSize = kObjects.size();
00222         // if the vector's size is zero, return an invalid shape
00223         if (kSize == 0) {
00224             return ShapeRoot();
00225         }
00226 
00227         // else if the vector's size is one, return the first element (the only shape in the vector)
00228         else if (kSize == 1) {
00229             return kObjects[0];
00230         }
00231 
00232         // else iterate over the vector and find the closest shape
00233         else {
00234             ShapeRoot nearestObject = kObjects[0];
00235             float nearestObjectDist = distanceFromAgentToObject(nearestObject);
00236             
00237             // iterate over the remainder of the objects
00238             for (std::size_t index = 1; index < kSize; index++) {
00239                 float currentObjectDist = distanceFromAgentToObject(kObjects[index]);
00240                 if (currentObjectDist < nearestObjectDist) {
00241                     nearestObjectDist = currentObjectDist;
00242                     nearestObject = kObjects[index];
00243                 }
00244             }
00245             return nearestObject;
00246         }
00247     }
00248 
00249     ShapeRoot getClosestObjectToPoint(const std::vector<ShapeRoot>& kShapes,
00250         const Point& kComparisonPoint)
00251     {
00252         const std::size_t kSize = kShapes.size();
00253         // if the vector is empty, return an invalid shape
00254         if (kSize == 0) {
00255             return ShapeRoot();
00256         }
00257         // else iterate over the vector and find the closest shape to the comparison point
00258         else {
00259             ShapeRoot closestMatch = kShapes[0];
00260             float minCenDiff = closestMatch->getCentroid().xyDistanceFrom(kComparisonPoint);
00261 
00262             for (std::size_t i = 1; i < kSize; i++) {
00263                 float cenDiff = kShapes[i]->getCentroid().xyDistanceFrom(kComparisonPoint);
00264                 if (cenDiff < minCenDiff) {
00265                     closestMatch = kShapes[i];
00266                     minCenDiff = cenDiff;
00267                 }
00268             }
00269             return closestMatch;
00270         }
00271     }
00272 
00273     std::vector<ShapeRoot> getObjectsLocated(const std::vector<ShapeRoot>& kObjects, SearchLocation_t location) {
00274         // copy the objects to result
00275         std::vector<ShapeRoot> result = kObjects;
00276         std::cout << "Checking map for objects:";
00277         
00278         // test if the search location should be limited to the front or back
00279         if (location & SL_IN_FRONT) {
00280             std::cout << " [in front]";
00281             result = subset(result, IsInFrontAgent());
00282         } else if (location & SL_BEHIND) {
00283             std::cout << " [behind]";
00284             result = subset(result, IsBehindAgent());
00285         }
00286             
00287         // test if the search location should be limited to the left or right sides
00288         if (location & SL_TO_LEFT) {
00289             std::cout << " [to the left]";
00290             result = subset(result, IsLeftOfAgent());
00291         } else if (location & SL_TO_RIGHT) {
00292             std::cout << " [to the right]";
00293             result = subset(result, IsRightOfAgent());
00294         }
00295 
00296         // test if the search location is limited to "close by" or "far away (from)" the agent
00297         if (location & SL_CLOSE_BY) {
00298             std::cout << " [close by]";
00299             result = subset(result, IsCloseByAgent());
00300         }
00301         else if (location & SL_FAR_AWAY) {
00302             std::cout << " [far away]";
00303             result = subset(result, IsFarAwayFromAgent());
00304         }
00305         std::cout << std::endl;
00306         return result;
00307     }
00308 
00309   std::vector<ShapeRoot> getMatchingObjects(const std::vector<ShapeRoot>& kObjects,
00310                                             const std::string& kColor, const std::string& kType) {
00311     std::string rcolor = ""; //TODO when setable colors are introduced this needs to be removed
00312     if (kType == "apple") {
00313       rcolor = "red";
00314     } else if (kType == "rock") {
00315       rcolor = "blue";
00316     } else if (kType == "tree") {
00317       rcolor = "green";
00318     }
00319     if (rcolor != "") //Condition for matching apples, trees, and rocks
00320       return subset(subset(kObjects, IsType(cylinderDataType)), IsColor(rcolor));
00321     else if(kType == "robot")
00322       return subset(kObjects, IsType(agentDataType)); //TODO setable colors not implemented
00323     else
00324       return subset(kObjects, IsName(kType)); // handle "turtle", "cycle", etc.
00325     
00326   }
00327 
00328     ShapeRoot getClosestObjectMatching(const std::string& color, const std::string& type, SearchLocation_t location,
00329                                        const ShapeRoot& kExcludedShape) {
00330         // The closest object that matches the specified criteria
00331         // (if not assigned a value it is invalid)
00332         ShapeRoot closestMatch;
00333 
00334         // Tekkotsu function. Returns all the objects (formerly only cylinders)
00335         NEW_SHAPEROOTVEC(matchingObjects, subset(VRmixin::worldShS, ClearSelfShape()));
00336         if ( ! matchingObjects.empty() && kExcludedShape.isValid() )
00337             matchingObjects = subset(matchingObjects, IsNotExcludedShape(kExcludedShape));
00338         
00339         // get objects with a particular color
00340         if ( ! matchingObjects.empty() )
00341           matchingObjects = getMatchingObjects(matchingObjects, color, type);
00342 
00343         // get objects that are located in a particular region (left, right, front, behind) and
00344         // distance (close by, far away) from the agent
00345         if ( ! matchingObjects.empty() && (location != SL_UNRESTRICTED) )
00346           matchingObjects = getObjectsLocated(matchingObjects, location);
00347 
00348         // get the closest object to the agent
00349         if ( ! matchingObjects.empty() )
00350           closestMatch = getClosestObject(matchingObjects);
00351 
00352         // return the object that matches the search criteria (may be valid or invalid)
00353         return closestMatch;
00354     }
00355 }

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:45 2016 by Doxygen 1.6.3