#ifndef MESSAGES_H #define MESSAGES_H #include #include #include #include #include "ros_bridge/rapidjson/include/rapidjson/rapidjson.h" #include "ros_bridge/rapidjson/include/rapidjson/document.h" #include "utilities.h" #include "MessageTraits.h" #include namespace ROSBridge { //! @brief Namespace containing methodes for Json generation. namespace JsonMethodes { //! @brief Namespace containing methodes for std_msgs generation. namespace StdMsgs { //! @brief Namespace containing methodes for std_msgs/Time message generation. namespace Time { template bool toJson(const TimeType &time, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { value.AddMember("secs", rapidjson::Value().SetUint(uint32_t(time.secs())), allocator); value.AddMember("nsecs", rapidjson::Value().SetUint(uint32_t(time.nSecs())), allocator); return true; } template bool fromJson(const rapidjson::Value &value, TimeType &time) { if (!value.HasMember("secs") || !value["secs"].IsUint()){ assert(false); return false; } if (!value.HasMember("nsecs")|| !value["nsecs"].IsUint()){ assert(false); return false; } time.setSecs(value["secs"].GetUint()); time.setNSecs(value["nsecs"].GetUint()); return true; } } // Time //! @brief Namespace containing methodes for std_msgs/Header message generation. namespace Header { template bool toJson(const HeaderType &header, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { value.AddMember("seq", rapidjson::Value().SetUint(uint32_t(header.seq())), allocator); rapidjson::Value stamp(rapidjson::kObjectType); if (!Time::toJson(header.stamp(), stamp, allocator)){ assert(false); return false; } value.AddMember("stamp", stamp, allocator); value.AddMember("frame_id", rapidjson::Value().SetString(header.frameId().data(), header.frameId().length(), allocator), allocator); return true; } template bool fromJson(const rapidjson::Value &value, HeaderType &header) { if (!value.HasMember("seq")|| !value["seq"].IsUint()){ assert(false); return false; } if (!value.HasMember("stamp")){ assert(false); return false; } if (!value.HasMember("frame_id")|| !value["frame_id"].IsString()){ assert(false); return false; } header.setSeq(value["seq"].GetUint()); decltype(header.stamp()) time; if (!Time::fromJson(value["stamp"], time)){ assert(false); return false; } header.setStamp(time); header.setFrameId(value["frame_id"].GetString()); return true; } } // Header } // StdMsgs //! @brief Namespace containing methodes for geometry_msgs generation. namespace GeometryMsgs { //! @brief Namespace containing methodes for geometry_msgs/Point32 message generation. namespace Point32 { using namespace ROSBridge::traits; namespace det { //detail template auto getZ(const T &p, Type2Type) { return p.z(); } template auto getZ(const T &p, Type2Type) { (void)p; return 0.0; // p has no member z() -> add 0. } template bool setZ(const rapidjson::Value &doc, const T &p, Type2Type) { p.setZ(doc["z"].GetFloat()); return true; } template bool setZ(const rapidjson::Value &doc, const T &p, Type2Type) { (void)doc; (void)p; return true; } } template bool toJson(const T&p, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { value.AddMember("x", rapidjson::Value().SetFloat(p.x()), allocator); value.AddMember("y", rapidjson::Value().SetFloat(p.y()), allocator); typedef typename Select::value, Has3Components, Has2Components>::Result Components; // Check if PointType has 2 or 3 dimensions. auto z = det::getZ(p, Type2Type()); // If T has no member z() replace it by 0. value.AddMember("z", rapidjson::Value().SetFloat(z), allocator); return true; } template bool fromJson(const rapidjson::Value &value, PointType &p) { if (!value.HasMember("x") || !value["x"].IsFloat()){ assert(false); return false; } if (!value.HasMember("y") || !value["y"].IsFloat()){ assert(false); return false; } if (!value.HasMember("z") || !value["z"].IsFloat()){ assert(false); return false; } p.setX(value["x"].GetFloat()); p.setY(value["y"].GetFloat()); typedef typename Select::value, Has3Components, Has2Components>::Result Components; // Check if PointType has 2 or 3 dimensions. (void)det::setZ(value["z"], p, Type2Type()); // If PointType has no member z() discard doc["z"]. return true; } } // Point32 //! @brief Namespace containing methodes for geometry_msgs/Polygon message generation. namespace Polygon { template bool toJson(const PolygonType &poly, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { rapidjson::Value points(rapidjson::kArrayType); for(unsigned long i=0; i < std::uint64_t(poly.points().size()); ++i) { rapidjson::Document point(rapidjson::kObjectType); if ( !Point32::toJson(poly.points()[i], point, allocator) ){ assert(false); return false; } points.PushBack(point, allocator); } value.AddMember("points", points, allocator); return true; } template bool fromJson(const rapidjson::Value &value, PolygonType &poly) { if (!value.HasMember("points") || !value["points"].IsArray()){ assert(false); return false; } const auto &jsonArray = value["points"].GetArray(); poly.points().reserve(jsonArray.Size()); typedef decltype (poly.points()[0]) PointTypeCVR; typedef typename boost::remove_cv::type>::type PointType; for (long i=0; i < jsonArray.Size(); ++i){ PointType pt; if ( !Point32::fromJson(jsonArray[i], pt) ){ assert(false); return false; } poly.points().push_back(std::move(pt)); } return true; } } // namespace Polygon //! @brief Namespace containing methodes for geometry_msgs/PolygonStamped message generation. namespace PolygonStamped { using namespace ROSBridge::JsonMethodes::StdMsgs; template bool toJson(const PolyStamped &polyStamped, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { return toJson(polyStamped.polygon(), polyStamped.header(), value, allocator); } template bool toJson(const PolygonType &poly, const HeaderType &h, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { rapidjson::Document header(rapidjson::kObjectType); if (!Header::toJson(h, header, allocator)){ assert(false); return false; } rapidjson::Document polygon(rapidjson::kObjectType); if (!Polygon::toJson(poly, polygon, allocator)){ assert(false); return false; } value.AddMember("header", header, allocator); value.AddMember("polygon", polygon, allocator); return true; } namespace det { template bool setHeader(const rapidjson::Value &doc, PolygonStampedType &polyStamped, Int2Type<1>) { // polyStamped.setHeader() exists typedef decltype (polyStamped.header()) HeaderTypeCVR; typedef typename boost::remove_cv::type>::type HeaderType; HeaderType header; bool ret = Header::fromJson(doc, header); polyStamped.header() = header; return ret; } template bool setHeader(const rapidjson::Value &doc, PolygonStampedType &polyStamped, Int2Type<0>) { // polyStamped.setHeader() does not exists (void)doc; (void)polyStamped; return true; } } // namespace det template bool fromJson(const rapidjson::Value &value, PolygonType &polyStamped) { if ( !value.HasMember("header") ){ assert(false); return false; } if ( !value.HasMember("polygon") ){ assert(false); return false; } typedef traits::HasMemberSetHeader HasHeader; if ( !det::setHeader(value["header"], polyStamped, Int2Type())){ assert(false); return false; } if ( !Polygon::fromJson(value["polygon"], polyStamped.polygon()) ){ assert(false); return false; } return true; } } // namespace PolygonStamped } // namespace GeometryMsgs //! @brief Namespace containing methodes for geographic_msgs generation. namespace GeographicMsgs { //! @brief Namespace containing methodes for geographic_msgs/GeoPoint message generation. namespace GeoPoint { using namespace ROSBridge::traits; namespace det { //detail template auto getAltitude(const T &p, Type2Type) { return p.altitude(); } template auto getAltitude(const T &p, Type2Type) { (void)p; return 0.0; } template void setAltitude(const rapidjson::Value &doc, T &p, Type2Type) { p.setAltitude(doc.GetFloat()); } template void setAltitude(const rapidjson::Value &doc, T &p, Type2Type) { (void)doc; (void)p; } } // namespace det template bool toJson(const T&p, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { value.AddMember("latitude", rapidjson::Value().SetFloat((_Float64)p.latitude()), allocator); value.AddMember("longitude", rapidjson::Value().SetFloat((_Float64)p.longitude()), allocator); typedef typename Select::value, Has3Components, Has2Components>::Result Components; // Check if PointType has 2 or 3 dimensions. auto altitude = det::getAltitude(p, Type2Type()); // If T has no member altitude() replace it by 0.0; value.AddMember("altitude", rapidjson::Value().SetFloat((_Float64)altitude), allocator); return true; } template bool fromJson(const rapidjson::Value &value, PointType &p) { if (!value.HasMember("latitude") || !value["latitude"].IsFloat()){ assert(false); return false; } if (!value.HasMember("longitude") || !value["longitude"].IsFloat()){ assert(false); return false; } if (!value.HasMember("altitude") || !value["altitude"].IsFloat()){ assert(false); return false; } p.setLatitude(value["latitude"].GetFloat()); p.setLongitude(value["longitude"].GetFloat()); typedef typename Select::value, Has3Components, Has2Components>::Result Components; // Check if PointType has 2 or 3 dimensions. det::setAltitude(value["altitude"], p, Type2Type()); // If T has no member altitude() discard doc["altitude"]; return true; } } // GeoPoint } // GeographicMsgs //! @brief Namespace containing methodes for jsk_recognition_msgs generation. namespace JSKRecognitionMsgs { //! @brief Namespace containing methodes for jsk_recognition_msgs/PolygonArray message generation. namespace PolygonArray { using namespace ROSBridge::traits; using namespace ROSBridge::JsonMethodes::StdMsgs; using namespace ROSBridge::JsonMethodes::GeometryMsgs; namespace PAdetail { //! Helper functions to generate Json entries for labels and likelihood. //! \note \p p has member \fn labels(). template void labelsToJson(const PolygonArrayType &p, rapidjson::Value &labels, rapidjson::Document::AllocatorType &allocator, Int2Type){ for(unsigned long i=0; i < (unsigned long)p.labels().size(); ++i) labels.PushBack(rapidjson::Value().SetUint(p.labels()[i]), allocator); } //! \note \p p has no member \fn labels(). template void labelsToJson(const PolygonArrayType &p, rapidjson::Value &labels, rapidjson::Document::AllocatorType &allocator, Int2Type<0>){ for(unsigned long i=0; i < (unsigned long)(p.polygons().size()); ++i) labels.PushBack(rapidjson::Value().SetUint(0), allocator); // use zero! } //! \note \p p has member \fn likelihood(). template void likelihoodToJson(const PolygonArrayType &p, rapidjson::Value &likelyhood, rapidjson::Document::AllocatorType &allocator, Int2Type){ for(unsigned long i=0; i < (unsigned long)p.likelyhood().size(); ++i) likelyhood.PushBack(rapidjson::Value().SetFloat(p.likelyhood()[i]), allocator); } //! \note \p p has no member \fn likelihood(). template void likelihoodToJson(const PolygonArrayType &p, rapidjson::Value &likelyhood, rapidjson::Document::AllocatorType &allocator, Int2Type<0>){ for(unsigned long i=0; i < (unsigned long)p.polygons().size(); ++i) likelyhood.PushBack(rapidjson::Value().SetFloat(0), allocator); // use zero! } //! \note \p p has member \fn labels(). template void setLabels(const rapidjson::Value &doc, PolygonArrayType &p, Int2Type){ for(unsigned long i=0; i < (unsigned long)doc.Size(); ++i) p.labels().push_back(doc[i]); } //! \note \p p has no member \fn labels(). template void setLabels(const rapidjson::Value &doc, PolygonArrayType &p, Int2Type<0>){ (void)doc; (void)p; } //! \note \p p has member \fn likelihood(). template void setLikelihood(const rapidjson::Value &doc, PolygonArrayType &p, Int2Type){ for(unsigned long i=0; i < (unsigned long)doc.Size(); ++i) p.likelihood().push_back(doc[i]); } //! \note \p p has no member \fn likelihood(). template void setLikelihood(const rapidjson::Value &doc, PolygonArrayType &p, Int2Type<0>){ (void)doc; (void)p; } } //! //! Create PolygonArray message from \p p. \p p contains a header. //! \param p Class implementing the PolygonArrayType interface. //! \param doc Rapidjson document used to store the PolygonArray message. //! \param allocator Allocator used by doc. Can be obtained e.g. by calling doc.getAllocator(). //! //! \note The \fn labels() and \fn likelihood() members are optinal. If any of them is missing they //! will be replaced by arrays filled with zero and size p.polygons.size(). //! //! \note If this function is called p.polygons[i] (entries implement the the PolygonStampedGroup interface) //! must contain a header. template bool toJson(const PolygonArrayType &pArray, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { rapidjson::Document header(rapidjson::kObjectType); if (Header::toJson(pArray.header(), header, allocator)){ assert(false); return false; } value.AddMember("header", header, allocator); rapidjson::Value polygons(rapidjson::kArrayType); for(unsigned long i=0; i < pArray.polygons().size(); ++i){ rapidjson::Document polygon(rapidjson::kObjectType); if (!PolygonStamped::toJson(pArray.polygons()[i], polygon, allocator)){ assert(false); return false; } polygons.PushBack(polygon, allocator); } value.AddMember("polygons", polygons, allocator); rapidjson::Value labels(rapidjson::kArrayType); typedef HasMemberLabels HasLabels; PAdetail::labelsToJson(pArray, labels, allocator, Int2Type()); value.AddMember("labels", labels, allocator); rapidjson::Value likelihood(rapidjson::kArrayType); typedef HasMemberLikelihood HasLikelihood; PAdetail::likelihoodToJson(pArray, likelihood, allocator, Int2Type()); value.AddMember("likelihood", likelihood, allocator); return true; } //! //! Create PolygonArray message from \p p and \p h. \p p doesn't have it's own header. //! \param p Class implementing the PolygonArrayType interface. //! \param h Class implementing the HeaderType interface. //! \param doc Rapidjson document used to store the PolygonArray message. //! \param allocator Allocator used by doc. Can be obtained e.g. by calling doc.getAllocator(). //! //! \note The \fn labels() and \fn likelihood() members are optinal. If any of them is missing they //! will be replaced by arrays filled with zero and size p.polygons.size(). //! //! \note If this function is called the headers in p.polygons[i] (entries implement the the PolygonStampedGroup interface) //! are ignored. template bool toJson(const PolygonArrayType &p, const HeaderType &h, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { rapidjson::Document header(rapidjson::kObjectType); if (!Header::toJson(h, header, allocator)){ assert(false); return false; } value.AddMember("header", header, allocator); rapidjson::Value polygons(rapidjson::kArrayType); for(unsigned long i=0; i < (unsigned long)(p.polygons().size()); ++i){ rapidjson::Document polygon(rapidjson::kObjectType); if (!PolygonStamped::toJson(p.polygons()[i].polygon(), h, polygon, allocator)){ assert(false); return false; } polygons.PushBack(polygon, allocator); } value.AddMember("polygons", polygons, allocator); rapidjson::Value labels(rapidjson::kArrayType); typedef HasMemberLabels HasLabels; PAdetail::labelsToJson(p, labels, allocator, Int2Type()); value.AddMember("labels", labels, allocator); rapidjson::Value likelihood(rapidjson::kArrayType); typedef HasMemberLikelihood HasLikelihood; PAdetail::likelihoodToJson(p, likelihood, allocator, Int2Type()); value.AddMember("likelihood", likelihood, allocator); return true; } template bool fromJson(const rapidjson::Value &value, PolygonArrayType &p) { if ( !value.HasMember("header")){ assert(false); return false; } if ( !value.HasMember("polygons") || !value["polygons"].IsArray() ){ assert(false); return false; } if ( !value.HasMember("labels") || !value["labels"].IsArray() ){ assert(false); return false; } if ( !value.HasMember("likelihood") || !value["likelihood"].IsArray() ){ assert(false); return false; } typedef traits::HasMemberHeader HasHeader; if ( !PolygonStamped::det::setHeader(value["header"], p, Int2Type())){ assert(false); return false; } const auto &polyStampedJson = value["polygons"]; p.polygons().reserve(polyStampedJson.Size()); typedef decltype (p.polygons()[0]) PolyStampedCVR; typedef typename boost::remove_cv::type>::type PolyStamped; for (unsigned int i=0; i < polyStampedJson.Size(); ++i) { if ( !polyStampedJson[i].HasMember("header") ){ assert(false); return false; } PolyStamped polyStamped; if ( !PolygonStamped::det::setHeader(polyStampedJson[i]["header"], polyStamped, Int2Type())){ assert(false); return false; } if ( !Polygon::fromJson(polyStampedJson[i]["polygon"], polyStamped.polygon())){ assert(false); return false; } p.polygons().push_back(std::move(polyStamped)); } typedef traits::HasMemberLabels HasLabels; PAdetail::setLabels(value["labels"], p, Int2Type()); typedef traits::HasMemberLikelihood HasLikelihood; PAdetail::setLikelihood(value["likelihood"], p, Int2Type()); return true; } } // end namespace PolygonArray } // namespace JSKRekognitionMsgs //! @brief Namespace containing methodes for nemo_msgs generation. namespace NemoMsgs { //! @brief Namespace containing methodes for nemo_msgs/Progress generation. namespace Progress { template bool toJson(const ProgressType &p, rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator) { rapidjson::Value progressJson(rapidjson::kArrayType); for(unsigned long i=0; i < std::uint64_t(p.progress().size()); ++i){ progressJson.PushBack(rapidjson::Value().SetInt(std::int8_t(p.progress()[i])), allocator); } value.AddMember("progress", progressJson, allocator); return true; } template bool fromJson(const rapidjson::Value &value, ProgressType &p) { if (!value.HasMember("progress") || !value["progress"].IsArray()){ assert(false); return false; } const auto& jsonProgress = value["progress"]; unsigned long sz = jsonProgress.Size(); p.progress().reserve(sz); for (unsigned long i=0; i < sz; ++i) p.progress().push_back(std::int8_t(jsonProgress[i].GetInt())); return true; } } // namespace Progress } // namespace NemoMsgs } // namespace JsonMethodes } // namespace ROSBridge #endif // MESSAGES_H