| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /////////////////////////////////////////////////////////////////////////////// | ||
| 2 | // BSD 3-Clause License | ||
| 3 | // | ||
| 4 | // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh, | ||
| 5 | // Heriot-Watt University | ||
| 6 | // Copyright note valid unless otherwise stated in individual files. | ||
| 7 | // All rights reserved. | ||
| 8 | /////////////////////////////////////////////////////////////////////////////// | ||
| 9 | |||
| 10 | namespace crocoddyl { | ||
| 11 | |||
| 12 | template <typename Scalar> | ||
| 13 | ✗ | ContactModelMultipleTpl<Scalar>::ContactModelMultipleTpl( | |
| 14 | std::shared_ptr<StateMultibody> state, const std::size_t nu) | ||
| 15 | ✗ | : state_(state), | |
| 16 | ✗ | nc_(0), | |
| 17 | ✗ | nc_total_(0), | |
| 18 | ✗ | nu_(nu), | |
| 19 | ✗ | compute_all_contacts_(false) {} | |
| 20 | |||
| 21 | template <typename Scalar> | ||
| 22 | ✗ | ContactModelMultipleTpl<Scalar>::ContactModelMultipleTpl( | |
| 23 | std::shared_ptr<StateMultibody> state) | ||
| 24 | ✗ | : state_(state), | |
| 25 | ✗ | nc_(0), | |
| 26 | ✗ | nc_total_(0), | |
| 27 | ✗ | nu_(state->get_nv()), | |
| 28 | ✗ | compute_all_contacts_(false) {} | |
| 29 | |||
| 30 | template <typename Scalar> | ||
| 31 | ✗ | ContactModelMultipleTpl<Scalar>::~ContactModelMultipleTpl() {} | |
| 32 | |||
| 33 | template <typename Scalar> | ||
| 34 | ✗ | void ContactModelMultipleTpl<Scalar>::addContact( | |
| 35 | const std::string& name, std::shared_ptr<ContactModelAbstract> contact, | ||
| 36 | const bool active) { | ||
| 37 | ✗ | if (contact->get_nu() != nu_) { | |
| 38 | ✗ | throw_pretty("Invalid argument: " | |
| 39 | << name | ||
| 40 | << " contact item doesn't have the same control dimension (" + | ||
| 41 | std::to_string(nu_) + ")"); | ||
| 42 | } | ||
| 43 | std::pair<typename ContactModelContainer::iterator, bool> ret = | ||
| 44 | ✗ | contacts_.insert(std::make_pair( | |
| 45 | name, std::make_shared<ContactItem>(name, contact, active))); | ||
| 46 | ✗ | if (ret.second == false) { | |
| 47 | std::cerr << "Warning: we couldn't add the " << name | ||
| 48 | ✗ | << " contact item, it already existed." << std::endl; | |
| 49 | ✗ | } else if (active) { | |
| 50 | ✗ | nc_ += contact->get_nc(); | |
| 51 | ✗ | nc_total_ += contact->get_nc(); | |
| 52 | ✗ | active_set_.insert(name); | |
| 53 | ✗ | } else if (!active) { | |
| 54 | ✗ | nc_total_ += contact->get_nc(); | |
| 55 | ✗ | inactive_set_.insert(name); | |
| 56 | } | ||
| 57 | ✗ | } | |
| 58 | |||
| 59 | template <typename Scalar> | ||
| 60 | ✗ | void ContactModelMultipleTpl<Scalar>::removeContact(const std::string& name) { | |
| 61 | ✗ | typename ContactModelContainer::iterator it = contacts_.find(name); | |
| 62 | ✗ | if (it != contacts_.end()) { | |
| 63 | ✗ | nc_ -= it->second->contact->get_nc(); | |
| 64 | ✗ | nc_total_ -= it->second->contact->get_nc(); | |
| 65 | ✗ | contacts_.erase(it); | |
| 66 | ✗ | active_set_.erase(name); | |
| 67 | ✗ | inactive_set_.erase(name); | |
| 68 | } else { | ||
| 69 | std::cerr << "Warning: we couldn't remove the " << name | ||
| 70 | ✗ | << " contact item, it doesn't exist." << std::endl; | |
| 71 | } | ||
| 72 | ✗ | } | |
| 73 | |||
| 74 | template <typename Scalar> | ||
| 75 | ✗ | void ContactModelMultipleTpl<Scalar>::changeContactStatus( | |
| 76 | const std::string& name, const bool active) { | ||
| 77 | ✗ | typename ContactModelContainer::iterator it = contacts_.find(name); | |
| 78 | ✗ | if (it != contacts_.end()) { | |
| 79 | ✗ | if (active && !it->second->active) { | |
| 80 | ✗ | nc_ += it->second->contact->get_nc(); | |
| 81 | ✗ | active_set_.insert(name); | |
| 82 | ✗ | inactive_set_.erase(name); | |
| 83 | ✗ | } else if (!active && it->second->active) { | |
| 84 | ✗ | nc_ -= it->second->contact->get_nc(); | |
| 85 | ✗ | inactive_set_.insert(name); | |
| 86 | ✗ | active_set_.erase(name); | |
| 87 | } | ||
| 88 | // "else" case: Contact status unchanged - already in desired state | ||
| 89 | ✗ | it->second->active = active; | |
| 90 | } else { | ||
| 91 | std::cerr << "Warning: we couldn't change the status of the " << name | ||
| 92 | ✗ | << " contact item, it doesn't exist." << std::endl; | |
| 93 | } | ||
| 94 | ✗ | } | |
| 95 | |||
| 96 | template <typename Scalar> | ||
| 97 | ✗ | void ContactModelMultipleTpl<Scalar>::calc( | |
| 98 | const std::shared_ptr<ContactDataMultiple>& data, | ||
| 99 | const Eigen::Ref<const VectorXs>& x) { | ||
| 100 | ✗ | if (data->contacts.size() != contacts_.size()) { | |
| 101 | ✗ | throw_pretty("Invalid argument: " | |
| 102 | << "it doesn't match the number of contact datas and models"); | ||
| 103 | } | ||
| 104 | |||
| 105 | ✗ | std::size_t nc = 0; | |
| 106 | ✗ | const std::size_t nv = state_->get_nv(); | |
| 107 | ✗ | typename ContactModelContainer::iterator it_m, end_m; | |
| 108 | ✗ | typename ContactDataContainer::iterator it_d, end_d; | |
| 109 | ✗ | if (compute_all_contacts_) { | |
| 110 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 111 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 112 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 113 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 114 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 115 | ✗ | if (m_i->active) { | |
| 116 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 117 | ✗ | assert_pretty( | |
| 118 | it_m->first == it_d->first, | ||
| 119 | "it doesn't match the contact name between model and data (" | ||
| 120 | << it_m->first << " != " << it_d->first << ")"); | ||
| 121 | ✗ | m_i->contact->calc(d_i, x); | |
| 122 | ✗ | data->a0.segment(nc, nc_i) = d_i->a0; | |
| 123 | ✗ | data->Jc.block(nc, 0, nc_i, nv) = d_i->Jc; | |
| 124 | } else { | ||
| 125 | ✗ | data->a0.segment(nc, nc_i).setZero(); | |
| 126 | ✗ | data->Jc.block(nc, 0, nc_i, nv).setZero(); | |
| 127 | } | ||
| 128 | ✗ | nc += nc_i; | |
| 129 | } | ||
| 130 | } else { | ||
| 131 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 132 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 133 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 134 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 135 | ✗ | if (m_i->active) { | |
| 136 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 137 | ✗ | assert_pretty( | |
| 138 | it_m->first == it_d->first, | ||
| 139 | "it doesn't match the contact name between model and data (" | ||
| 140 | << it_m->first << " != " << it_d->first << ")"); | ||
| 141 | |||
| 142 | ✗ | m_i->contact->calc(d_i, x); | |
| 143 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 144 | ✗ | data->a0.segment(nc, nc_i) = d_i->a0; | |
| 145 | ✗ | data->Jc.block(nc, 0, nc_i, nv) = d_i->Jc; | |
| 146 | ✗ | nc += nc_i; | |
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | ✗ | } | |
| 151 | |||
| 152 | template <typename Scalar> | ||
| 153 | ✗ | void ContactModelMultipleTpl<Scalar>::calcDiff( | |
| 154 | const std::shared_ptr<ContactDataMultiple>& data, | ||
| 155 | const Eigen::Ref<const VectorXs>& x) { | ||
| 156 | ✗ | if (data->contacts.size() != contacts_.size()) { | |
| 157 | ✗ | throw_pretty("Invalid argument: " | |
| 158 | << "it doesn't match the number of contact datas and models"); | ||
| 159 | } | ||
| 160 | |||
| 161 | ✗ | std::size_t nc = 0; | |
| 162 | ✗ | const std::size_t ndx = state_->get_ndx(); | |
| 163 | ✗ | typename ContactModelContainer::iterator it_m, end_m; | |
| 164 | ✗ | typename ContactDataContainer::iterator it_d, end_d; | |
| 165 | ✗ | if (compute_all_contacts_) { | |
| 166 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 167 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 168 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 169 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 170 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 171 | ✗ | if (m_i->active) { | |
| 172 | ✗ | assert_pretty( | |
| 173 | it_m->first == it_d->first, | ||
| 174 | "it doesn't match the contact name between model and data (" | ||
| 175 | << it_m->first << " != " << it_d->first << ")"); | ||
| 176 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 177 | |||
| 178 | ✗ | m_i->contact->calcDiff(d_i, x); | |
| 179 | ✗ | data->da0_dx.block(nc, 0, nc_i, ndx) = d_i->da0_dx; | |
| 180 | } else { | ||
| 181 | ✗ | data->da0_dx.block(nc, 0, nc_i, ndx).setZero(); | |
| 182 | } | ||
| 183 | ✗ | nc += nc_i; | |
| 184 | } | ||
| 185 | } else { | ||
| 186 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 187 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 188 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 189 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 190 | ✗ | if (m_i->active) { | |
| 191 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 192 | ✗ | assert_pretty( | |
| 193 | it_m->first == it_d->first, | ||
| 194 | "it doesn't match the contact name between model and data (" | ||
| 195 | << it_m->first << " != " << it_d->first << ")"); | ||
| 196 | |||
| 197 | ✗ | m_i->contact->calcDiff(d_i, x); | |
| 198 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 199 | ✗ | data->da0_dx.block(nc, 0, nc_i, ndx) = d_i->da0_dx; | |
| 200 | ✗ | nc += nc_i; | |
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | ✗ | } | |
| 205 | |||
| 206 | template <typename Scalar> | ||
| 207 | ✗ | void ContactModelMultipleTpl<Scalar>::updateAcceleration( | |
| 208 | const std::shared_ptr<ContactDataMultiple>& data, | ||
| 209 | const VectorXs& dv) const { | ||
| 210 | ✗ | if (static_cast<std::size_t>(dv.size()) != state_->get_nv()) { | |
| 211 | ✗ | throw_pretty( | |
| 212 | "Invalid argument: " << "dv has wrong dimension (it should be " + | ||
| 213 | std::to_string(state_->get_nv()) + ")"); | ||
| 214 | } | ||
| 215 | ✗ | data->dv = dv; | |
| 216 | ✗ | } | |
| 217 | |||
| 218 | template <typename Scalar> | ||
| 219 | ✗ | void ContactModelMultipleTpl<Scalar>::updateForce( | |
| 220 | const std::shared_ptr<ContactDataMultiple>& data, const VectorXs& force) { | ||
| 221 | ✗ | if (static_cast<std::size_t>(force.size()) != | |
| 222 | ✗ | (compute_all_contacts_ ? nc_total_ : nc_)) { | |
| 223 | ✗ | throw_pretty( | |
| 224 | "Invalid argument: " | ||
| 225 | << "force has wrong dimension (it should be " + | ||
| 226 | std::to_string((compute_all_contacts_ ? nc_total_ : nc_)) + ")"); | ||
| 227 | } | ||
| 228 | ✗ | if (static_cast<std::size_t>(data->contacts.size()) != contacts_.size()) { | |
| 229 | ✗ | throw_pretty("Invalid argument: " | |
| 230 | << "it doesn't match the number of contact datas and models"); | ||
| 231 | } | ||
| 232 | |||
| 233 | ✗ | for (ForceIterator it = data->fext.begin(); it != data->fext.end(); ++it) { | |
| 234 | ✗ | *it = pinocchio::ForceTpl<Scalar>::Zero(); | |
| 235 | } | ||
| 236 | |||
| 237 | ✗ | std::size_t nc = 0; | |
| 238 | ✗ | typename ContactModelContainer::iterator it_m, end_m; | |
| 239 | ✗ | typename ContactDataContainer::iterator it_d, end_d; | |
| 240 | ✗ | if (compute_all_contacts_) { | |
| 241 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 242 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 243 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 244 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 245 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 246 | ✗ | assert_pretty(it_m->first == it_d->first, | |
| 247 | "it doesn't match the contact name between data and model"); | ||
| 248 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 249 | ✗ | if (m_i->active) { | |
| 250 | const Eigen::VectorBlock<const VectorXs, Eigen::Dynamic> force_i = | ||
| 251 | ✗ | force.segment(nc, nc_i); | |
| 252 | ✗ | m_i->contact->updateForce(d_i, force_i); | |
| 253 | ✗ | const pinocchio::JointIndex joint = | |
| 254 | ✗ | state_->get_pinocchio()->frames[d_i->frame].parentJoint; | |
| 255 | ✗ | data->fext[joint] = d_i->fext; | |
| 256 | } else { | ||
| 257 | ✗ | m_i->contact->setZeroForce(d_i); | |
| 258 | } | ||
| 259 | ✗ | nc += nc_i; | |
| 260 | } | ||
| 261 | } else { | ||
| 262 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 263 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 264 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 265 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 266 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 267 | ✗ | assert_pretty(it_m->first == it_d->first, | |
| 268 | "it doesn't match the contact name between data and model"); | ||
| 269 | ✗ | if (m_i->active) { | |
| 270 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 271 | const Eigen::VectorBlock<const VectorXs, Eigen::Dynamic> force_i = | ||
| 272 | ✗ | force.segment(nc, nc_i); | |
| 273 | ✗ | m_i->contact->updateForce(d_i, force_i); | |
| 274 | ✗ | const pinocchio::JointIndex joint = | |
| 275 | ✗ | state_->get_pinocchio()->frames[d_i->frame].parentJoint; | |
| 276 | ✗ | data->fext[joint] = d_i->fext; | |
| 277 | ✗ | nc += nc_i; | |
| 278 | } else { | ||
| 279 | ✗ | m_i->contact->setZeroForce(d_i); | |
| 280 | } | ||
| 281 | } | ||
| 282 | } | ||
| 283 | ✗ | } | |
| 284 | |||
| 285 | template <typename Scalar> | ||
| 286 | ✗ | void ContactModelMultipleTpl<Scalar>::updateAccelerationDiff( | |
| 287 | const std::shared_ptr<ContactDataMultiple>& data, | ||
| 288 | const MatrixXs& ddv_dx) const { | ||
| 289 | ✗ | if (static_cast<std::size_t>(ddv_dx.rows()) != state_->get_nv() || | |
| 290 | ✗ | static_cast<std::size_t>(ddv_dx.cols()) != state_->get_ndx()) { | |
| 291 | ✗ | throw_pretty( | |
| 292 | "Invalid argument: " << "ddv_dx has wrong dimension (it should be " + | ||
| 293 | std::to_string(state_->get_nv()) + "," + | ||
| 294 | std::to_string(state_->get_ndx()) + ")"); | ||
| 295 | } | ||
| 296 | ✗ | data->ddv_dx = ddv_dx; | |
| 297 | ✗ | } | |
| 298 | |||
| 299 | template <typename Scalar> | ||
| 300 | ✗ | void ContactModelMultipleTpl<Scalar>::updateForceDiff( | |
| 301 | const std::shared_ptr<ContactDataMultiple>& data, const MatrixXs& df_dx, | ||
| 302 | const MatrixXs& df_du) const { | ||
| 303 | ✗ | const std::size_t ndx = state_->get_ndx(); | |
| 304 | ✗ | if (static_cast<std::size_t>(df_dx.rows()) != | |
| 305 | ✗ | (compute_all_contacts_ ? nc_total_ : nc_) || | |
| 306 | ✗ | static_cast<std::size_t>(df_dx.cols()) != ndx) { | |
| 307 | ✗ | throw_pretty( | |
| 308 | "Invalid argument: " | ||
| 309 | << "df_dx has wrong dimension (it should be " + | ||
| 310 | std::to_string((compute_all_contacts_ ? nc_total_ : nc_)) + "," + | ||
| 311 | std::to_string(ndx) + ")"); | ||
| 312 | } | ||
| 313 | ✗ | if (static_cast<std::size_t>(df_du.rows()) != | |
| 314 | ✗ | (compute_all_contacts_ ? nc_total_ : nc_) || | |
| 315 | ✗ | static_cast<std::size_t>(df_du.cols()) != nu_) { | |
| 316 | ✗ | throw_pretty( | |
| 317 | "Invalid argument: " | ||
| 318 | << "df_du has wrong dimension (it should be " + | ||
| 319 | std::to_string((compute_all_contacts_ ? nc_total_ : nc_)) + "," + | ||
| 320 | std::to_string(nu_) + ")"); | ||
| 321 | } | ||
| 322 | ✗ | if (static_cast<std::size_t>(data->contacts.size()) != contacts_.size()) { | |
| 323 | ✗ | throw_pretty("Invalid argument: " | |
| 324 | << "it doesn't match the number of contact datas and models"); | ||
| 325 | } | ||
| 326 | |||
| 327 | ✗ | std::size_t nc = 0; | |
| 328 | ✗ | typename ContactModelContainer::const_iterator it_m, end_m; | |
| 329 | ✗ | typename ContactDataContainer::const_iterator it_d, end_d; | |
| 330 | ✗ | if (compute_all_contacts_) { | |
| 331 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 332 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 333 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 334 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 335 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 336 | ✗ | assert_pretty(it_m->first == it_d->first, | |
| 337 | "it doesn't match the contact name between data and model"); | ||
| 338 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 339 | ✗ | if (m_i->active) { | |
| 340 | const Eigen::Block<const MatrixXs> df_dx_i = | ||
| 341 | ✗ | df_dx.block(nc, 0, nc_i, ndx); | |
| 342 | const Eigen::Block<const MatrixXs> df_du_i = | ||
| 343 | ✗ | df_du.block(nc, 0, nc_i, nu_); | |
| 344 | ✗ | m_i->contact->updateForceDiff(d_i, df_dx_i, df_du_i); | |
| 345 | } else { | ||
| 346 | ✗ | m_i->contact->setZeroForceDiff(d_i); | |
| 347 | } | ||
| 348 | ✗ | nc += nc_i; | |
| 349 | } | ||
| 350 | } else { | ||
| 351 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 352 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 353 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 354 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 355 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 356 | ✗ | assert_pretty(it_m->first == it_d->first, | |
| 357 | "it doesn't match the contact name between data and model"); | ||
| 358 | ✗ | if (m_i->active) { | |
| 359 | ✗ | const std::size_t nc_i = m_i->contact->get_nc(); | |
| 360 | const Eigen::Block<const MatrixXs> df_dx_i = | ||
| 361 | ✗ | df_dx.block(nc, 0, nc_i, ndx); | |
| 362 | const Eigen::Block<const MatrixXs> df_du_i = | ||
| 363 | ✗ | df_du.block(nc, 0, nc_i, nu_); | |
| 364 | ✗ | m_i->contact->updateForceDiff(d_i, df_dx_i, df_du_i); | |
| 365 | ✗ | nc += nc_i; | |
| 366 | } else { | ||
| 367 | ✗ | m_i->contact->setZeroForceDiff(d_i); | |
| 368 | } | ||
| 369 | } | ||
| 370 | } | ||
| 371 | ✗ | } | |
| 372 | |||
| 373 | template <typename Scalar> | ||
| 374 | ✗ | void ContactModelMultipleTpl<Scalar>::updateRneaDiff( | |
| 375 | const std::shared_ptr<ContactDataMultiple>& data, | ||
| 376 | pinocchio::DataTpl<Scalar>& pinocchio) const { | ||
| 377 | ✗ | if (static_cast<std::size_t>(data->contacts.size()) != | |
| 378 | ✗ | this->get_contacts().size()) { | |
| 379 | ✗ | throw_pretty("Invalid argument: " | |
| 380 | << "it doesn't match the number of contact datas and models"); | ||
| 381 | } | ||
| 382 | ✗ | typename ContactModelContainer::const_iterator it_m, end_m; | |
| 383 | ✗ | typename ContactDataContainer::const_iterator it_d, end_d; | |
| 384 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(), | |
| 385 | ✗ | it_d = data->contacts.begin(), end_d = data->contacts.end(); | |
| 386 | ✗ | it_m != end_m || it_d != end_d; ++it_m, ++it_d) { | |
| 387 | ✗ | const std::shared_ptr<ContactItem>& m_i = it_m->second; | |
| 388 | ✗ | const std::shared_ptr<ContactDataAbstract>& d_i = it_d->second; | |
| 389 | ✗ | assert_pretty(it_m->first == it_d->first, | |
| 390 | "it doesn't match the contact name between data and model"); | ||
| 391 | ✗ | if (m_i->active) { | |
| 392 | ✗ | switch (m_i->contact->get_type()) { | |
| 393 | ✗ | case pinocchio::ReferenceFrame::LOCAL: | |
| 394 | ✗ | break; | |
| 395 | ✗ | case pinocchio::ReferenceFrame::WORLD: | |
| 396 | case pinocchio::ReferenceFrame::LOCAL_WORLD_ALIGNED: | ||
| 397 | ✗ | pinocchio.dtau_dq += d_i->dtau_dq; | |
| 398 | ✗ | break; | |
| 399 | } | ||
| 400 | } | ||
| 401 | } | ||
| 402 | ✗ | } | |
| 403 | |||
| 404 | template <typename Scalar> | ||
| 405 | std::shared_ptr<ContactDataMultipleTpl<Scalar> > | ||
| 406 | ✗ | ContactModelMultipleTpl<Scalar>::createData( | |
| 407 | pinocchio::DataTpl<Scalar>* const data) { | ||
| 408 | return std::allocate_shared<ContactDataMultiple>( | ||
| 409 | ✗ | Eigen::aligned_allocator<ContactDataMultiple>(), this, data); | |
| 410 | } | ||
| 411 | |||
| 412 | template <typename Scalar> | ||
| 413 | template <typename NewScalar> | ||
| 414 | ✗ | ContactModelMultipleTpl<NewScalar> ContactModelMultipleTpl<Scalar>::cast() | |
| 415 | const { | ||
| 416 | typedef ContactModelMultipleTpl<NewScalar> ReturnType; | ||
| 417 | typedef StateMultibodyTpl<NewScalar> StateType; | ||
| 418 | typedef ContactItemTpl<NewScalar> ContactType; | ||
| 419 | ✗ | ReturnType ret( | |
| 420 | ✗ | std::make_shared<StateType>(state_->template cast<NewScalar>()), nu_); | |
| 421 | ✗ | typename ContactModelContainer::const_iterator it_m, end_m; | |
| 422 | ✗ | for (it_m = contacts_.begin(), end_m = contacts_.end(); it_m != end_m; | |
| 423 | ✗ | ++it_m) { | |
| 424 | ✗ | const std::string name = it_m->first; | |
| 425 | ✗ | const ContactType& m_i = it_m->second->template cast<NewScalar>(); | |
| 426 | ✗ | ret.addContact(name, m_i.contact, m_i.active); | |
| 427 | } | ||
| 428 | ✗ | return ret; | |
| 429 | ✗ | } | |
| 430 | |||
| 431 | template <typename Scalar> | ||
| 432 | const std::shared_ptr<StateMultibodyTpl<Scalar> >& | ||
| 433 | ✗ | ContactModelMultipleTpl<Scalar>::get_state() const { | |
| 434 | ✗ | return state_; | |
| 435 | } | ||
| 436 | |||
| 437 | template <typename Scalar> | ||
| 438 | const typename ContactModelMultipleTpl<Scalar>::ContactModelContainer& | ||
| 439 | ✗ | ContactModelMultipleTpl<Scalar>::get_contacts() const { | |
| 440 | ✗ | return contacts_; | |
| 441 | } | ||
| 442 | |||
| 443 | template <typename Scalar> | ||
| 444 | ✗ | std::size_t ContactModelMultipleTpl<Scalar>::get_nc() const { | |
| 445 | ✗ | return nc_; | |
| 446 | } | ||
| 447 | |||
| 448 | template <typename Scalar> | ||
| 449 | ✗ | std::size_t ContactModelMultipleTpl<Scalar>::get_nc_total() const { | |
| 450 | ✗ | return nc_total_; | |
| 451 | } | ||
| 452 | |||
| 453 | template <typename Scalar> | ||
| 454 | ✗ | std::size_t ContactModelMultipleTpl<Scalar>::get_nu() const { | |
| 455 | ✗ | return nu_; | |
| 456 | } | ||
| 457 | |||
| 458 | template <typename Scalar> | ||
| 459 | ✗ | const std::set<std::string>& ContactModelMultipleTpl<Scalar>::get_active_set() | |
| 460 | const { | ||
| 461 | ✗ | return active_set_; | |
| 462 | } | ||
| 463 | |||
| 464 | template <typename Scalar> | ||
| 465 | ✗ | const std::set<std::string>& ContactModelMultipleTpl<Scalar>::get_inactive_set() | |
| 466 | const { | ||
| 467 | ✗ | return inactive_set_; | |
| 468 | } | ||
| 469 | |||
| 470 | template <typename Scalar> | ||
| 471 | ✗ | bool ContactModelMultipleTpl<Scalar>::getContactStatus( | |
| 472 | const std::string& name) const { | ||
| 473 | ✗ | typename ContactModelContainer::const_iterator it = contacts_.find(name); | |
| 474 | ✗ | if (it != contacts_.end()) { | |
| 475 | ✗ | return it->second->active; | |
| 476 | } else { | ||
| 477 | std::cerr << "Warning: we couldn't get the status of the " << name | ||
| 478 | ✗ | << " contact item, it doesn't exist." << std::endl; | |
| 479 | ✗ | return false; | |
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | template <typename Scalar> | ||
| 484 | ✗ | bool ContactModelMultipleTpl<Scalar>::getComputeAllContacts() const { | |
| 485 | ✗ | return compute_all_contacts_; | |
| 486 | } | ||
| 487 | |||
| 488 | template <typename Scalar> | ||
| 489 | ✗ | void ContactModelMultipleTpl<Scalar>::setComputeAllContacts(const bool status) { | |
| 490 | ✗ | compute_all_contacts_ = status; | |
| 491 | ✗ | } | |
| 492 | |||
| 493 | template <class Scalar> | ||
| 494 | ✗ | std::ostream& operator<<(std::ostream& os, | |
| 495 | const ContactModelMultipleTpl<Scalar>& model) { | ||
| 496 | ✗ | const auto& active = model.get_active_set(); | |
| 497 | ✗ | const auto& inactive = model.get_inactive_set(); | |
| 498 | ✗ | os << "ContactModelMultiple:" << std::endl; | |
| 499 | ✗ | os << " Active:" << std::endl; | |
| 500 | ✗ | for (std::set<std::string>::const_iterator it = active.begin(); | |
| 501 | ✗ | it != active.end(); ++it) { | |
| 502 | const std::shared_ptr< | ||
| 503 | ✗ | typename ContactModelMultipleTpl<Scalar>::ContactItem>& contact_item = | |
| 504 | ✗ | model.get_contacts().find(*it)->second; | |
| 505 | ✗ | if (it != --active.end()) { | |
| 506 | ✗ | os << " " << *it << ": " << *contact_item << std::endl; | |
| 507 | } else { | ||
| 508 | ✗ | os << " " << *it << ": " << *contact_item << std::endl; | |
| 509 | } | ||
| 510 | } | ||
| 511 | ✗ | os << " Inactive:" << std::endl; | |
| 512 | ✗ | for (std::set<std::string>::const_iterator it = inactive.begin(); | |
| 513 | ✗ | it != inactive.end(); ++it) { | |
| 514 | const std::shared_ptr< | ||
| 515 | ✗ | typename ContactModelMultipleTpl<Scalar>::ContactItem>& contact_item = | |
| 516 | ✗ | model.get_contacts().find(*it)->second; | |
| 517 | ✗ | if (it != --inactive.end()) { | |
| 518 | ✗ | os << " " << *it << ": " << *contact_item << std::endl; | |
| 519 | } else { | ||
| 520 | ✗ | os << " " << *it << ": " << *contact_item; | |
| 521 | } | ||
| 522 | } | ||
| 523 | ✗ | return os; | |
| 524 | } | ||
| 525 | |||
| 526 | } // namespace crocoddyl | ||
| 527 |