IceStateConverter.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Clara Scherer
18* @date 2014
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "IceStateConverter.h"
24
25#include <algorithm>
26#include <cassert>
27#include <cmath>
28#include <string>
29#include <utility>
30#include <vector>
31
32#include <QMap>
33#include <QString>
34
35#include <ArmarXCore/interface/statechart/RemoteStateIce.h>
36
37#include "model/State.h"
41
43{
44 topState.reset(new statechartmodel::LocalState(state, state->getStateName()));
45}
46
50
51void
52armarx::IceStateConverter::convert(armarx::StateIceBasePtr iceBase)
53{
54 convert(iceBase, topState);
55}
56
59{
60 return topState;
61}
62
63void
65{
66 this->watcher = watcher;
67}
68
69std::map<std::string, std::pair<armarx::statechartmodel::StateInstancePtr, armarx::StateIceBasePtr>>
71{
72 return completeStateMap;
73}
74
75void
76armarx::IceStateConverter::convert(armarx::StateIceBasePtr iceBase,
78{
79 if (watcher && modelState->getStateClass())
80 {
81 if (!watcher->subscribeToState(iceBase, modelState->getStateClass()))
82 {
83 ARMARX_WARNING_S << "subscribing failed";
84 }
85 }
86 // ARMARX_LOG_S << "Converting state " << modelState->getStateName();
87
88 if (stateEqual(iceBase, modelState))
89 {
90 updateState(iceBase, modelState);
91 }
92 else
93 {
94 ARMARX_INFO_S << "State " << iceBase->stateName << " could not be recognized - resetting";
95 resetState(iceBase, modelState);
96 }
97
98 StateList iceSubstates = iceBase->subStateList;
99 std::sort(
100 iceSubstates.begin(), iceSubstates.end(), &armarx::IceStateConverter::compareIceStates);
101
103 if (modelState->getStateClass())
104 {
105 modelSubstates = modelState->getStateClass()->getSubstates();
106 }
107
108 assert(iceSubstates.size() == static_cast<size_t>(modelSubstates.size()));
109
110 using modelSubstateIter = statechartmodel::StateInstanceMap::const_iterator;
111 StateList::const_iterator iceIter = iceSubstates.begin();
112 modelSubstateIter modelIter = modelSubstates.begin();
113
114 for (; iceIter != iceSubstates.end(); iceIter++, modelIter++)
115 {
116 convert(StateIceBasePtr::dynamicCast(*iceIter), modelIter.value());
117 }
118}
119
120bool
121armarx::IceStateConverter::stateEqual(armarx::StateIceBasePtr iceBase,
123{
124 if (!modelState)
125 {
126 return true;
127 }
128 // ARMARX_CHECK_EXPRESSION(modelState) << iceBase->stateName;
129 if (!modelState || iceBase->stateName.c_str() != modelState->getInstanceName())
130 {
131 if (!modelState->getStateClass() && iceBase->transitions.size() > 0)
132 {
133 return false;
134 }
135 if (modelState->getStateClass() && !sameTransitions(iceBase, modelState->getStateClass()))
136 {
137 return false;
138 }
139 }
140
141 return true;
142}
143
144bool
145armarx::IceStateConverter::sameTransitions(armarx::StateIceBasePtr iceBase,
147{
148 if (static_cast<size_t>(modelState->getTransitions().size()) != iceBase->transitions.size())
149 {
150 return false;
151 }
152
153 assert(static_cast<size_t>(modelState->getTransitions().size()) == iceBase->transitions.size());
154
155 std::pair<stringVector, stringVector> sortedTransitions =
156 sortTransitionNames(iceBase->transitions, modelState->getTransitions());
157 stringVector iceTransitions = sortedTransitions.first;
158 stringVector modelTransitions = sortedTransitions.second;
159
160 using stringIter = stringVector::const_iterator;
161 std::pair<stringIter, stringIter> mismatch;
162 mismatch = std::mismatch<stringIter, stringIter>(
163 iceTransitions.begin(), iceTransitions.end(), modelTransitions.begin());
164
165 if (mismatch.first == iceTransitions.end()) //all transitions have matched
166 {
167 return true;
168 }
169
170 return false;
171}
172
173void
174armarx::IceStateConverter::updateTransitions(armarx::StateIceBasePtr iceBase,
176{
177 if (modelState->getTransitions().empty())
178 {
179 resetTransitions(iceBase, modelState);
180 return;
181 }
182
183 TransitionTable iceTransitions = iceBase->transitions;
184 statechartmodel::CTransitionList modelTransitions = modelState->getTransitions();
185
186 //check for new transitions
187 foreach (TransitionIceBase newTrans, iceTransitions)
188 {
189 //transitions from all don't have a source state specified
190 if (!newTrans.sourceState)
191 {
192 updateTransitionFromAll(newTrans, modelState);
193 }
194 else
195 {
196 updateSingleTransition(newTrans, modelState);
197 }
198 }
199
200 //check for old transitions
201 foreach (auto oldTrans, modelTransitions)
202 {
203 bool found = false;
204
205 foreach (auto newTrans, iceTransitions)
206 {
207 if (newTrans.evt->eventName == oldTrans->eventName.toStdString())
208 {
209 found = true;
210 break;
211 }
212 }
213
214 if (!found)
215 {
216 //remove the transition from the model
217 modelState->removeTransition(modelState->findTransition(oldTrans));
218 }
219 }
220}
221
222void
223armarx::IceStateConverter::updateSubstates(armarx::StateIceBasePtr iceBase,
225{
226 using modelSubstateIter = statechartmodel::StateInstanceMap::const_iterator;
227
228 statechartmodel::StateInstanceMap modelSubstates = modelState->getSubstates();
229 if (modelSubstates.empty())
230 {
231 resetSubstates(iceBase, modelState);
232 return;
233 }
234
235 StateList iceSubstates = iceBase->subStateList;
236 std::sort(
237 iceSubstates.begin(), iceSubstates.end(), &armarx::IceStateConverter::compareIceStates);
238
239
240 StateList::const_iterator iceIter = iceSubstates.begin();
241 modelSubstateIter modelIter = modelSubstates.begin();
242
243 while ((iceIter != iceSubstates.end()) || (modelIter != modelSubstates.end()))
244 {
245 // ARMARX_CHECK_EXPRESSION(modelIter.value()->getStateClass()) << (*iceIter)->stateName;
246 //TODO:StateInstance name oder Statename für Identifikation benutzen?
247 //momentan wird Name des States benutzt
248 if ((iceIter != iceSubstates.end()) &&
249 ((modelIter == modelSubstates.end()) ||
250 ((*iceIter)->stateName.c_str() < modelIter.value()->getInstanceName())))
251 //a substate from ice is missing in the model
252 {
253 //insert new substate
255 newSubstate->setStateName((*iceIter)->stateName.c_str());
256 // newSubstate->setActive(false);
259 (*iceIter)->stateType, newSubstate, (*iceIter)->stateName.c_str(), modelState);
260 modelState->addSubstate(instance);
261 //name of stateInstance is initialized to be the same as the correspoding state's name
262
263 iceIter++;
264 continue;
265 }
266
267 if ((modelIter != modelSubstates.end()) &&
268 ((iceIter == iceSubstates.end()) ||
269 (*iceIter)->stateName.c_str() > modelIter.value()->getInstanceName()))
270 //a substate in the model is not found in ice anymore
271 {
272 //substate löschen
273 modelState->removeSubstate(modelIter.key());
274
275 modelIter++;
276 continue;
277 }
278
279 // if (watcher /*&& (*iceIter)->subStateList.size() > 0*/)
280 // {
281 // if (!watcher->subscribeToState(*iceIter, (*modelIter)->getStateClass()))
282 // {
283 // ARMARX_WARNING_S << "subscribing failed";
284 // }
285 // }
286
287 iceIter++;
288 modelIter++;
289 continue;
290 }
291}
292
294armarx::IceStateConverter::convertToModelParameterMap(armarx::StateParameterMap iceMap)
295{
297
298
299 for (StateParameterMap::const_iterator iter = iceMap.begin(); iter != iceMap.end(); iter++)
300 {
303
304 modelMap.insert((*iter).first.c_str(), param);
305 }
306
307 return modelMap;
308}
309
310std::pair<armarx::IceStateConverter::stringVector, armarx::IceStateConverter::stringVector>
311armarx::IceStateConverter::sortTransitionNames(
312 armarx::TransitionTable iceTransitions,
314{
315 stringVector eventsOfIceTransitions;
316
317 for (TransitionTable::const_iterator iceIter = iceTransitions.begin();
318 iceIter != iceTransitions.end();
319 iceIter++)
320 {
321 eventsOfIceTransitions.push_back((*iceIter).evt->eventName);
322 }
323
324 std::sort(eventsOfIceTransitions.begin(), eventsOfIceTransitions.end());
325
326 stringVector eventsOfModelTransitions;
327
328 for (statechartmodel::CTransitionList::const_iterator modelIter = modelTransitions.begin();
329 modelIter != modelTransitions.end();
330 modelIter++)
331 {
332 eventsOfModelTransitions.push_back((*modelIter)->eventName.toStdString());
333 }
334
335 std::sort(eventsOfModelTransitions.begin(), eventsOfModelTransitions.end());
336
337 return make_pair(eventsOfIceTransitions, eventsOfModelTransitions);
338}
339
340bool
341armarx::IceStateConverter::compareIceStates(armarx::AbstractStateIceBasePtr l,
342 armarx::AbstractStateIceBasePtr r)
343{
344 return l->stateName < r->stateName;
345}
346
348armarx::IceStateConverter::findSubstateByName(statechartmodel::StatePtr state, QString name)
349{
350 //search for stateinstance with this name among the substates of modelState
351 statechartmodel::StateInstanceMap::const_iterator substateIter =
352 state->getSubstates().find(name);
353
354 if (substateIter != state->getSubstates().end())
355 {
356 return *substateIter;
357 }
358
359 ARMARX_ERROR_S << "substate " << name << " provided by ice is not found among the substates of "
360 << state->getStateName().toStdString();
362}
363
364void
365armarx::IceStateConverter::updateStartState(armarx::StateIceBasePtr iceBase,
367{
368 //requires that names of substates are distinct for one state
369 if (iceBase->initState && modelState->getStartState() &&
370 (iceBase->initState->stateName.c_str() == modelState->getStartState()->getInstanceName()))
371 {
372 return;
373 //no need for change if both model- and ice-startState exist and have the same name.
374 }
375 else
376 {
377 resetStartState(iceBase, modelState);
378 }
379}
380
381void
382armarx::IceStateConverter::updateActiveSubstate(armarx::StateIceBasePtr iceBase,
384{
385 if (!modelState || !iceBase)
386 {
387 return;
388 }
389 if (iceBase->activeSubstate && modelState->getActiveSubstate() &&
390 (iceBase->activeSubstate->stateName.c_str() ==
391 modelState->getActiveSubstate()->getInstanceName()))
392 {
393 return;
394 //no need to change anything if both active substates exist and are the same
395 }
396 else
397 {
398 // ARMARX_INFO_S << "Resetting ActiveSubstate of" << iceBase->stateName;
399 resetActiveSubstate(iceBase, modelState);
400 }
401}
402
403void
404armarx::IceStateConverter::updateStateAttributes(
405 armarx::StateIceBasePtr iceBase,
407{
408 if (iceBase->stateName.c_str() != modelState->getInstanceName())
409 {
410 resetStateAttributes(iceBase, modelState);
411 }
412}
413
414void
415armarx::IceStateConverter::updateTransitionFromAll(armarx::TransitionIceBase newTrans,
417{
418 // ARMARX_INFO_S << newTrans.evt->eventName << " is a transition from all.";
419
420 statechartmodel::CTransitionList modelTransitions = modelState->getTransitions();
421
422 if (!newTrans.destinationState)
423 {
424 ARMARX_ERROR_S << "Transitions from all cannot be detached";
425 return;
426 }
428 findSubstateByName(modelState, newTrans.destinationState->stateName.c_str());
429
430 //iterate over all substates and test whether they have a fitting transition
431 foreach (statechartmodel::StateInstancePtr substate, modelState->getSubstates())
432 {
433 bool transFound = false;
434 foreach (statechartmodel::TransitionCPtr oldTrans, modelTransitions)
435 {
436 if ((newTrans.evt->eventName == oldTrans->eventName.toStdString()) &&
437 (substate == oldTrans->sourceState))
438 {
439 transFound = true;
440
441 //update destination state if necessary
442 if (!(oldTrans->destinationState) ||
443 (newTrans.destinationState->stateName !=
444 oldTrans->destinationState->getInstanceName().toStdString()))
445 {
446 modelState->updateTransitionDestination(oldTrans, destination);
447 }
448
449 break;
450 }
451 }
452
453 if (!transFound)
454 {
455 //create new model Transition to insert
457
458 transition->eventName = newTrans.evt->eventName.c_str();
459 transition->sourceState = substate;
460 transition->destinationState = destination;
461
462 modelState->addTransition(transition);
463 }
464 }
465}
466
467void
468armarx::IceStateConverter::updateSingleTransition(armarx::TransitionIceBase newTrans,
470{
471 statechartmodel::CTransitionList modelTransitions = modelState->getTransitions();
472
473 bool found = false;
474
475 foreach (statechartmodel::TransitionCPtr oldTrans, modelTransitions)
476 {
477 //it is assumed that a transition is uniquely identified by its source and event
478 if ((newTrans.evt->eventName == oldTrans->eventName.toStdString()))
479 {
480 found = true;
481
482 //update destination state if necessary
483 if (newTrans.destinationState)
484 {
485 if (!(oldTrans->destinationState) ||
486 (newTrans.destinationState->stateName !=
487 oldTrans->destinationState->getInstanceName().toStdString()))
488 {
489 modelState->updateTransitionDestination(
490 oldTrans,
491 findSubstateByName(modelState,
492 newTrans.destinationState->stateName.c_str()));
493 }
494 }
495 else
496 {
497 if (oldTrans->destinationState)
498 {
499 modelState->detachTransitionDestination(oldTrans);
500 }
501 }
502
503 break;
504 }
505 }
506
507 if (!found)
508 {
509 //create new model Transition to insert
511 transition->eventName = newTrans.evt->eventName.c_str();
512
513 transition->sourceState =
514 findSubstateByName(modelState, newTrans.sourceState->stateName.c_str());
515
516 if (newTrans
517 .destinationState) //transitions can be detached, i.e. not have a destination state
518 {
519 transition->destinationState =
520 findSubstateByName(modelState, newTrans.destinationState->stateName.c_str());
521 modelState->addTransition(transition);
522 }
523 else
524 {
525 modelState->addDetachedTransition(transition->eventName, transition->sourceState);
526 }
527 }
528}
529
530void
531armarx::IceStateConverter::resetTransitions(armarx::StateIceBasePtr iceBase,
533{
534 statechartmodel::TransitionList newTransitionList;
535 statechartmodel::TransitionList detachedTransitionList;
536
537 for (TransitionTable::const_iterator iceIter = iceBase->transitions.begin();
538 iceIter != iceBase->transitions.end();
539 iceIter++)
540 {
542 transition->eventName = (*iceIter).evt->eventName.c_str();
543
544 bool detached = false;
545
546 //transitions from all have no sourceState
547 if (!((*iceIter).sourceState))
548 {
549 if (!((*iceIter).destinationState))
550 {
551 ARMARX_ERROR_S << "Transition from all states: " << transition->eventName
552 << " doesn't have a destination state.";
553 continue;
554 }
556 findSubstateByName(modelState, (*iceIter).destinationState->stateName.c_str());
557
558 foreach (statechartmodel::StateInstancePtr substate, modelState->getSubstates())
559 {
561 newTransition->eventName = transition->eventName;
562 newTransition->sourceState = substate;
563 newTransition->destinationState = destination;
564
565 newTransitionList.push_back(newTransition);
566 }
567 }
568 else
569 {
570 transition->sourceState =
571 findSubstateByName(modelState, (*iceIter).sourceState->stateName.c_str());
572
573 if ((*iceIter).destinationState)
574 {
575 transition->destinationState =
576 findSubstateByName(modelState, (*iceIter).destinationState->stateName.c_str());
577 }
578 else
579 {
580 detached = true;
581 }
582
583 //TODO: also set parameter mapping
584 if (detached)
585 {
586 detachedTransitionList.push_back(transition);
587 }
588 else
589 {
590 newTransitionList.push_back(transition);
591 }
592 }
593 }
594
595 modelState->replaceTransitions(newTransitionList);
596
597 foreach (statechartmodel::TransitionPtr trans, detachedTransitionList)
598 {
599 modelState->addDetachedTransition(trans->eventName, trans->sourceState);
600 }
601}
602
603void
604armarx::IceStateConverter::resetSubstates(armarx::StateIceBasePtr iceBase,
606{
607 statechartmodel::StateInstanceMap newSubstateList;
608
609 for (StateList::const_iterator iceIter = iceBase->subStateList.begin();
610 iceIter != iceBase->subStateList.end();
611 iceIter++)
612 {
614 newSubstate->setStateName((*iceIter)->stateName.c_str());
615 // newSubstate->setActive(false);
616 QString proxyName;
617 armarx::RemoteStateIceBasePtr remoteState =
618 armarx::RemoteStateIceBasePtr::dynamicCast(*iceIter);
619 if (remoteState)
620 {
621 proxyName = QString::fromStdString(remoteState->proxyName);
622 }
625 newSubstate,
626 (*iceIter)->stateName.c_str(),
627 modelState,
628 proxyName);
629 // statechartmodel::StateInstancePtr instance(new statechartmodel::LocalState(newSubstate, (*iceIter)->stateName.c_str(), modelState));
630
631 instance->inputParameters = (*iceIter)->inputParameters;
632 newSubstateList.insert((*iceIter)->stateName.c_str(), instance);
633
634 if (watcher && StateIceBasePtr::dynamicCast(*iceIter)->subStateList.size() > 0)
635 {
636 if (!watcher->subscribeToState(StateIceBasePtr::dynamicCast(*iceIter), newSubstate))
637 {
638 ARMARX_INFO_S << "subscribing failed";
639 }
640 }
641 resetState(StateIceBasePtr::dynamicCast(*iceIter), instance);
642 //name of stateInstance is initialized to be the same as the correspoding state's name
643 }
644
645 modelState->replaceSubstates(newSubstateList);
646}
647
648void
649armarx::IceStateConverter::resetParameters(armarx::StateIceBasePtr iceBase,
651{
652 modelState->setInputParameters(convertToModelParameterMap(iceBase->inputParameters));
653 modelState->setLocalParameters(convertToModelParameterMap(iceBase->localParameters));
654 modelState->setOutputParameters(convertToModelParameterMap(iceBase->outputParameters));
655}
656
657void
658armarx::IceStateConverter::resetStartState(armarx::StateIceBasePtr iceBase,
660{
661 if (iceBase->initState) //test whether ice state has an active substate
662 {
663 modelState->setStartState(
664 findSubstateByName(modelState, iceBase->initState->stateName.c_str()));
665 }
666 else //modelState still has an active substate but iceBase doesn't
667 {
668 modelState->setStartState(statechartmodel::StateInstancePtr());
669 }
670}
671
672void
673armarx::IceStateConverter::resetActiveSubstate(armarx::StateIceBasePtr iceBase,
675{
676 if (iceBase->activeSubstate) //test whether ice state has an active substate
677 {
678
679 statechartmodel::StateInstancePtr activeSubstate =
680 findSubstateByName(modelState, iceBase->activeSubstate->stateName.c_str());
681 modelState->setActiveSubstate(activeSubstate);
682 }
683 else //modelState still has an active substate but iceBase doesn't
684 {
685 modelState->setActiveSubstate(statechartmodel::StateInstancePtr());
686 }
687}
688
689void
690armarx::IceStateConverter::resetStateAttributes(
691 armarx::StateIceBasePtr iceBase,
693{
694 modelState->setInstanceName(iceBase->stateName.c_str());
695 if (modelState->getStateClass())
696 {
697 modelState->getStateClass()->setStateName(iceBase->stateClassName.c_str());
698 }
699 int subStateCount =
700 modelState->getStateClass() ? modelState->getStateClass()->getSubstates().size() : 0;
701 float sizeFactor = pow(subStateCount, 0.7);
702 sizeFactor = std::max(sizeFactor, 1.0f);
703 modelState->setBoundingBox(sizeFactor * modelState->defaultBoundingSquareSize);
704}
705
706void
707armarx::IceStateConverter::resetState(armarx::StateIceBasePtr iceBase,
709{
710 completeStateMap[iceBase->globalStateIdentifier] = std::make_pair(modelState, iceBase);
711
712
713 if (modelState->getStateClass())
714 {
715 auto stateClass = modelState->getStateClass();
716 resetParameters(iceBase, stateClass);
717 resetSubstates(iceBase, stateClass);
718 resetTransitions(iceBase, stateClass);
719 resetActiveSubstate(iceBase, stateClass);
720 resetStartState(iceBase, stateClass);
721 }
722
723 resetStateAttributes(iceBase, modelState);
724}
725
726void
727armarx::IceStateConverter::updateState(armarx::StateIceBasePtr iceBase,
729{
730 updateStateAttributes(iceBase, modelState);
731
732
733 if (modelState->getStateClass())
734 {
735 auto stateClass = modelState->getStateClass();
736 updateSubstates(iceBase, stateClass);
737 if (!sameTransitions(iceBase, stateClass))
738 {
739 // ARMARX_INFO_S << "Updating transitions of" << iceBase->stateName;
740 updateTransitions(iceBase, stateClass);
741 }
742
743 resetParameters(iceBase, stateClass);
744 updateActiveSubstate(iceBase, stateClass);
745 updateStartState(iceBase, stateClass);
746 }
747}
748
749bool
750armarx::IceStateConverter::transitionEqual(armarx::TransitionIceBase iceTransition,
752{
753 if (iceTransition.evt->eventName.c_str() == modelTransition->eventName)
754 {
755 return false;
756 }
757
758 return true;
759}
statechartmodel::StateInstancePtr getTopState()
getTopState Returns the top state of the internal model that was converted from an ice model.
void convert(StateIceBasePtr iceBase)
Converts the given ice model into a statechartmodel.
void setStateWatcher(StateWatcherPtr watcher)
std::map< std::string, std::pair< statechartmodel::StateInstancePtr, StateIceBasePtr > > getCompleteStateMap() const
IceStateConverter(statechartmodel::StatePtr state=statechartmodel::StatePtr(new statechartmodel::State()))
IceStateConverter Creates a converter whose model's top state is state.
static StateInstancePtr CreateFromIceType(eStateType type, StatePtr stateClass, const QString &instanceName, StatePtr parentState=StatePtr(), const QString &proxyName="")
static statechartmodel::StateParameterPtr FromIceStateParameter(armarx::StateParameterIceBasePtr param)
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
std::shared_ptr< State > StatePtr
Definition State.h:48
QMap< QString, StateParameterPtr > StateParameterMap
std::shared_ptr< StateInstance > StateInstancePtr
std::shared_ptr< StateParameter > StateParameterPtr
QList< TransitionPtr > TransitionList
Definition State.h:50
std::shared_ptr< const Transition > TransitionCPtr
Definition Transition.h:91
QList< TransitionCPtr > CTransitionList
Definition State.h:51
std::shared_ptr< Transition > TransitionPtr
Definition Transition.h:90
QMap< QString, StateInstancePtr > StateInstanceMap
Definition State.h:52
armem::articulated_object::ArticulatedObject convert(const VirtualRobot::Robot &obj, const armem::Time &timestamp)
IceInternal::Handle< StateWatcher > StateWatcherPtr