se2ez
planpanel.cpp
Go to the documentation of this file.
1 /* Author: Constantinos Chamzas, Zachary Kingston */
2 
3 #include <QString>
4 #include <QLineEdit>
5 
6 #include <se2ez/core/robot.h>
7 #include <se2ez/core/frame.h>
8 #include <se2ez/core/state.h>
9 #include <se2ez/core/log.h>
10 #include <se2ez/core/io.h>
11 
12 #include <se2ez/plan/helper.h>
13 
14 #include <se2ez/gui/planpanel.h>
15 #include <se2ez/gui/jointpanel.h>
16 #include <se2ez/gui/scenepanel.h>
17 
18 #include "ui_planpanel.h"
19 
20 using namespace se2ez;
21 
23  std::map<std::string, ompl::base::ConstraintPtr> constraints, QWidget *parent)
24  : Panel(name, parent), ui_(new Ui::PlanPanel), robot_(robot), constraints_(constraints)
25 {
26  {
28 
29  ui_->setupUi(this);
30 
31  planner_ = std::make_shared<plan::EZPlans>(robot_);
32  planner_->initialize();
33  planner_->createPlanners();
34 
35  // allocating space for the states
36  pstate_ = std::make_shared<State>(robot_);
37 
38  // Populate constraint list
39  ui_->constraints->addItem("<none>");
40  for (const auto &constraint : constraints)
41  ui_->constraints->addItem(QString(constraint.first.c_str()));
42 
43  // Populate planner list
44  for (const auto &name : planner_->getPlanners())
45  ui_->planners->addItem(QString(name.c_str()));
46 
47  // Populate graph end-effector list
48  for (const auto &name : robot_->getFrameNames())
49  {
50  const auto &data = robot_->getFrameDataConst(name);
51  if (data->movable)
52  ui_->ees->addItem(QString(name.c_str()));
53  }
54 
55  // Animation slider bookkeeping
56  ui_->pathSlider->setEnabled(false);
57 
58  anim_.setTargetObject(ui_->pathSlider);
59  anim_.setPropertyName("value");
60 
61  // Setup all signals
62  connect(ui_->plan, SIGNAL(clicked()), this, SLOT(plan()));
63  connect(ui_->pathSlider, SIGNAL(valueChanged(int)), this, SLOT(setState(int)));
64  connect(ui_->animateBox, SIGNAL(stateChanged(int)), this, SLOT(animate(int)));
65  connect(ui_->animTime, SIGNAL(valueChanged(double)), this, SLOT(animateTime()));
66  connect(ui_->planners, SIGNAL(currentTextChanged(const QString &)), this,
67  SLOT(plannerChanged(const QString &)));
68  connect(ui_->swept, SIGNAL(stateChanged(int)), this, SLOT(updateState()));
69  connect(ui_->sweptCount, SIGNAL(valueChanged(int)), this, SLOT(updateState()));
70  connect(ui_->draw, SIGNAL(toggled(bool)), this, SLOT(updateState()));
71  connect(ui_->constraints, SIGNAL(currentTextChanged(const QString &)), this,
72  SLOT(setConstraints(const QString &)));
73 
74  connect(ui_->ees, SIGNAL(currentTextChanged(const QString &)), this, SLOT(setEE(const QString &)));
75  connect(ui_->gorn, SIGNAL(toggled(bool)), this, SLOT(updateState()));
76  connect(ui_->gstate, SIGNAL(toggled(bool)), this, SLOT(updateState()));
77  connect(ui_->gedge, SIGNAL(toggled(bool)), this, SLOT(updateState()));
78  }
79 
80  ui_->ees->setCurrentIndex(ui_->ees->count() - 1);
81  setEE(ui_->ees->currentText());
82 
83  int index = ui_->planners->findText("rrt:RRTConnect", Qt::MatchExactly);
84  if (index >= 0)
85  ui_->planners->setCurrentIndex(index);
86 }
87 
89 {
90  delete ui_;
91 }
92 
94 {
95  emit stateChanged();
96 }
97 
98 void gui::PlanPanel::setEE(const QString &text)
99 {
100  {
102  ee_ = text.toStdString();
103  }
104 
105  updateState();
106 }
107 
108 void gui::PlanPanel::setConstraints(const QString &text)
109 {
110  {
112 
113  if (ui_->constraints->currentIndex() != 0)
114  {
115  const auto &constraint = text.toStdString();
116  planner_ = std::make_shared<plan::EZPlansConstraint>(robot_, constraints_[constraint],
118  }
119  else
120  planner_ = std::make_shared<plan::EZPlans>(robot_);
121 
122  planner_->initialize();
123  planner_->createPlanners();
124  }
125 
126  plannerChanged(ui_->planners->currentText());
127  updateState();
128 }
129 
130 void gui::PlanPanel::plannerChanged(const QString &text)
131 {
133 
134  while (ui_->parameters->count())
135  {
136  QLayoutItem *child = ui_->parameters->takeAt(0);
137  delete child->widget();
138  delete child;
139  }
140 
141  set_.clear();
142 
143  const auto &planner = text.toStdString();
144  planner_->setPlanner(planner);
145 
146  // HACK: PRM's parameters do not play nice with this interface
147  if (planner == "prm:PRM")
148  return;
149 
150  set_ = planner_->setup->getPlanner()->params();
151  for (const auto &entry : set_.getParams())
152  {
153  const auto &name = entry.first;
154  std::string formatted_name = name;
155  std::replace(formatted_name.begin(), formatted_name.end(), '_', ' ');
156  if (formatted_name.size() > 28)
157  {
158  formatted_name.resize(25);
159  formatted_name += "...";
160  }
161 
162  auto &param = entry.second;
163  const auto &range = param->getRangeSuggestion();
164 
165  // Check if range is for a boolean value
166  auto maybeBool = io::tokenize(range, ",");
167  if (maybeBool.size() == 2)
168  {
169  auto box = new QCheckBox();
170  connect(box, &QCheckBox::stateChanged, [&, name](int state) {
171  std::string value = (state == Qt::Unchecked) ? "0" : "1";
172  set_.setParam(name, value);
173  });
174 
175  box->setCheckState(boost::lexical_cast<bool>(param->getValue()) ? Qt::Checked : Qt::Unchecked);
176  ui_->parameters->addRow(QString(formatted_name.c_str()), box);
177  }
178  else
179  {
180  // Try to guess type based upon value or range
181  const auto &vt = param->getValue();
182  bool isDouble =
183  range.find_first_of(".") != std::string::npos || vt.find_first_of(".") != std::string::npos;
184 
185  // Tokenize range to extract
186  auto numbers = io::tokenize(range, ":");
187 
188  // If we guess a double type, create a double spin box
189  if (isDouble)
190  {
191  double min = 0, max = 1, step = 0.1;
192  if (numbers.size() == 3)
193  {
194  min = boost::lexical_cast<double>(numbers[0]);
195  step = boost::lexical_cast<double>(numbers[1]);
196  max = boost::lexical_cast<double>(numbers[2]);
197  }
198  else if (numbers.size() == 2)
199  {
200  min = boost::lexical_cast<double>(numbers[0]);
201  max = boost::lexical_cast<double>(numbers[1]);
202  }
203 
204  auto box = new QDoubleSpinBox();
205  box->setMaximum(max);
206  box->setMinimum(min);
207  box->setSingleStep(step);
208 
209  connect(box, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
210  [&, name](double value) {
211  try
212  {
213  set_.setParam(name, std::to_string(value));
214  }
215  catch (std::exception &e)
216  {
217  SE2EZ_ERROR(e.what());
218  }
219  });
220 
221  box->setValue(boost::lexical_cast<double>(param->getValue()));
222  ui_->parameters->addRow(QString(formatted_name.c_str()), box);
223  }
224  // If a range is specified but there is no `.`, we are integral
225  else if (not numbers.empty())
226  {
227  int min = 0, max = 100, step = 1;
228  if (numbers.size() == 3)
229  {
230  min = boost::lexical_cast<int>(numbers[0]);
231  step = boost::lexical_cast<int>(numbers[1]);
232  max = boost::lexical_cast<int>(numbers[2]);
233  }
234  else if (numbers.size() == 2)
235  {
236  min = boost::lexical_cast<int>(numbers[0]);
237  max = boost::lexical_cast<int>(numbers[1]);
238  }
239 
240  auto box = new QSpinBox();
241  box->setMaximum(max);
242  box->setMinimum(min);
243  box->setSingleStep(step);
244 
245  connect(box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
246  [&, name](int value) {
247  try
248  {
249  set_.setParam(name, std::to_string(value));
250  }
251  catch (std::exception &e)
252  {
253  SE2EZ_ERROR(e.what());
254  }
255  });
256 
257  box->setValue(boost::lexical_cast<int>(param->getValue()));
258  ui_->parameters->addRow(QString(formatted_name.c_str()), box);
259  }
260  // If nothing else, just add a text box
261  else
262  {
263  auto line = new QLineEdit(QString(param->getValue().c_str()));
264  ui_->parameters->addWidget(line);
265  connect(line, &QLineEdit::textChanged, [&, name](const QString &newValue) {
266  const auto value = newValue.toStdString();
267  set_.setParam(name, value);
268  });
269 
270  ui_->parameters->addRow(QString(formatted_name.c_str()), line);
271  }
272  }
273 
274  auto label =
275  ui_->parameters->itemAt(ui_->parameters->rowCount() - 1, QFormLayout::LabelRole)->widget();
276  auto widget =
277  ui_->parameters->itemAt(ui_->parameters->rowCount() - 1, QFormLayout::FieldRole)->widget();
278  label->setToolTip(QString(name.c_str()));
279  widget->setToolTip(QString(name.c_str()));
280  }
281 }
282 
283 void gui::PlanPanel::animate(int state)
284 {
285  if (state == Qt::Checked)
286  {
287  if (path_.size())
288  {
289  startAnimation();
290  anim_.start();
291  }
292  }
293  else
294  pauseAnimation();
295 }
296 
298 {
299  if (ui_->animateBox->isChecked())
300  {
301  pauseAnimation();
302  startAnimation();
303  anim_.start();
304  }
305 }
306 
308 {
309  anim_.stop();
310 }
311 
313 {
314  anim_.setDuration(ui_->animTime->value() * 1000);
315  anim_.setLoopCount(-1);
316 
317  anim_.setStartValue(ui_->pathSlider->minimum());
318  // anim_.setKeyValueAt(0.5, ui_->pathSlider->maximum());
319  anim_.setEndValue(ui_->pathSlider->maximum() + 1);
320 }
321 
323 {
324  pstate_ = path_[index];
325  updateState();
326 }
327 
329 {
331  path_ = path;
332 
333  if (path_.size())
334  {
335  double l = 0;
336  for (unsigned int i = 0; i < path_.size() - 1; ++i)
337  l += robot_->distance(path_[i], path_[i + 1]);
338  ui_->length->setText(QString(log::format("%1$0.3f", l).c_str()));
339  ui_->states->setText(QString(log::format("%1%", path_.size()).c_str()));
340 
341  ui_->pathSlider->setMaximum(path_.size() - 1);
342  ui_->pathSlider->setEnabled(true);
343 
344  setState(ui_->pathSlider->value());
345 
346  animateTime();
347  }
348 
349  emit newPlan();
350  updateState();
351 }
352 
354 {
355  return path_;
356 }
357 
358 ompl::base::PlannerDataPtr gui::PlanPanel::getPlannerData()
359 {
361 
362  if (ui_->constraints->currentIndex() == 0)
363  {
364  auto pd = std::make_shared<ompl::base::PlannerData>(planner_->info);
365  planner_->setup->getPlannerData(*pd);
366  pd->decoupleFromPlanner();
367 
368  return pd;
369  }
370 
371  return nullptr;
372 }
373 
375 {
376  auto state = std::make_shared<State>(robot_);
377  const std::string &name = s.toStdString();
378 
379  if (panelnames_.find(name) != panelnames_.end())
380  {
381  auto entry = panels->find(name);
382  auto jp = dynamic_cast<gui::JointPanel *>(entry->second);
383  jp->getState(state);
384  }
385 
386  if (snames_.find(name) != snames_.end())
387  robot_->getNamedState(name, state);
388 
389  return state;
390 }
391 
393 {
394  if (planning_)
395  {
396  planning_->join();
397  delete planning_;
398  }
399 
400  {
402  robot_->compileTree();
403  planner_->updateValidityChecker();
404 
405  ui_->setbox->setEnabled(false);
406  ui_->planbox->setEnabled(false);
407  ui_->scrollArea->setEnabled(false);
408  }
409 
410  planning_ = new std::thread([&]() {
412 
413  // Clear previous paths
414  if (ui_->clear->isChecked())
415  planner_->setup->clear();
416  else
417  {
418  const auto &cptr = std::static_pointer_cast<ompl::base::ProblemDefinition>(
419  planner_->setup->getProblemDefinition());
420  auto *pdef = const_cast<ompl::base::ProblemDefinition *>(cptr.get());
421 
422  pdef->clearGoal();
423  pdef->clearSolutionPaths();
424 
425  planner_->setup->getPlanner()->clearQuery();
426  }
427 
428  planner_->info->setStateValidityCheckingResolution(ui_->valid->value());
429  planner_->setStart(getState(ui_->startComboBox->currentText()));
430  planner_->setGoal(getState(ui_->goalComboBox->currentText()));
431 
432  planner_->setup->getPlanner()->params().include(set_);
433 
434  ompl::base::PlannerStatus solved = planner_->setup->solve(ui_->time->value());
435  const bool display =
436  ui_->approx->isChecked() ? solved : solved == ompl::base::PlannerStatus::EXACT_SOLUTION;
437 
438  if (display)
439  {
440  if (ui_->simplify->isChecked())
441  planner_->setup->simplifySolution();
442 
443  if (ui_->interpolate->isChecked())
444  {
445  auto &path = planner_->setup->getSolutionPath();
446  path.interpolate();
447  }
448 
449  ui_->tts->setText(
450  QString(log::format("%1$0.3f s", planner_->setup->getLastPlanComputationTime()).c_str()));
451  setPath(planner_->extractPath());
452  }
453  else
454  {
455  SE2EZ_WARN("No solution found");
456  setPath({});
457  }
458 
459  lock.unlock();
460 
461  {
463  pd_ = getPlannerData();
464 
465  if (pd_)
466  {
467  ui_->gstatel->setText(QString(log::format("%1%", pd_->numVertices()).c_str()));
468  ui_->gedgel->setText(QString(log::format("%1%", pd_->numEdges()).c_str()));
469  }
470  else
471  {
472  ui_->gstatel->setText("0");
473  ui_->gedgel->setText("0");
474  }
475  }
476 
477  ui_->setbox->setEnabled(true);
478  ui_->planbox->setEnabled(true);
479  ui_->scrollArea->setEnabled(true);
480 
481  updateState();
482  });
483 }
484 
485 void gui::PlanPanel::draw(QPainter &painter, RenderArea *canvas)
486 {
487  // Draw path
488  bool path = ui_->draw->isChecked();
489  if (path && path_.size())
490  {
492  bool swept = ui_->swept->isChecked();
493  unsigned int count = ui_->sweptCount->value();
494 
495  if (swept)
496  {
497  for (unsigned int i = 0; i < path_.size() - 1; i += count)
498  canvas->drawGeometry(painter, robot_, path_[i]);
499 
500  canvas->drawGeometry(painter, robot_, path_.back());
501  }
502 
503  else
504  {
505  pstate_->fk(robot_);
506  canvas->drawGeometry(painter, robot_, pstate_);
507  }
508  }
509 
510  bool edges = ui_->gedge->isChecked();
511  bool states = ui_->gstate->isChecked();
512  bool orn = ui_->gorn->isChecked();
513  if (pd_ && (edges || states || orn))
514  {
516 
517  painter.save();
518  painter.resetTransform();
519 
520  for (unsigned int i = 0; i < pd_->numVertices(); ++i)
521  {
522  const auto &vert = pd_->getVertex(i);
523  const auto &state = planner_->getStateConst(vert.getState());
524 
525  QColor color(0, 255, 164);
526  if (vert.getTag() == 2)
527  color = QColor(0, 164, 255);
528 
529  QPen pen(color);
530  painter.setPen(pen);
531 
532  state->fk(robot_);
533  auto iso = state->getPose(robot_, ee_);
534  auto pose = iso.translation();
535 
536  int x, y;
537  canvas->toScreen(pose[0], pose[1], x, y);
538 
539  if (states)
540  painter.fillRect(x - 3, y - 3, 6, 6, color);
541 
542  if (orn)
543  {
544  Eigen::Vector2d rot{0.15, 0};
545  rot = iso * rot;
546 
547  int xa, ya;
548  canvas->toScreen(rot[0], rot[1], xa, ya);
549 
550  painter.drawLine(x, y, xa, ya);
551  }
552 
553  if (edges)
554  {
556  unsigned int m = pd_->getEdges(i, edge);
557 
558  for (unsigned int j = 0; j < m; ++j)
559  {
560  const auto &next = planner_->getStateConst(pd_->getVertex(edge[j]).getState());
561 
562  next->fk(robot_);
563  auto npose = next->getPose(robot_, ee_).translation();
564 
565  int xa, ya;
566  canvas->toScreen(npose[0], npose[1], xa, ya);
567 
568  painter.drawLine(x, y, xa, ya);
569  }
570  }
571  }
572 
573  painter.restore();
574  }
575 
576  // Draw constraints
577  if (ui_->constraints->currentIndex() != 0)
578  {
579  const auto &text = ui_->constraints->currentText();
580  auto constraint = constraints_[text.toStdString()];
581  auto line = std::dynamic_pointer_cast<plan::LineConstraint>(constraint);
582 
583  painter.save();
584  painter.resetTransform();
585  QPen pen(QColor(255, 164, 0));
586  pen.setWidth(3);
587  painter.setPen(pen);
588 
589  if (line)
590  {
591  Eigen::Vector2d a, b;
592  line->getEndpoints(a, b, pstate_);
593 
594  int ax, ay, bx, by;
595  canvas->toScreen(a[0], a[1], ax, ay);
596  canvas->toScreen(b[0], b[1], bx, by);
597 
598  painter.drawLine(ax, ay, bx, by);
599  painter.drawText(bx + 3, by, text);
600  }
601 
602  auto point = std::dynamic_pointer_cast<plan::PointConstraint>(constraint);
603  if (point)
604  {
605  Eigen::Vector2d a;
606  point->getPoint(a, pstate_);
607 
608  int ax, ay;
609  canvas->toScreen(a[0], a[1], ax, ay);
610  painter.drawEllipse(ax, ay, 5, 5);
611  painter.drawText(ax + 7, ay, text);
612  }
613 
614  auto circle = std::dynamic_pointer_cast<plan::CircleConstraint>(constraint);
615  if (circle)
616  {
617  painter.save();
618 
619  double v;
620  Eigen::Vector2d p, r;
621  circle->getCircle(p, r, v, pstate_);
622 
623  int px, py;
624  canvas->toScreen(p[0], p[1], px, py);
625  int rx, ry, ox, oy;
626  canvas->toScreen(r[0], r[1], rx, ry);
627  canvas->toScreen(0, 0, ox, oy);
628 
629  rx -= ox;
630  ry -= oy;
631 
632  painter.translate(px, py);
633  painter.rotate(v);
634 
635  painter.drawEllipse(-rx, -ry, 2*rx, 2*ry);
636  painter.restore();
637 
638  painter.drawText(px + 7, py, text);
639  }
640 
641  painter.restore();
642  }
643 }
644 
645 void gui::PlanPanel::update(boost::posix_time::ptime /*last*/, boost::posix_time::ptime /*current*/)
646 {
647  bool update = false;
648 
649  // Storing the named states
650  for (const auto &name : robot_->getNamedStates())
651  {
652  auto result = snames_.find(name);
653  if (result == snames_.end())
654  {
656  update = true;
657  }
658  }
659  // Storing the states from joint panels
660  for (const auto &panel : *panels)
661  {
662  if (panelnames_.emplace(panel.first).second) // If new panel was added
663  {
664  auto jpanel = dynamic_cast<gui::JointPanel *>(panel.second); // check if it is jpanel
665  if (jpanel)
666  {
667  // If the joint panel controls the robot
668  if (jpanel->getSignature().compare(robot_->getSignature()) == 0)
669  {
670  jnames_.emplace(panel.first);
671  update = true;
672  }
673  }
674  }
675  }
676 
677  // update
678  if (update)
679  {
680  ui_->startComboBox->clear();
681  ui_->goalComboBox->clear();
682 
683  // Adding the named states
684  for (const auto &name : snames_)
685  {
686  ui_->startComboBox->addItem(QString(name.c_str()));
687  ui_->goalComboBox->addItem(QString(name.c_str()));
688  }
689 
690  int count = ui_->startComboBox->count();
691  ui_->startComboBox->insertSeparator(count);
692  ui_->goalComboBox->insertSeparator(count);
693 
694  // Adding the states from jointPanels
695  for (const auto &name : jnames_)
696  {
697  ui_->startComboBox->addItem(QString(name.c_str()));
698  ui_->goalComboBox->addItem(QString(name.c_str()));
699  }
700 
701  count = ui_->startComboBox->count();
702  if (count)
703  {
704  ui_->startComboBox->setCurrentIndex(count - 2);
705  ui_->goalComboBox->setCurrentIndex(count - 1);
706  }
707  }
708 }
std::vector< StatePtr > path_
Definition: planpanel.h:88
plan::EZPlansPtr planner_
Definition: planpanel.h:93
T unlock(T... args)
A shared pointer wrapper for se2ez::State.
std::string ee_
Definition: planpanel.h:90
~PlanPanel() override
Definition: planpanel.cpp:88
std::thread * planning_
Definition: planpanel.h:97
PlanPanel(RobotPtr robot, std::string name, std::map< std::string, ompl::base::ConstraintPtr > constraints={}, QWidget *parent=0)
Definition: planpanel.cpp:22
Definition: cspacepanel.h:22
T to_string(T... args)
std::set< std::string > jnames_
Definition: planpanel.h:103
T end(T... args)
void setEE(const QString &text)
Definition: planpanel.cpp:98
T resize(T... args)
std::set< std::string > panelnames_
Definition: planpanel.h:104
void drawGeometry(QPainter &painter, RobotPtr robot, StatePtr state, GeometryDrawerPtr drawer=nullptr)
Definition: renderarea.cpp:211
ompl::base::PlannerDataPtr pd_
Definition: planpanel.h:91
void getPoint(Eigen::Ref< Eigen::VectorXd > a, const StatePtr &state) const
Definition: constraint.cpp:475
Ui::PlanPanel * ui_
Definition: planpanel.h:82
QPropertyAnimation anim_
Definition: planpanel.h:84
void update(boost::posix_time::ptime last, boost::posix_time::ptime current) override
Definition: planpanel.cpp:645
std::mutex planmutex_
Definition: planpanel.h:100
T join(T... args)
T what(T... args)
T replace(T... args)
ompl::base::PlannerDataPtr getPlannerData()
Definition: planpanel.cpp:358
std::map< std::string, ompl::base::ConstraintPtr > constraints_
Definition: planpanel.h:106
ompl::base::ParamSet set_
Definition: planpanel.h:95
std::mutex pdmutex_
Definition: planpanel.h:99
#define SE2EZ_WARN(fmt,...)
Definition: log.h:41
std::mutex pathmutex_
Definition: planpanel.h:98
StatePtr getState(const QString &s)
Definition: planpanel.cpp:374
T static_pointer_cast(T... args)
void getState(StatePtr state)
Definition: jointpanel.cpp:101
void toScreen(double xin, double yin, int &xout, int &yout)
Definition: renderarea.cpp:431
std::vector< std::string > tokenize(const std::string &string, const std::string &separators)
Separates a string into tokens, based upon separators.
Definition: io.cpp:200
T find(T... args)
void setPath(const std::vector< StatePtr > path)
Definition: planpanel.cpp:328
T size(T... args)
QString name
Definition: panel.h:45
MainWindow::PanelMapPtr panels
Definition: panel.h:46
void draw(QPainter &painter, RenderArea *canvas) override
Definition: planpanel.cpp:485
T begin(T... args)
void plannerChanged(const QString &text)
Definition: planpanel.cpp:130
A shared pointer wrapper for se2ez::Robot.
T c_str(T... args)
std::string format(const std::string &fmt, Args &&... args)
Definition: log.h:25
void animate(int state)
Definition: planpanel.cpp:283
void setConstraints(const QString &text)
Definition: planpanel.cpp:108
T emplace(T... args)
The canvas widget. It contains all the drawing functions as well as all the general settings for draw...
Definition: renderarea.h:48
Main namespace.
Definition: collision.h:11
#define SE2EZ_ERROR(fmt,...)
Definition: log.h:39
const std::vector< StatePtr > & getPath() const
Definition: planpanel.cpp:353
void getCircle(Eigen::Ref< Eigen::VectorXd > p, Eigen::Ref< Eigen::VectorXd > r, double &v, const StatePtr &state) const
Definition: constraint.cpp:554
std::set< std::string > snames_
Definition: planpanel.h:102
void setState(int index)
Definition: planpanel.cpp:322