diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-01-10 22:42:42 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-01-10 22:42:42 (GMT) |
commit | 7aa7095d17a180d663cd9647c31d99d97c1dca4f (patch) | |
tree | 460bc3a67f0adc3199bec9f22ee15a102263eb4c /src/uscxml/plugins/invoker | |
parent | da1032ffbff229ce2ca9a83d47522ff45c90ba23 (diff) | |
download | uscxml-7aa7095d17a180d663cd9647c31d99d97c1dca4f.zip uscxml-7aa7095d17a180d663cd9647c31d99d97c1dca4f.tar.gz uscxml-7aa7095d17a180d663cd9647c31d99d97c1dca4f.tar.bz2 |
Major changes - see details
- Dynamic SceneGraph ML
- V8 DOM for ecmascript datamodel
- New heartbeat invoker
- Fixed various bugs
Diffstat (limited to 'src/uscxml/plugins/invoker')
7 files changed, 286 insertions, 49 deletions
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp index 2712be3..7a0e63a 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp @@ -45,6 +45,13 @@ void OSGInvoker::sendToParent(SendRequest& req) { void OSGInvoker::invoke(InvokeRequest& req) { tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + // register default event handlers + Arabica::DOM::Events::EventTarget<std::string> evTarget = Arabica::DOM::Events::EventTarget<std::string>(req.dom); + evTarget.addEventListener("DOMSubtreeModified", *this, false); + evTarget.addEventListener("DOMNodeInserted", *this, false); + evTarget.addEventListener("DOMNodeRemoved", *this, false); + evTarget.addEventListener("DOMAttrModified", *this, false); + Arabica::XPath::NodeSet<std::string> content = Interpreter::filterChildElements("content", req.dom); std::set<std::string> validChilds; @@ -62,7 +69,19 @@ void OSGInvoker::runOnMainThread() { _mutex.unlock(); } } - + +void OSGInvoker::handleEvent(Arabica::DOM::Events::Event<std::string>& event) { +// std::cout << "Handling Event!" << std::endl; + Arabica::DOM::Node<std::string> node(event.getTarget()); + if (_nodes.find(node) != _nodes.end()) { + osg::Node* osgNode = _nodes[node]; + if (false) { + } else if (boost::iequals(LOCALNAME(node), "rotation")) { + updateRotation(osgNode, event); + } + } +} + void OSGInvoker::processDisplay(const Arabica::DOM::Node<std::string>& element) { // std::cout << element << std::endl; @@ -108,13 +127,17 @@ void OSGInvoker::processViewport(const Arabica::DOM::Node<std::string>& element) compDisp->addView(name, viewPort, sceneView); std::set<std::string> validChilds; + validChilds.insert("camera"); validChilds.insert("translation"); validChilds.insert("rotation"); validChilds.insert("scale"); validChilds.insert("node"); - processChildren(validChilds, element); + processChildren(validChilds, element); } +void OSGInvoker::processCamera(const Arabica::DOM::Node<std::string>& element) {} +void OSGInvoker::updateCamera(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event) {} + void OSGInvoker::processTranslation(const Arabica::DOM::Node<std::string>& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::Node* node = _nodes[element.getParentNode()]; @@ -146,7 +169,31 @@ void OSGInvoker::processTranslation(const Arabica::DOM::Node<std::string>& eleme void OSGInvoker::processRotation(const Arabica::DOM::Node<std::string>& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::Node* node = _nodes[element.getParentNode()]; - + + osg::Matrix rotation = rotationFromElement(element); + osg::MatrixTransform* transform = new osg::MatrixTransform(); + transform->setMatrix(rotation); + node->asGroup()->addChild(transform); + _nodes[element] = transform; + + std::set<std::string> validChilds; + validChilds.insert("translation"); + validChilds.insert("rotation"); + validChilds.insert("scale"); + validChilds.insert("node"); + processChildren(validChilds, element); +} + +void OSGInvoker::updateRotation(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event) { + osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node); + if (false) { + } else if (boost::iequals(event.getType(), "DOMAttrModified")) { + osg::Matrix rotation = rotationFromElement(Arabica::DOM::Node<std::string>(event.getTarget())); + transform->setMatrix(rotation); + } +} + +osg::Matrix OSGInvoker::rotationFromElement(const Arabica::DOM::Node<std::string>& element) { double pitch = 0, roll = 0, yaw = 0; if (HAS_ATTR(element, "pitch")) { NumAttr pitchAttr = NumAttr(ATTR(element, "pitch")); @@ -178,24 +225,13 @@ void OSGInvoker::processRotation(const Arabica::DOM::Node<std::string>& element) yaw = strTo<float>(yawAttr.value); } } - + osg::Matrix rotation; rotation.makeRotate(roll, osg::Vec3(0,1,0), // roll pitch, osg::Vec3(1,0,0) , // pitch yaw, osg::Vec3(0,0,1) ); // heading - - osg::MatrixTransform* transform = new osg::MatrixTransform(); - transform->setMatrix(rotation); - node->asGroup()->addChild(transform); - _nodes[element] = transform; - - std::set<std::string> validChilds; - validChilds.insert("translation"); - validChilds.insert("rotation"); - validChilds.insert("scale"); - validChilds.insert("node"); - processChildren(validChilds, element); + return rotation; } void OSGInvoker::processScale(const Arabica::DOM::Node<std::string>& element) { @@ -227,6 +263,9 @@ void OSGInvoker::processScale(const Arabica::DOM::Node<std::string>& element) { } void OSGInvoker::processNode(const Arabica::DOM::Node<std::string>& element) { + _nodes_t::iterator nodeIter = _nodes.find(element.getParentNode()); + assert(nodeIter != _nodes.end()); + assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::Node* parent = _nodes[element.getParentNode()]; @@ -276,6 +315,9 @@ void OSGInvoker::processChildren(const std::set<std::string>& validChildren, con } else if (boost::iequals(LOCALNAME(childs.item(i)), "viewport") && validChildren.find("viewport") != validChildren.end()) { processViewport(childs.item(i)); + } else if (boost::iequals(LOCALNAME(childs.item(i)), "camera") && + validChildren.find("camera") != validChildren.end()) { + processCamera(childs.item(i)); } else if (boost::iequals(LOCALNAME(childs.item(i)), "display") && validChildren.find("display") != validChildren.end()) { processDisplay(childs.item(i)); diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h index cf1556e..90dda31 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h @@ -2,6 +2,9 @@ #define OSGINVOKER_H_H6T4R8HU #include <uscxml/Interpreter.h> +#include <DOM/Events/MutationEvent.hpp> +#include <DOM/Events/EventListener.hpp> +#include <DOM/Events/Event.hpp> #include "CompositeDisplay.h" #include <osg/MatrixTransform> #include <osgDB/ReadFile> @@ -13,7 +16,7 @@ namespace uscxml { -class OSGInvoker : public Invoker { +class OSGInvoker : public Invoker, public Arabica::DOM::Events::EventListener<std::string> { public: OSGInvoker(); virtual ~OSGInvoker(); @@ -32,16 +35,30 @@ public: virtual void cancel(const std::string sendId); virtual void invoke(InvokeRequest& req); virtual void sendToParent(SendRequest& req); + virtual void handleEvent(Arabica::DOM::Events::Event<std::string>& event); virtual void runOnMainThread(); protected: void processDisplay(const Arabica::DOM::Node<std::string>& element); + void updateDisplay(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); void processViewport(const Arabica::DOM::Node<std::string>& element); + void updateViewport(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); + void processCamera(const Arabica::DOM::Node<std::string>& element); + void updateCamera(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); + void processTranslation(const Arabica::DOM::Node<std::string>& element); + void updateTranslation(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); + void processRotation(const Arabica::DOM::Node<std::string>& element); + void updateRotation(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); + static osg::Matrix rotationFromElement(const Arabica::DOM::Node<std::string>& element); + void processScale(const Arabica::DOM::Node<std::string>& element); + void updateScale(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); void processNode(const Arabica::DOM::Node<std::string>& element); + void updateNode(osg::Node* node, Arabica::DOM::Events::Event<std::string>& event); + void processChildren(const std::set<std::string>& validChildren, const Arabica::DOM::Node<std::string>& element); void getViewport(const Arabica::DOM::Node<std::string>& element, diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp new file mode 100644 index 0000000..6bc06d9 --- /dev/null +++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp @@ -0,0 +1,95 @@ +#include "HeartbeatInvoker.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new HeartbeatInvokerProvider() ); + return true; +} +#endif + +HeartbeatInvoker::HeartbeatInvoker() { +} + +HeartbeatInvoker::~HeartbeatInvoker() { +}; + +Invoker* HeartbeatInvoker::create(Interpreter* interpreter) { + HeartbeatInvoker* invoker = new HeartbeatInvoker(); + invoker->_interpreter = interpreter; + return invoker; +} + +Data HeartbeatInvoker::getDataModelVariables() { + Data data; + return data; +} + +void HeartbeatInvoker::send(SendRequest& req) { +} + +void HeartbeatInvoker::cancel(const std::string sendId) { + HeartbeatDispatcher::getInstance()->cancelEvent(toStr(this)); +} + +void HeartbeatInvoker::sendToParent(SendRequest& req) { +} + +void HeartbeatInvoker::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + _event.invokeid = _invokeId; + std::string intervalStr; + double interval = 0; + unsigned long intervalMs = 0; + InvokeRequest::params_t::iterator paramIter = req.params.begin(); + while(paramIter != req.params.end()) { + if (boost::iequals(paramIter->first, "interval")) { + intervalStr = paramIter->second; + NumAttr intervalAttr(paramIter->second); + interval = strTo<double>(intervalAttr.value); + if (false) { + } else if (boost::iequals(intervalAttr.unit, "s")) { + intervalMs = interval * 1000; + } else if (boost::iequals(intervalAttr.unit, "ms")) { + intervalMs = interval; + } else { + intervalMs = interval; + } + } + if (boost::iequals(paramIter->first, "eventname")) { + _event.name = paramIter->second; + } + paramIter++; + } + if (_event.name.length() == 0) + _event.name = std::string("heartbeat." + intervalStr); + + if (intervalMs > 0) { + HeartbeatDispatcher::getInstance()->addEvent(toStr(this), HeartbeatInvoker::dispatch, intervalMs, this, true); + } +} + +void HeartbeatInvoker::dispatch(void* instance, std::string name) { + HeartbeatInvoker* invoker = (HeartbeatInvoker*)instance; + invoker->_interpreter->receive(invoker->_event); +} + +HeartbeatDispatcher* HeartbeatDispatcher::_instance = NULL; +HeartbeatDispatcher* HeartbeatDispatcher::getInstance() { + if (_instance == NULL) { + _instance = new HeartbeatDispatcher(); + _instance->start(); + } + return _instance; +} + +HeartbeatDispatcher::HeartbeatDispatcher() {} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h new file mode 100644 index 0000000..9a6cb47 --- /dev/null +++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h @@ -0,0 +1,54 @@ +#ifndef HEARTBEATINVOKER_H_W09J90F0 +#define HEARTBEATINVOKER_H_W09J90F0 + +#include <uscxml/Interpreter.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class HeartbeatInvoker : public Invoker { +public: + HeartbeatInvoker(); + virtual ~HeartbeatInvoker(); + virtual Invoker* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("heartbeat"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#heartbaet"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); + + static void dispatch(void* instance, std::string name); + +protected: + std::string _invokeId; + Event _event; + +}; + +class HeartbeatDispatcher : public DelayedEventQueue { +public: + static HeartbeatDispatcher* getInstance(); +protected: + static HeartbeatDispatcher* _instance; + HeartbeatDispatcher(); +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(HeartbeatInvoker, Invoker); +#endif + +} + + +#endif /* end of include guard: HEARTBEATINVOKER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp index b5c351c..f115c25 100644 --- a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp +++ b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp @@ -42,6 +42,7 @@ void SampleInvoker::sendToParent(SendRequest& req) { } void SampleInvoker::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index ee6c903..9957bfa 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -1,5 +1,6 @@ #include "UmundoInvoker.h" #include <glog/logging.h> +#include "uscxml/URL.h" #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> @@ -15,12 +16,16 @@ bool connect(pluma::Host& host) { } #endif -UmundoInvoker::UmundoInvoker() { +UmundoInvoker::UmundoInvoker() : _node(NULL), _pub(NULL), _sub(NULL) { } UmundoInvoker::~UmundoInvoker() { - _node.removeSubscriber(_sub); - _node.removePublisher(_pub); + if (_node) { + if (_sub) + _node->removeSubscriber(*_sub); + if (_pub) + _node->removePublisher(*_pub); + } }; Invoker* UmundoInvoker::create(Interpreter* interpreter) { @@ -63,8 +68,8 @@ void UmundoInvoker::send(SendRequest& req) { } else { // add all s11n properties if (!_isService) { - _pub.prepareMsg(msg, type, pbMsg); - _pub.send(msg); + _pub->prepareMsg(msg, type, pbMsg); + _pub->send(msg); } else { std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin(); while(svcIter != _svcs.end()) { @@ -107,11 +112,12 @@ void UmundoInvoker::sendToParent(SendRequest& req) { void UmundoInvoker::invoke(InvokeRequest& req) { _invokeId = req.invokeid; + std::string domain; std::string channelName; std::string serviceName; if (req.params.find("channel") != req.params.end()) { - channelName = req.params.find("type")->second; + channelName = req.params.find("channel")->second; _isService = false; } else if (req.params.find("service") != req.params.end()) { serviceName = req.params.find("service")->second; @@ -120,34 +126,50 @@ void UmundoInvoker::invoke(InvokeRequest& req) { LOG(ERROR) << "Invoking umundo needs a service or a channel param"; return; } + if (req.params.find("domain") != req.params.end()) { + domain = req.params.find("domain")->second; + } + _node = getNode(_interpreter, domain); - _node = getNode(_interpreter); - - // add types from .proto or .desc files - if (req.params.find("types") != req.params.end()) { + // add type from .proto or .desc files + if (req.params.find("type") != req.params.end()) { std::pair<InvokeRequest::params_t::iterator, InvokeRequest::params_t::iterator> typeRange = req.params.equal_range("types"); for (InvokeRequest::params_t::iterator it = typeRange.first; it != typeRange.second; it++) { - Arabica::io::URI srcURI(it->first); - // if (!_interpreter->makeAbsolute(srcURI)) { - // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter"; - // return; - // } - umundo::PBSerializer::addProto(srcURI.path()); + URL typeURI(it->second); + if (typeURI.toAbsolute(_interpreter->getBaseURI())) { + std::string filename = typeURI.asLocalFile(".proto"); + umundo::PBSerializer::addProto(filename); + } else { + LOG(ERROR) << "umundo invoker has relative type src but nor baseURI set with interpreter."; + } } } + // add directory with .proto or .desc files + if (req.params.find("types") != req.params.end()) { + std::pair<InvokeRequest::params_t::iterator, InvokeRequest::params_t::iterator> typeRange = req.params.equal_range("types"); + for (InvokeRequest::params_t::iterator it = typeRange.first; it != typeRange.second; it++) { + URL typeURI(it->second); + if (typeURI.toAbsolute(_interpreter->getBaseURI()) && typeURI.scheme().compare("file") == 0) { + umundo::PBSerializer::addProto(typeURI.path()); + } else { + LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; + } + } + } + if (!_isService) { // use umundo to publish objects on a channel - _pub = umundo::TypedPublisher(channelName); - _sub = umundo::TypedSubscriber(channelName, this); + _pub = new umundo::TypedPublisher(channelName); + _sub = new umundo::TypedSubscriber(channelName, this); - _node.addPublisher(_pub); - _node.addSubscriber(_sub); + _node->addPublisher(*_pub); + _node->addSubscriber(*_sub); } else if (serviceName.length() > 0) { // use umundo to access services _svcFilter = umundo::ServiceFilter(serviceName); - _node.connect(&_svcMgr); + _node->connect(&_svcMgr); _svcMgr.startQuery(_svcFilter, this); } } @@ -233,12 +255,17 @@ void UmundoInvoker::removed(umundo::ServiceDescription desc) { void UmundoInvoker::changed(umundo::ServiceDescription desc) { } -std::map<std::string, umundo::Node> UmundoInvoker::_nodes; -umundo::Node UmundoInvoker::getNode(Interpreter* interpreter) { - if ((_nodes.find(interpreter->getName()) == _nodes.end())) { - _nodes[interpreter->getName()] = umundo::Node(); - } - return _nodes[interpreter->getName()]; +std::multimap<std::string, std::pair<std::string, umundo::Node*> > UmundoInvoker::_nodes; +umundo::Node* UmundoInvoker::getNode(Interpreter* interpreter, const std::string& domain) { + std::pair<_nodes_t::iterator, _nodes_t::iterator> range = _nodes.equal_range(interpreter->getName()); + for (_nodes_t::iterator it = range.first; it != range.second; it++) { + if (it->second.first.compare(domain) == 0) + return it->second.second; + } + umundo::Node* node = new umundo::Node(domain); + std::pair<std::string, std::pair<std::string, umundo::Node*> > pair = std::make_pair(interpreter->getName(), std::make_pair(domain, node)); + _nodes.insert(pair); + return node; } bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& msg) { diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h index 72fcc9b..09d07bf 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h @@ -49,16 +49,17 @@ protected: bool dataToProtobuf(google::protobuf::Message* msg, Data& data); bool protobufToData(Data& data, const google::protobuf::Message& msg); - umundo::TypedPublisher _pub; - umundo::TypedSubscriber _sub; - umundo::Node _node; + umundo::Node* _node; + umundo::TypedPublisher* _pub; + umundo::TypedSubscriber* _sub; umundo::ServiceFilter _svcFilter; umundo::ServiceManager _svcMgr; std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs; - static std::map<std::string, umundo::Node> _nodes; - static umundo::Node getNode(Interpreter* interpreter); + static std::multimap<std::string, std::pair<std::string, umundo::Node*> > _nodes; + typedef std::multimap<std::string, std::pair<std::string, umundo::Node*> > _nodes_t; + static umundo::Node* getNode(Interpreter* interpreter, const std::string& domain); }; #ifdef BUILD_AS_PLUGINS |