common.cpp
Go to the documentation of this file.
1 
29 #include <cstdio>
30 #include <fstream>
31 #include <iostream>
32 #include <iomanip>
33 #include <boost/algorithm/string.hpp>
34 #include <console_bridge/console.h>
36 
37 #include <tesseract_common/utils.h>
38 #include <tesseract_common/types.h>
41 
42 namespace tesseract_collision
43 {
44 std::vector<ObjectPairKey>
45 getCollisionObjectPairs(const std::vector<std::string>& active_links,
46  const std::vector<std::string>& static_links,
47  const std::shared_ptr<const tesseract_common::ContactAllowedValidator>& validator)
48 {
49  std::size_t num_pairs = active_links.size() * (active_links.size() - 1) / 2;
50  num_pairs += (active_links.size() * static_links.size());
51 
52  std::vector<ObjectPairKey> clp;
53  clp.reserve(num_pairs);
54 
55  // Create active to active pairs
56  for (std::size_t i = 0; i < active_links.size() - 1; ++i)
57  {
58  const std::string& l1 = active_links[i];
59  for (std::size_t j = i + 1; j < active_links.size(); ++j)
60  {
61  const std::string& l2 = active_links[j];
62  if (validator == nullptr || (validator != nullptr && !(*validator)(l1, l2)))
63  clp.push_back(tesseract_common::makeOrderedLinkPair(l1, l2));
64  }
65  }
66 
67  // Create active to static pairs
68  for (const auto& l1 : active_links)
69  {
70  for (const auto& l2 : static_links)
71  {
72  if (validator == nullptr || (validator != nullptr && !(*validator)(l1, l2)))
73  clp.push_back(tesseract_common::makeOrderedLinkPair(l1, l2));
74  }
75  }
76 
77  return clp;
78 }
79 
80 bool isLinkActive(const std::vector<std::string>& active, const std::string& name)
81 {
82  return active.empty() || (std::find(active.begin(), active.end(), name) != active.end());
83 }
84 
85 bool isContactAllowed(const std::string& name1,
86  const std::string& name2,
87  const std::shared_ptr<const tesseract_common::ContactAllowedValidator>& validator,
88  bool verbose)
89 {
90  // do not distance check geoms part of the same object / link / attached body
91  if (name1 == name2)
92  return true;
93 
94  if (validator != nullptr && (*validator)(name1, name2))
95  {
96  if (verbose)
97  {
98  CONSOLE_BRIDGE_logError(
99  "Collision between '%s' and '%s' is allowed. No contacts are computed.", name1.c_str(), name2.c_str());
100  }
101  return true;
102  }
103 
104  if (verbose)
105  {
106  CONSOLE_BRIDGE_logError("Actually checking collisions between %s and %s", name1.c_str(), name2.c_str());
107  }
108 
109  return false;
110 }
111 
113  ContactResult& contact,
114  const std::pair<std::string, std::string>& key,
115  bool found)
116 {
117  if (cdata.req.is_valid && !(*cdata.req.is_valid)(contact))
118  return nullptr;
119 
120  if ((cdata.req.calculate_distance || cdata.req.calculate_penetration) &&
121  (contact.distance > cdata.collision_margin_data.getCollisionMargin(key.first, key.second)))
122  return nullptr;
123 
124  if (!found)
125  {
126  if (cdata.req.type == ContactTestType::FIRST)
127  cdata.done = true;
128 
129  return &(cdata.res->addContactResult(key, contact));
130  }
131 
132  assert(cdata.req.type != ContactTestType::FIRST);
133  if (cdata.req.type == ContactTestType::ALL)
134  return &(cdata.res->addContactResult(key, contact));
135 
136  if (cdata.req.type == ContactTestType::CLOSEST)
137  {
138  const auto& cv = cdata.res->at(key);
139  assert(!cv.empty());
140 
141  if (contact.distance < cv.front().distance)
142  return &(cdata.res->setContactResult(key, contact));
143  }
144 
145  // else if (cdata.cdata.condition == DistanceRequestType::LIMITED)
146  // {
147  // assert(dr.size() < cdata.req->max_contacts_per_body);
148  // dr.emplace_back(contact);
149  // return &(dr.back());
150  // }
151 
152  return nullptr;
153 }
154 
156  const Eigen::Vector3d& center,
157  const Eigen::Vector3d& scale)
158 {
159  for (auto& v : vertices)
160  v = scale.cwiseProduct(v - center) + center;
161 }
162 
163 void scaleVertices(tesseract_common::VectorVector3d& vertices, const Eigen::Vector3d& scale)
164 {
165  Eigen::Vector3d center(0, 0, 0);
166  for (const auto& v : vertices)
167  center = center + v;
168 
169  center = (1.0 / static_cast<double>(vertices.size())) * center;
170 
171  scaleVertices(vertices, center, scale);
172 }
173 
174 bool writeSimplePlyFile(const std::string& path,
175  const tesseract_common::VectorVector3d& vertices,
176  const std::vector<Eigen::Vector3i>& vectices_color,
177  const Eigen::VectorXi& faces,
178  int num_faces)
179 {
180  // ply
181  // format ascii 1.0 { ascii/binary, format version number }
182  // comment made by Greg Turk { comments keyword specified, like all lines }
183  // comment this file is a cube
184  // element vertex 8 { define "vertex" element, 8 of them in file }
185  // property float x { vertex contains float "x" coordinate }
186  // property float y { y coordinate is also a vertex property }
187  // property float z { z coordinate, too }
188  // property uchar red { start of vertex color }
189  // property uchar green
190  // property uchar blue
191  // element face 6 { there are 6 "face" elements in the file }
192  // property list uchar int vertex_index { "vertex_indices" is a list of ints }
193  // end_header { delimits the end of the header }
194  // 0 0 0 { start of vertex list }
195  // 0 0 1
196  // 0 1 1
197  // 0 1 0
198  // 1 0 0
199  // 1 0 1
200  // 1 1 1
201  // 1 1 0
202  // 4 0 1 2 3 { start of face list }
203  // 4 7 6 5 4
204  // 4 0 4 5 1
205  // 4 1 5 6 2
206  // 4 2 6 7 3
207  // 4 3 7 4 0
208  std::ofstream myfile;
209  myfile.open(path);
210  if (myfile.fail())
211  {
212  CONSOLE_BRIDGE_logError("Failed to open file: %s", path.c_str());
213  return false;
214  }
215 
216  myfile << "ply\n";
217  myfile << "format ascii 1.0\n";
218  myfile << "comment made by tesseract\n";
219  myfile << "element vertex " << vertices.size() << "\n";
220  myfile << "property float x\n";
221  myfile << "property float y\n";
222  myfile << "property float z\n";
223  if (!vectices_color.empty())
224  {
225  myfile << "property uchar red\n";
226  myfile << "property uchar green\n";
227  myfile << "property uchar blue\n";
228  }
229  myfile << "element face " << num_faces << "\n";
230  myfile << "property list uchar int vertex_indices\n";
231  myfile << "end_header\n";
232 
233  // Add vertices
234  if (vectices_color.empty())
235  {
236  for (const auto& v : vertices)
237  {
238  myfile << std::fixed << std::setprecision(std::numeric_limits<float>::digits10 + 1) << v[0] << " " << v[1] << " "
239  << v[2] << "\n";
240  }
241  }
242  else if (vectices_color.size() == 1)
243  {
244  const Eigen::Vector3i& default_color = vectices_color[0];
245  for (const auto& v : vertices)
246  {
247  myfile << std::fixed << std::setprecision(std::numeric_limits<float>::digits10 + 1) << v[0] << " " << v[1] << " "
248  << v[2] << " " << default_color[0] << " " << default_color[1] << " " << default_color[2] << "\n";
249  }
250  }
251  else
252  {
253  for (std::size_t i = 0; i < vertices.size(); ++i)
254  {
255  const Eigen::Vector3d& v = vertices[i];
256  const Eigen::Vector3i& v_color = vectices_color[i];
257  myfile << std::fixed << std::setprecision(std::numeric_limits<float>::digits10 + 1) << v[0] << " " << v[1] << " "
258  << v[2] << " " << v_color[0] << " " << v_color[1] << " " << v_color[2] << "\n";
259  }
260  }
261 
262  // Add faces
263  long idx = 0;
264  for (long i = 0; i < num_faces; ++i)
265  {
266  long num_vert = faces[idx];
267  for (long j = 0; j < num_vert; ++j)
268  {
269  myfile << faces[idx] << " ";
270  ++idx;
271  }
272  myfile << faces[idx] << "\n";
273  ++idx;
274  }
275 
276  myfile.close();
277  return true;
278 }
279 
280 bool writeSimplePlyFile(const std::string& path,
281  const tesseract_common::VectorVector3d& vertices,
282  const Eigen::VectorXi& faces,
283  int num_faces)
284 {
285  std::vector<Eigen::Vector3i> vertices_color;
286  return writeSimplePlyFile(path, vertices, vertices_color, faces, num_faces);
287 }
288 
289 int loadSimplePlyFile(const std::string& path,
291  Eigen::VectorXi& faces,
292  bool triangles_only)
293 {
294  // ply
295  // format ascii 1.0 { ascii/binary, format version number }
296  // comment made by Greg Turk { comments keyword specified, like all lines }
297  // comment this file is a cube
298  // element vertex 8 { define "vertex" element, 8 of them in file }
299  // property float x { vertex contains float "x" coordinate }
300  // property float y { y coordinate is also a vertex property }
301  // property float z { z coordinate, too }
302  // element face 6 { there are 6 "face" elements in the file }
303  // property list uchar int vertex_index { "vertex_indices" is a list of ints }
304  // end_header { delimits the end of the header }
305  // 0 0 0 { start of vertex list }
306  // 0 0 1
307  // 0 1 1
308  // 0 1 0
309  // 1 0 0
310  // 1 0 1
311  // 1 1 1
312  // 1 1 0
313  // 4 0 1 2 3 { start of face list }
314  // 4 7 6 5 4
315  // 4 0 4 5 1
316  // 4 1 5 6 2
317  // 4 2 6 7 3
318  // 4 3 7 4 0
319 
320  vertices.clear();
321 
322  std::ifstream myfile;
323  myfile.open(path);
324  if (myfile.fail())
325  {
326  CONSOLE_BRIDGE_logError("Failed to open file: %s", path.c_str());
327  return 0;
328  }
329  std::string str;
330  std::getline(myfile, str);
331  std::getline(myfile, str);
332  std::getline(myfile, str);
333  std::getline(myfile, str);
334  std::vector<std::string> tokens;
335  boost::split(tokens, str, boost::is_any_of(" "));
336  if (tokens.size() != 3 || !tesseract_common::isNumeric(tokens.back()))
337  {
338  CONSOLE_BRIDGE_logError("Failed to parse file: %s", path.c_str());
339  return 0;
340  }
341  auto num_vertices = static_cast<size_t>(std::stoi(tokens.back()));
342 
343  std::getline(myfile, str);
344  std::getline(myfile, str);
345  std::getline(myfile, str);
346  std::getline(myfile, str);
347 
348  tokens.clear();
349  boost::split(tokens, str, boost::is_any_of(" "));
350  if (tokens.size() != 3 || !tesseract_common::isNumeric(tokens.back()))
351  {
352  CONSOLE_BRIDGE_logError("Failed to parse file: %s", path.c_str());
353  return 0;
354  }
355 
356  auto num_faces = static_cast<size_t>(std::stoi(tokens.back()));
357  std::getline(myfile, str);
358  std::getline(myfile, str);
359  if (str != "end_header")
360  {
361  CONSOLE_BRIDGE_logError("Failed to parse file: %s", path.c_str());
362  return 0;
363  }
364 
365  vertices.reserve(num_vertices);
366  for (size_t i = 0; i < num_vertices; ++i)
367  {
368  std::getline(myfile, str);
369  tokens.clear();
370  boost::split(tokens, str, boost::is_any_of(" "));
371  if (tokens.size() != 3)
372  {
373  CONSOLE_BRIDGE_logError("Failed to parse file: %s", path.c_str());
374  return 0;
375  }
376 
377  vertices.emplace_back(std::stod(tokens[0]), std::stod(tokens[1]), std::stod(tokens[2]));
378  }
379 
380  std::vector<int> local_faces;
381  local_faces.reserve(num_faces * 3);
382  size_t copy_num_faces = num_faces; // Becuase num_faces can change within for loop
383  for (size_t i = 0; i < copy_num_faces; ++i)
384  {
385  std::getline(myfile, str);
386  tokens.clear();
387  boost::split(tokens, str, boost::is_any_of(" "));
388  if (tokens.size() < 3)
389  {
390  CONSOLE_BRIDGE_logError("Failed to parse file: %s", path.c_str());
391  return 0;
392  }
393 
394  auto num_verts = static_cast<int>(tokens.size());
395  assert(num_verts >= 3);
396  if (triangles_only && num_verts > 3)
397  {
398  local_faces.push_back(3);
399  local_faces.push_back(std::stoi(tokens[0]));
400  local_faces.push_back(std::stoi(tokens[1]));
401  local_faces.push_back(std::stoi(tokens[2]));
402  for (size_t i = 3; i < tokens.size(); ++i)
403  {
404  num_faces += 1;
405  local_faces.push_back(3);
406  local_faces.push_back(std::stoi(tokens[0]));
407  local_faces.push_back(std::stoi(tokens[i - 1]));
408  local_faces.push_back(std::stoi(tokens[i]));
409  }
410  }
411  else
412  {
413  local_faces.push_back(static_cast<int>(tokens.size()));
414  for (const auto& t : tokens)
415  local_faces.push_back(std::stoi(t));
416  }
417  }
418 
419  faces.resize(static_cast<long>(local_faces.size()));
420  for (size_t i = 0; i < local_faces.size(); ++i)
421  faces[static_cast<long>(i)] = local_faces[i];
422 
423  myfile.close();
424  return static_cast<int>(num_faces);
425 }
426 
427 } // namespace tesseract_collision
tesseract_collision::ContactTestData
This data is intended only to be used internal to the collision checkers as a container and should no...
Definition: types.h:328
tesseract_collision::isContactAllowed
bool isContactAllowed(const std::string &name1, const std::string &name2, const std::shared_ptr< const tesseract_common::ContactAllowedValidator > &validator, bool verbose=false)
Determine if contact is allowed between two objects.
Definition: common.cpp:85
tesseract_collision::ContactRequest::calculate_distance
bool calculate_distance
This enables the calculation of distance data if two objects are within the contact threshold.
Definition: types.h:309
tesseract_collision::ContactTestData::done
bool done
Indicate if search is finished.
Definition: types.h:355
tesseract_collision::ContactResultMap::setContactResult
ContactResult & setContactResult(const KeyType &key, ContactResult result)
Set contact results for the provided key.
Definition: types.cpp:122
utils.h
tesseract_collision::isLinkActive
bool isLinkActive(const std::vector< std::string > &active, const std::string &name)
This will check if a link is active provided a list. If the list is empty the link is considered acti...
Definition: common.cpp:80
tesseract_collision::ContactResultMap::addContactResult
ContactResult & addContactResult(const KeyType &key, ContactResult result)
Add contact results for the provided key.
Definition: types.cpp:103
tesseract_collision::ContactRequest::type
ContactTestType type
This controls the exit condition for the contact test type.
Definition: types.h:303
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
tesseract_collision::loadSimplePlyFile
int loadSimplePlyFile(const std::string &path, tesseract_common::VectorVector3d &vertices, Eigen::VectorXi &faces, bool triangles_only=false)
Loads a simple ply file given a path.
Definition: common.cpp:289
tesseract_common::CollisionMarginData::getCollisionMargin
double getCollisionMargin(const std::string &obj1, const std::string &obj2) const
tesseract_collision::ContactTestData::collision_margin_data
CollisionMarginData collision_margin_data
The current contact_distance threshold.
Definition: types.h:343
tesseract_collision::ContactResultMap::at
const ContactResultVector & at(const KeyType &key) const
access specified element with bounds checking
Definition: types.cpp:266
tesseract_collision::scaleVertices
void scaleVertices(tesseract_common::VectorVector3d &vertices, const Eigen::Vector3d &center, const Eigen::Vector3d &scale)
Apply scaling to the geometry coordinates.
Definition: common.cpp:155
tesseract_collision::getCollisionObjectPairs
std::vector< ObjectPairKey > getCollisionObjectPairs(const std::vector< std::string > &active_links, const std::vector< std::string > &static_links, const std::shared_ptr< const tesseract_common::ContactAllowedValidator > &validator=nullptr)
Get a vector of possible collision object pairs.
Definition: common.cpp:45
name
std::string name
tesseract_common::VectorVector3d
std::vector< Eigen::Vector3d > VectorVector3d
tesseract_collision::ContactRequest::is_valid
std::shared_ptr< const ContactResultValidator > is_valid
This provides a user defined function approve/reject contact results.
Definition: types.h:316
TESSERACT_COMMON_IGNORE_WARNINGS_POP
Definition: create_convex_hull.cpp:37
tesseract_collision::ContactTestData::res
ContactResultMap * res
Distance query results information.
Definition: types.h:352
contact_result_validator.h
Contact result validator.
common.h
This is a collection of common methods.
tesseract_collision::ContactTestType::FIRST
@ FIRST
tesseract_collision::ContactResult::distance
EIGEN_MAKE_ALIGNED_OPERATOR_NEW double distance
The distance between two links.
Definition: types.h:88
tesseract_collision::ContactTestData::req
ContactRequest req
The type of contact request data.
Definition: types.h:349
tesseract_common::isNumeric
bool isNumeric(const std::string &s)
tesseract_common::makeOrderedLinkPair
LinkNamesPair makeOrderedLinkPair(const std::string &link_name1, const std::string &link_name2)
tesseract_collision
Definition: bullet_cast_bvh_manager.h:48
types.h
macros.h
tesseract_collision::ContactTestType::ALL
@ ALL
tesseract_collision::processResult
ContactResult * processResult(ContactTestData &cdata, ContactResult &contact, const std::pair< std::string, std::string > &key, bool found)
processResult Processes the ContactResult based on the information in the ContactTestData
Definition: common.cpp:112
tesseract_collision::ContactResult
Definition: types.h:81
tesseract_collision::writeSimplePlyFile
bool writeSimplePlyFile(const std::string &path, const tesseract_common::VectorVector3d &vertices, const std::vector< Eigen::Vector3i > &vectices_color, const Eigen::VectorXi &faces, int num_faces)
Write a simple ply file given vertices and faces.
Definition: common.cpp:174
tesseract_collision::ContactTestType::CLOSEST
@ CLOSEST
tesseract_collision::ContactRequest::calculate_penetration
bool calculate_penetration
This enables the calculation of penetration contact data if two objects are in collision.
Definition: types.h:306
verbose
bool verbose


tesseract_collision
Author(s): Levi Armstrong
autogenerated on Sun May 18 2025 03:01:52