diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-02-25 12:28:05 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-02-25 12:28:05 (GMT) |
commit | 49c3c43d18c9cce6de305aae77cc8bd839506129 (patch) | |
tree | cfc4ea84416c76e8bbe3e27d2918321115b61e24 /src/uscxml/plugins | |
parent | 47956a35d11495f2ebf6988c7f9d9dffe0bd3a4b (diff) | |
download | uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.zip uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.gz uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.bz2 |
Introduced postpone element and reorganized http request representation as events
Diffstat (limited to 'src/uscxml/plugins')
13 files changed, 657 insertions, 35 deletions
diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.cpp b/src/uscxml/plugins/element/postpone/PostponeElement.cpp new file mode 100644 index 0000000..644cb1d --- /dev/null +++ b/src/uscxml/plugins/element/postpone/PostponeElement.cpp @@ -0,0 +1,97 @@ +#include "PostponeElement.h" +#include "uscxml/plugins/invoker/http/HTTPServletInvoker.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 PostponeElementProvider() ); + return true; +} +#endif + +boost::shared_ptr<ExecutableContentImpl> PostponeElement::create(Interpreter* interpreter) { + boost::shared_ptr<PostponeElement> invoker = boost::shared_ptr<PostponeElement>(new PostponeElement()); + invoker->_interpreter = interpreter; + return invoker; +} + +void PostponeElement::enterElement(const Arabica::DOM::Node<std::string>& node) { + if (!_interpreter->getDataModel()) { + LOG(ERROR) << "Postpone element requires a datamodel"; + return; + } + + // under which condition will we postpone the current event? + if (HAS_ATTR(node, "cond")) { + std::string cond = ATTR(node, "cond"); + try { + if (!_interpreter->getDataModel().evalAsBool(cond)) + return; + } catch (Event e) { + LOG(ERROR) << "Syntax error in cond attribute of postpone element:" << std::endl << e << std::endl; + return; + } + } + + // when will we refire the event? + if (!HAS_ATTR(node, "until")) { + LOG(ERROR) << "Postpone element requires until attribute "; + return; + } + std::string until = ATTR(node, "until"); + + Event currEvent = _interpreter->getCurrentEvent(); + Resubmitter::postpone(currEvent, until, _interpreter); +} + +void PostponeElement::exitElement(const Arabica::DOM::Node<std::string>& node) { +} + +void PostponeElement::Resubmitter::postpone(const Event& event, std::string until, Interpreter* interpreter) { + Resubmitter* resubmitter = getInstance(interpreter); + resubmitter->_postponedEvents.push_back(std::make_pair(until, event)); +} + +void PostponeElement::Resubmitter::onStableConfiguration(Interpreter* interpreter) { + std::list<std::pair<std::string, Event> >::iterator eventIter = _postponedEvents.begin(); + while(eventIter != _postponedEvents.end()) { + try { + if (interpreter->getDataModel().evalAsBool(eventIter->first)) { + interpreter->receive(eventIter->second, true); + _postponedEvents.erase(eventIter); + break; + } + } catch (Event e) { + LOG(ERROR) << "Syntax error in until attribute of postpone element:" << std::endl << e << std::endl; + _postponedEvents.erase(eventIter++); + continue; + } + eventIter++; + } +} + +void PostponeElement::Resubmitter::afterCompletion(Interpreter* interpreter) { + tthread::lock_guard<tthread::recursive_mutex> lock(PostponeElement::Resubmitter::_accessLock); + _instances.erase(interpreter); + delete this; // committing suicide is ok if we are careful +} + +std::map<Interpreter*, PostponeElement::Resubmitter*> PostponeElement::Resubmitter::_instances; +tthread::recursive_mutex PostponeElement::Resubmitter::_accessLock; + +PostponeElement::Resubmitter* PostponeElement::Resubmitter::getInstance(Interpreter* interpreter) { + tthread::lock_guard<tthread::recursive_mutex> lock(PostponeElement::Resubmitter::_accessLock); + if (_instances.find(interpreter) == _instances.end()) { + _instances[interpreter] = new Resubmitter(interpreter); + } + return _instances[interpreter]; +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.h b/src/uscxml/plugins/element/postpone/PostponeElement.h new file mode 100644 index 0000000..03aafde --- /dev/null +++ b/src/uscxml/plugins/element/postpone/PostponeElement.h @@ -0,0 +1,62 @@ +#ifndef POSTPONEELEMENT_H_WN8EIYYI +#define POSTPONEELEMENT_H_WN8EIYYI + +#include <uscxml/Interpreter.h> +#include <list> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class PostponeElement : public ExecutableContentImpl { +public: + PostponeElement() {} + virtual ~PostponeElement() {} + boost::shared_ptr<ExecutableContentImpl> create(Interpreter* interpreter); + + std::string getLocalName() { + return "postpone"; + } + + std::string getNamespace() { + return "http://www.w3.org/2005/07/scxml"; + } + + bool processChildren() { + return false; + } + + void enterElement(const Arabica::DOM::Node<std::string>& node); + void exitElement(const Arabica::DOM::Node<std::string>& node); + +protected: + // once per interpreter + class Resubmitter : public InterpreterMonitor { + public: + Resubmitter(Interpreter* interpreter) { + interpreter->addMonitor(this); + } + + static Resubmitter* getInstance(Interpreter* interpreter); + static void postpone(const Event& event, std::string until, Interpreter* interpreter); + + // InterpreterMonitor + void onStableConfiguration(Interpreter* interpreter); + void afterCompletion(Interpreter* interpreter); + + std::list<std::pair<std::string, Event> > _postponedEvents; + static std::map<Interpreter*, Resubmitter*> _instances; + static tthread::recursive_mutex _accessLock; + + }; +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(PostponeElement, Element); +#endif + +} + +#endif /* end of include guard: POSTPONEELEMENT_H_WN8EIYYI */ diff --git a/src/uscxml/plugins/element/response/ResponseElement.cpp b/src/uscxml/plugins/element/response/ResponseElement.cpp index 814f726..7f1a479 100644 --- a/src/uscxml/plugins/element/response/ResponseElement.cpp +++ b/src/uscxml/plugins/element/response/ResponseElement.cpp @@ -23,6 +23,7 @@ boost::shared_ptr<ExecutableContentImpl> ResponseElement::create(Interpreter* in } void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node) { + // try to get the request id if (!HAS_ATTR(node, "request") && !HAS_ATTR(node, "requestexpr")) { LOG(ERROR) << "Response element requires request or requestexpr"; return; @@ -31,12 +32,9 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node) LOG(ERROR) << "Response element with requestexpr requires datamodel"; return; } - if (HAS_ATTR(node, "close")) { - - } - std::string requestId = (HAS_ATTR(node, "request") ? ATTR(node, "request") : _interpreter->getDataModel().evalAsString(ATTR(node, "requestexpr"))); + // try to get the request object HTTPServletInvoker* servlet = _interpreter->getHTTPServlet(); tthread::lock_guard<tthread::recursive_mutex> lock(servlet->getMutex()); @@ -44,19 +42,39 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node) LOG(ERROR) << "No matching HTTP request for response element"; return; } + HTTPServer::Request httpReq = servlet->getRequests()[requestId]; + HTTPServer::Reply httpReply(httpReq); + // get the status or default to 200 std::string statusStr = (HAS_ATTR(node, "status") ? ATTR(node, "status") : "200"); if (!isNumeric(statusStr.c_str(), 10)) { LOG(ERROR) << "Response element with non-numeric status " << statusStr; return; } - int status = strTo<int>(statusStr); - - HTTPServer::Request httpReq = servlet->getRequests()[requestId]; - - HTTPServer::Reply httpReply(httpReq); - httpReply.status = status; + httpReply.status = strTo<int>(statusStr);; + + // extract the content + Arabica::XPath::NodeSet<std::string> contents = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node); + if (contents.size() > 0) { + if (HAS_ATTR(contents[0], "expr")) { + if (_interpreter->getDataModel()) { + try { + std::string contentValue = _interpreter->getDataModel().evalAsString(ATTR(contents[0], "expr")); + httpReply.content = contentValue; + } catch (Event e) { + LOG(ERROR) << "Syntax error with expr in content child of response element:" << std::endl << e << std::endl; + } + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; + } + } else if (contents[0].hasChildNodes()) { + httpReply.content = contents[0].getFirstChild().getNodeValue(); + } else { + LOG(ERROR) << "content element does not specify any content."; + } + } + // send the reply HTTPServer::reply(httpReply); servlet->getRequests().erase(requestId); } diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp new file mode 100644 index 0000000..05af363 --- /dev/null +++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp @@ -0,0 +1,48 @@ +#include "FFMPEGInvoker.h" +#include <glog/logging.h> + +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.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 FFMPEGInvokerProvider() ); + return true; +} +#endif + +FFMPEGInvoker::FFMPEGInvoker() { +} + +FFMPEGInvoker::~FFMPEGInvoker() { +}; + +boost::shared_ptr<IOProcessorImpl> FFMPEGInvoker::create(Interpreter* interpreter) { + boost::shared_ptr<FFMPEGInvoker> invoker = boost::shared_ptr<FFMPEGInvoker>(new FFMPEGInvoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data FFMPEGInvoker::getDataModelVariables() { + Data data; + return data; +} + +void FFMPEGInvoker::send(const SendRequest& req) { +} + +void FFMPEGInvoker::cancel(const std::string sendId) { +} + +void FFMPEGInvoker::invoke(const InvokeRequest& req) { +// AVIOContext* avCtx = avio_alloc_context(); +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h new file mode 100644 index 0000000..9b1b0ca --- /dev/null +++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h @@ -0,0 +1,40 @@ +#ifndef FFMPEGINVOKER_H_VQD1V1C2 +#define FFMPEGINVOKER_H_VQD1V1C2 + +#include <uscxml/Interpreter.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class FFMPEGInvoker : public InvokerImpl { +public: + FFMPEGInvoker(); + virtual ~FFMPEGInvoker(); + virtual boost::shared_ptr<IOProcessorImpl> create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("ffmpeg"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#ffmpeg"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(FFMPEGInvoker, Invoker); +#endif + +} + + +#endif /* end of include guard: FFMPEGINVOKER_H_VQD1V1C2 */ diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp index 9486de3..e34517d 100644 --- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp +++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp @@ -1,6 +1,8 @@ #include "DirMonInvoker.h" #include <glog/logging.h> +#include "uscxml/config.h" + #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> #endif @@ -111,13 +113,38 @@ void DirMonInvoker::handleFileAction(FW::WatchID watchid, const FW::String& dir, case FW::Actions::Modified: event.name = "file.modified"; break; - default: break; } - event.data.compound["file"].compound["name"] = Data(filename, Data::VERBATIM); - event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM); + std::string basename; + size_t lastSep; + if ((lastSep = filename.find_last_of(PATH_SEPERATOR)) != std::string::npos) { + lastSep++; + basename = filename.substr(lastSep, filename.length() - lastSep); + } else { + basename = filename; + } + + std::string extension; + size_t lastDot; + if ((lastDot = basename.find_last_of(".")) != std::string::npos) { + lastDot++; + extension = basename.substr(lastDot, basename.length() - lastDot); + } + + std::string relPath; + if (boost::algorithm::starts_with(filename, dir)) { + relPath = filename.substr(dir.length()); + } else { + relPath = filename; + } + + event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM); + event.data.compound["file"].compound["path"] = Data(filename, Data::VERBATIM); + event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM); + event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM); + event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM); event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime); event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime); diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp index 49c9ccb..726cd08 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp @@ -1,5 +1,12 @@ #include "OSGConverter.h" #include <glog/logging.h> +#include "uscxml/config.h" + +#include <osg/MatrixTransform> +#include <osgDB/ReadFile> +#include <osgDB/WriteFile> +#include <osgDB/Registry> +#include <osgGA/TrackballManipulator> #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> @@ -15,10 +22,15 @@ bool connect(pluma::Host& host) { } #endif -OSGConverter::OSGConverter() { +OSGConverter::OSGConverter() : _isRunning(false) { } OSGConverter::~OSGConverter() { + _isRunning = false; + std::set<tthread::thread*>::iterator threadIter = _threads.begin(); + while(threadIter != _threads.end()) { + (*threadIter)->join(); + } }; boost::shared_ptr<IOProcessorImpl> OSGConverter::create(Interpreter* interpreter) { @@ -33,16 +45,294 @@ Data OSGConverter::getDataModelVariables() { } void OSGConverter::send(const SendRequest& req) { - std::cout << req << std::endl; - Event event; - event.name = "error"; - returnEvent(event); + + /** + * we have to resolve all datamodel dependent strings first as + * we cannot access the datamodel from within another thread without locking + */ + + // make a copy + SendRequest actualReq(req); + + if (actualReq.params.find("source") == actualReq.params.end()) { + // no explicit source + if (actualReq.params.find("sourceexpr") != actualReq.params.end() && _interpreter->getDataModel()) { + actualReq.params.insert(std::make_pair("source", _interpreter->getDataModel().evalAsString(actualReq.params.find("sourceexpr")->second))); + } else { + LOG(ERROR) << "SendRequests for osginvoker missing source or sourceExpr and datamodel"; + return; + } + } + + if (actualReq.params.find("dest") == actualReq.params.end()) { + // no explicit destination + if (actualReq.params.find("destexpr") != actualReq.params.end() && _interpreter->getDataModel()) { + actualReq.params.insert(std::make_pair("dest", _interpreter->getDataModel().evalAsString(actualReq.params.find("destexpr")->second))); + } else { + LOG(ERROR) << "SendRequests for osginvoker missing dest or destExpr and datamodel"; + return; + } + } + + if (actualReq.params.find("format") == actualReq.params.end()) { + // no explicit format + if (actualReq.params.find("formatexpr") != actualReq.params.end() && _interpreter->getDataModel()) { + actualReq.params.insert(std::make_pair("format", _interpreter->getDataModel().evalAsString(actualReq.params.find("formatexpr")->second))); + } else { + std::string format; + size_t lastDot; + std::string dest = req.params.find("dest")->second; + if ((lastDot = dest.find_last_of(".")) != std::string::npos) { + lastDot++; + format = dest.substr(lastDot, dest.length() - lastDot); + } + if (format.length() == 0 || format.find_last_of(PATH_SEPERATOR) != std::string::npos) { + // empty format or pathseperator in format + format = "png"; + } + actualReq.params.insert(std::make_pair("format", format)); + } + } + + if (actualReq.params.find("height") == actualReq.params.end()) { + // no explicit height + if (actualReq.params.find("heightexpr") != actualReq.params.end() && _interpreter->getDataModel()) { + actualReq.params.insert(std::make_pair("height", _interpreter->getDataModel().evalAsString(actualReq.params.find("heightexpr")->second))); + } + } + + if (actualReq.params.find("width") == actualReq.params.end()) { + // no explicit width + if (actualReq.params.find("widthexpr") != actualReq.params.end() && _interpreter->getDataModel()) { + actualReq.params.insert(std::make_pair("width", _interpreter->getDataModel().evalAsString(actualReq.params.find("widthexpr")->second))); + } + } + + _workQueue.push(actualReq); } void OSGConverter::cancel(const std::string sendId) { } void OSGConverter::invoke(const InvokeRequest& req) { + int nrThreads = 1; + if (req.params.find("threads") != req.params.end() && isNumeric(req.params.find("threads")->second.c_str(), 10)) { + nrThreads = strTo<int>(req.params.find("threads")->second); + } + + _isRunning = true; + for (int i = 0; i < nrThreads; i++) { + _threads.insert(new tthread::thread(OSGConverter::run, this)); + } +} + +void OSGConverter::run(void* instance) { + OSGConverter* INSTANCE = (OSGConverter*)instance; + while(true) { + SendRequest req = INSTANCE->_workQueue.pop(); + if (INSTANCE->_isRunning) { + INSTANCE->process(req); + } else { + return; + } + } +} + +void OSGConverter::process(const SendRequest& req) { + + int width = (req.params.find("width") != req.params.end() ? strTo<int>(req.params.find("width")->second) : 640); + int height = (req.params.find("height") != req.params.end() ? strTo<int>(req.params.find("height")->second) : 480); + + assert(req.params.find("source") != req.params.end()); + assert(req.params.find("dest") != req.params.end()); + assert(req.params.find("format") != req.params.end()); + + std::string source = req.params.find("source")->second; + std::string dest = req.params.find("dest")->second; + std::string format = req.params.find("format")->second; + + osg::ref_ptr<osg::Node> sceneGraph = setupGraph(source); + + osgDB::ReaderWriter::WriteResult result; + if (osgDB::Registry::instance()->getReaderWriterForExtension(format) != NULL) { + // write as another 3D file + result = osgDB::Registry::instance()->writeNode(*sceneGraph, dest, osgDB::Registry::instance()->getOptions()); + } + + if (result.error()) { + // make a screenshot + osgViewer::ScreenCaptureHandler::CaptureOperation* cOp = new NameRespectingWriteToFile(dest, + format, + osgViewer::ScreenCaptureHandler::WriteToFile::OVERWRITE + ); + + osgViewer::ScreenCaptureHandler* captureHandler = new osgViewer::ScreenCaptureHandler(cOp, -1); + + osgViewer::Viewer viewer; + viewer.setSceneData(sceneGraph); + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); + viewer.addEventHandler(captureHandler); + captureHandler->startCapture(); + + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds); + traits->width = width; + traits->height = height; + traits->pbuffer = true; + osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + GLenum pbuffer = gc->getTraits()->doubleBuffer ? GL_BACK : GL_FRONT; + + viewer.getCamera()->setGraphicsContext(gc.get()); + viewer.getCamera()->setViewport(new osg::Viewport(0,0,traits->width,traits->height)); + viewer.getCamera()->setDrawBuffer(pbuffer); + viewer.getCamera()->setReadBuffer(pbuffer); + + // set background color + viewer.getCamera()->setClearColor(osg::Vec4f(1.0f,1.0f,1.0f,1.0f)); + viewer.getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ((osg::MatrixTransform*)sceneGraph.get())->setMatrix(requestToModelPose(req)); + viewer.getCamera()->setViewMatrix(requestToCamPose(req)); + +// viewer.home(); + + // perform one viewer iteration + viewer.realize(); + viewer.frame(); + } +} + +osg::Matrix OSGConverter::requestToModelPose(const SendRequest& req) { + double pitch = (req.params.find("pitch") != req.params.end() ? strTo<int>(req.params.find("pitch")->second) : 0); + double roll = (req.params.find("roll") != req.params.end() ? strTo<int>(req.params.find("roll")->second) : 0); + double yaw = (req.params.find("yaw") != req.params.end() ? strTo<int>(req.params.find("yaw")->second) : 0); + + return eulerToMatrix(pitch, roll, yaw); +// osg::Matrix m; +// m.makeIdentity(); +// return m; +} + +osg::Matrix OSGConverter::requestToCamPose(const SendRequest& req) { + return eulerToMatrix(0, 0, 0); +} + +osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename) { + + /** + * root (model pose) + * - modelCenter (center model) + * - model (actual model) + */ + + long now = tthread::chrono::system_clock::now(); + + { + // get some privacy + tthread::lock_guard<tthread::recursive_mutex> lock(_cacheMutex); + + // do we have it in the cache? + if (_models.find(filename) == _models.end()) { + osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(filename); + if (!model.valid()) { + LOG(ERROR) << "Cannot load model from " << filename; + return new osg::MatrixTransform(); + } + _models[filename] = std::make_pair(now, model); + } + + // remove old models from cache + std::map<std::string, std::pair<long, osg::ref_ptr<osg::Node> > >::iterator modelIter = _models.begin(); + while(modelIter != _models.end()) { + // delete every model unused for 1 minutes + if (now - modelIter->second.first > 60000) { + _models.erase(modelIter++); + } else { + modelIter++; + } + } + } + + osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform(); + + osg::ref_ptr<osg::Node> model = _models[filename].second; + _models[filename].first = now; + + // translation matrix to move model into center + osg::ref_ptr<osg::MatrixTransform> modelCenter = new osg::MatrixTransform(); + modelCenter->addChild(model); + + // move bounding sphere center into origin + osg::BoundingSphere bs = model->getBound(); + modelCenter->setMatrix(osg::Matrix::translate(bs.center() *= -1)); + + // add to model pose matrix + root->addChild(modelCenter); + + return root; +} + +osg::Matrix OSGConverter::eulerToMatrix(double pitch, double roll, double yaw) { + // see http://www.flipcode.com/documents/matrfaq.html#Q36 + osg::Matrix m; + m.makeIdentity(); + + double A = cos(pitch); + double B = sin(pitch); + double C = cos(roll); + double D = sin(roll); + double E = cos(yaw); + double F = sin(yaw); + + double AD = A * D; + double BD = B * D; + + m(0,0) = C * E; + m(0,1) = -C * F; + m(0,2) = -D; + m(1,0) = -BD * E + A * F; + m(1,1) = BD * F + A * E; + m(1,2) = -B * C; + m(2,0) = AD * E + B * F; + m(2,1) = -AD * F + B * E; + m(2,2) = A * C; + + m(0,3) = m(1,3) = m(2,3) = m(3,0) = m(3,1) = m(3,2) = 0; + m(3,3) = 1; + + return m; +} + +void OSGConverter::matrixToEuler(const osg::Matrix& m, double& pitch, double& roll, double& yaw) { + // see: http://www.flipcode.com/documents/matrfaq.html#Q37 + double angle_x, angle_z; + double D = -1 * asin(m(0,2)); /* Calculate Y-axis angle */ + double angle_y = D; + double C = cos(angle_y); + + /* Gimball lock? */ + if ( fabs( C ) > 0.005 ) { + double tr_x = m(2,2) / C; /* No, so get X-axis angle */ + double tr_y = -1 * m(1,2) / C; + angle_x = atan2( tr_y, tr_x ); + tr_x = m(0,0) / C; /* Get Z-axis angle */ + tr_y = -1 * m(0,1) / C; + angle_z = atan2( tr_y, tr_x ); + } else { + /* Gimball lock has occurred */ + angle_x = 0; /* Set X-axis angle to zero */ + double tr_x = m(1,1); /* And calculate Z-axis angle */ + double tr_y = m(1,0); + angle_z = atan2( tr_y, tr_x ); + } + + pitch = fmod(angle_x, 2 * M_PI ); /* Clamp all angles to range */ + roll = fmod( angle_y, 2 * M_PI ); + yaw = fmod( angle_z, 2 * M_PI ); +} + +void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image, const unsigned int context_id) { + osgDB::writeImageFile(image, _filename); } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h index c52b1ee..e96a4e9 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h @@ -2,6 +2,8 @@ #define OSGCONVERTER_H_W09J90F0 #include <uscxml/Interpreter.h> +#include <osg/Node> +#include <osgViewer/ViewerEventHandlers> #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" @@ -29,7 +31,35 @@ public: virtual void cancel(const std::string sendId); virtual void invoke(const InvokeRequest& req); + osg::Matrix requestToModelPose(const SendRequest& req); + osg::Matrix requestToCamPose(const SendRequest& req); + + static osg::Matrix eulerToMatrix(double pitch, double roll, double yaw); + static void matrixToEuler(const osg::Matrix& m, double& pitch, double& roll, double& yaw); + protected: + class NameRespectingWriteToFile : public osgViewer::ScreenCaptureHandler::WriteToFile { + public: + NameRespectingWriteToFile(const std::string& filename, + const std::string& extension, + SavePolicy savePolicy) : osgViewer::ScreenCaptureHandler::WriteToFile(filename, extension, savePolicy) { + } + + virtual void operator()(const osg::Image& image, const unsigned int context_id); + }; + + uscxml::concurrency::BlockingQueue<SendRequest> _workQueue; + osg::ref_ptr<osg::Node> setupGraph(const std::string filename); + + std::map<std::string, std::pair<long, osg::ref_ptr<osg::Node> > > _models; + tthread::recursive_mutex _cacheMutex; + + std::set<tthread::thread*> _threads; + + static void run(void*); + void process(const SendRequest& req); + + bool _isRunning; }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp index 78e3bea..753877c 100644 --- a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp +++ b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp @@ -117,25 +117,16 @@ void HTTPServletInvoker::httpRecvRequest(const HTTPServer::Request& req) { _requests[toStr((uintptr_t)req.curlReq)] = req; - Event event; + Event event = req; if (_isInterpreterGlobal) { - event.name = "http." + req.type; + event.name = "http." + event.data.compound["type"].atom; event.origin = toStr((uintptr_t)req.curlReq); } else { event.name = _callback; event.data.compound["reqId"] = Data(toStr((uintptr_t)req.curlReq), Data::VERBATIM); } - std::map<std::string, std::string>::const_iterator headerIter = req.headers.begin(); - while(headerIter != req.headers.end()) { - event.data.compound["headers"].compound[headerIter->first] = Data(headerIter->second, Data::VERBATIM); - headerIter++; - } - - event.data.compound["content"] = Data(req.content, Data::VERBATIM); - event.data.compound["type"] = Data(req.type, Data::VERBATIM); - returnEvent(event); } diff --git a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h index 4ac87e0..c9fe844 100644 --- a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h +++ b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h @@ -19,7 +19,7 @@ public: virtual std::set<std::string> getNames() { std::set<std::string> names; - names.insert("httpserver"); + names.insert("httpservlet"); names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#httpserver"); return names; } diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 4f7d61d..b7d08c4 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -54,9 +54,10 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { } } -void USCXMLInvoker::push(Event& event) { - event.invokeid = _invokeId; - _parentInterpreter->receive(event); +void USCXMLInvoker::push(const Event& event) { + Event copyEvent(event); + copyEvent.invokeid = _invokeId; + _parentInterpreter->receive(copyEvent); } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index 792cc5d..aedef32 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -23,6 +23,7 @@ public: virtual boost::shared_ptr<IOProcessorImpl> create(Interpreter* interpreter); virtual std::set<std::string> getNames() { std::set<std::string> names; + names.insert("scxml"); names.insert("uscxml"); names.insert("http://www.w3.org/TR/scxml"); names.insert("http://www.w3.org/TR/scxml/"); @@ -34,7 +35,7 @@ public: virtual void cancel(const std::string sendId); virtual void invoke(const InvokeRequest& req); - virtual void push(Event& event); + virtual void push(const Event& event); protected: Interpreter* _invokedInterpreter; diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp index 1b58785..6c7a8fc 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -67,10 +67,26 @@ Data EventIOProcessor::getDataModelVariables() { } void EventIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { - Event reqEvent; + Event reqEvent = req; reqEvent.type = Event::EXTERNAL; bool scxmlStructFound = false; + if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) { + // TODO: this looses all other information + reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str())); + scxmlStructFound = true; + } + if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) { + reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str()); + } + + std::map<std::string, Data>::iterator headerIter = reqEvent.data.compound["header"].compound.begin(); + while(headerIter != reqEvent.data.compound["header"].compound.end()) { + reqEvent.data.compound[headerIter->first] = Data(evhttp_decode_uri(headerIter->second.atom.c_str()), Data::VERBATIM); + headerIter++; + } + +#if 0 std::map<std::string, std::string>::const_iterator headerIter = req.headers.begin(); while(headerIter != req.headers.end()) { if (boost::iequals("_scxmleventstruct", headerIter->first)) { @@ -84,6 +100,7 @@ void EventIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { } headerIter++; } +#endif if (reqEvent.name.length() == 0) reqEvent.name = req.type; |