NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
tgCompoundRigidSensorInfo.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2012, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
7  * under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * http://www.apache.org/licenses/LICENSE-2.0.
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied. See the License for the specific language
16  * governing permissions and limitations under the License.
17 */
18 
26 // This module
28 // Other includes from NTRTsim
29 #include "tgCompoundRigidSensor.h"
30 #include "core/tgModel.h"
31 #include "core/tgBaseRigid.h" // for checking descendants via casting.
32 #include "core/tgSenseable.h"
33 #include "core/tgCast.h"
34 // Other includes from the C++ standard library
35 #include <stdexcept>
36 #include <sstream> // for ease of converting tags to strings.
37 #include <iostream> // for writing output to the terminal
38 #include <algorithm> // // for std::find, used with blacklist.
39 // Includes from boost
40 #include <boost/regex.hpp>
41 
49 static const boost::regex compound_regex("compound_\\w{6}");
50 
55 {
56 }
57 
62 {
63 }
64 
69 std::map<std::string, int> tgCompoundRigidSensorInfo::getCompoundTags(tgModel* pModel)
70 {
71  // Check for null pointer.
72  if ( pModel == NULL) {
73  throw std::invalid_argument("pModel was NULL inside tgCompoundRigidSensorInfo.");
74  }
75  // Then, get the descendants.
76  // Note that we're using tgModel's getDescendants function here.
77  std::vector<tgModel*> descendants = pModel->getDescendants();
78  // This map will store the number of valid rigids with a given compound tag.
79  std::map<std::string, int> compounds;
80 
81  // Iterate through the descendants, search for tags,
82  // and count them up.
83  for (size_t i=0; i < descendants.size(); i++){
84  // Check if this descendant has a compound tag...
85  // (a) get the tags in string form
86  std::stringstream tagstream;
87  tagstream << descendants[i]->getTags();
88  std::string tags = tagstream.str();
89  // (b) use a regular expression to pick out any compound tags
90  boost::smatch matches;
91  bool anymatches = boost::regex_search(tags, matches, compound_regex);
92  // If there are zero matches, do nothing: this descendant is not compound.
93  // Note that matches is only initialized if anymatches is true.
94  // In other words, we CANNOT do a check of matches.size() here instead,
95  // since if matches.size() == 0, then matches will not have been initialized.
96  if( anymatches ) {
97  // Note that there should be AT MOST one match.
98  // No rigid body should ever be part of more than one compound: if
99  // it was part of two compounds, those compounds would be the same!!
100  // TO-DO: write some verifying code (maybe in tgRigidAutoCompounder)
101  // to enforce this.
102  if (matches.size() >= 2 ){
103  throw std::runtime_error("A tgModel has more than one compound tag in its tag list, inside tgCompoundRigidSensorInfo. This is impossible, and something is very wrong.");
104  }
105  // Confirm that the specific descendant is actually a rigid body.
106  // It's possible that some not-rigid-bodies could have erroneous tags...
107  tgBaseRigid* pBaseRigid =
108  tgCast::cast<tgSenseable, tgBaseRigid>(descendants[i]);
109  if (pBaseRigid == 0 ) {
110  throw std::runtime_error("A tgModel that is NOT a rigid body has a compound tag attached to it. Only rigid bodies should have compound tags.");
111  }
112  // Finally, if everything is good, add to the index of counts for this tag.
113  compounds[matches.str(0)] += 1;
114  }
115  }
116 
117  // Return the completed list. If descendants was size zero,
118  // then this map will not have any entries.
119  return compounds;
120 }
121 
122 // Quick check: is this tag in the blacklist?
123 bool tgCompoundRigidSensorInfo::isBlacklisted(std::string tag)
124 {
125  // Use the std::find algorithm, with an iterator.
126  std::vector<std::string>::iterator it;
127  it = std::find( blacklist.begin(), blacklist.end(), tag);
128  if( it == blacklist.end() ) {
129  // if the iterator has looked through the whole list
130  // and didn't find anything, the tag is not in the blacklist.
131  return 0;
132  }
133  else {
134  return 1;
135  }
136 }
137 
146 {
147  // Check for null pointer.
148  if ( pSenseable == NULL) {
149  throw std::invalid_argument("pSenseable was NULL inside tgCompoundRigidSensorInfo.");
150  }
151  else {
152  // Condition 1: cast to tgModel, since compound rigids are always tgModels,
153  // and since we need the tags from the objects and tgSenseables don't have tags.
154  tgModel* pModel = tgCast::cast<tgSenseable, tgModel>(pSenseable);
155  if (pModel == 0 ) {
156  return 0;
157  }
158  // Then, get the compound tags for this model.
159  std::map<std::string, int> compounds = getCompoundTags(pModel);
160 
161  // note that we don't need to expressly check if there are
162  // two or more descendants of this model. If there are less, then
163  // 'compounds' will just have no entries.
164 
165  // Condition 2:
166  // Are there any valid compounds?
167  // Iterate over the map:
168  std::map<std::string, int>::iterator it;
169  for( it = compounds.begin(); it != compounds.end(); ++it){
170  // The 'second' field of this iterator is the value.
171  // We need at least two rigids in order to have a proper compound.
172  if( (it->second) >= 2 ) {
173  // Condition 3: finally, check and return true iff this compound
174  // tag is not in the blacklist.
175  if( !isBlacklisted( it->first ) ){
176  return 1;
177  }
178  }
179  else if( (it->second) == 1) {
180  // It should never happen that there is only one object with a
181  // compound tag...
182  throw std::runtime_error("There is only one object with a compound tag. That's not possible, compound tgModels should be at least two objects. Exiting.");
183  }
184  }
185  // If there were no compound tags,
186  return 0;
187  }
188 }
189 
194 {
195  //CHECK: the caller SHOULD HAVE made sure that pSenseable
196  // satisfied the conditions of sensor creation.
197  if (!isThisMySenseable(pSenseable)) {
198  throw std::invalid_argument("pSenseable is NOT a valid tgModel or does not have non-blacklisted compound rigid bodies, inside tgCompoundRigidSensorInfo.");
199  }
200  // Then, if the program hasn't quit, make the sensor.
201  std::vector<tgSensor*> newSensors;
202 
211  // First, need to cast the pointer to tgModel.
212  tgModel* pModel = tgCast::cast<tgSenseable, tgModel>(pSenseable);
213  if (pModel == 0 ) {
214  throw std::invalid_argument("pSenseable is not a tgModel inside tgCompoundRigidSensorInfo::createSensorsIfAppropriate.");
215  }
216 
217  // (1)
218  std::map<std::string, int> compounds = getCompoundTags(pModel);
219  // (2)
220  for( size_t i=0; i < blacklist.size(); i++) {
221  // Note that it's valid to erase a non-existant key from a map.
222  compounds.erase(blacklist[i]);
223  }
224  // (3)
225  // Use an iterator over the map
226  std::map<std::string, int>::iterator it;
227  for( it = compounds.begin(); it != compounds.end(); ++it){
228  // Add a new sensor for the specified tag.
229  // At this point, it should be GUARANTEED that the tag
230  // exists in the model, so this should always be valid...
231  // Note that it->first points to a tag in this map.
232  newSensors.push_back( new tgCompoundRigidSensor(pModel, it->first) );
233  // (4)
234  // Now that a sensor for this tag has been created, add
235  // this tag to the blacklist.
236  blacklist.push_back( it->first );
237  }
238 
239  // This list should now be populated.
240  return newSensors;
241 }
virtual std::vector< tgSensor * > createSensorsIfAppropriate(tgSenseable *pSenseable)
Create a box shape as an obstacle or add it to your tensegrity.
Constains definition of concrete class tgCompoundRigidSensor.
Utility class for class casting and filtering collections by type.
virtual bool isThisMySenseable(tgSenseable *pSenseable)
Contains the definition of class tgModel.
Definition of concrete class tgCompoundRigidSensorInfo.
Constains the implementation of mixin class tgSenseable.
std::vector< tgModel * > getDescendants() const
Definition: tgModel.cpp:170