00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <rosmatlab/conversion.h>
00030 #include <rosmatlab/exception.h>
00031
00032 #include <introspection/message.h>
00033 #include <introspection/type.h>
00034
00035 #include <ros/time.h>
00036 #include <ros/duration.h>
00037
00038 #include <stdio.h>
00039 #include <ros/message_traits.h>
00040
00041 #include <mex.h>
00042
00043 namespace rosmatlab {
00044
00045 Conversion::Conversion(const MessagePtr &message) : message_(message) {}
00046 Conversion::~Conversion() {}
00047
00048 Array Conversion::toDoubleMatrix() {
00049 return toDoubleMatrix(0);
00050 }
00051
00052 Array Conversion::toDoubleMatrix(Array target, std::size_t n) {
00053 std::size_t m = 0;
00054 if (!target) target = mxCreateDoubleMatrix(expanded()->size(), n + 1, mxREAL);
00055
00056 bool do_realloc = false;
00057 if (mxGetM(target) < expanded()->size()) { mxSetM(target, expanded()->size()); do_realloc = true; }
00058 if (mxGetN(target) < n + 1) { mxSetN(target, n + 1); do_realloc = true; }
00059 if (do_realloc)
00060 {
00061 mxSetData(target, mxRealloc(mxGetData(target), mxGetN(target) * mxGetN(target) * sizeof(double)));
00062 }
00063
00064 double *data = mxGetPr(target) + mxGetM(target) * n;
00065 for(Message::const_iterator field = expanded()->begin(); field != expanded()->end(); ++field) {
00066 if (!(*field)->getType()->isNumeric()) continue;
00067 *data++ = (*field)->getType()->as_double((*field)->get());
00068 }
00069 return target;
00070 }
00071
00072 Array Conversion::toStruct() {
00073 return toStruct(0);
00074 }
00075
00076 Array Conversion::toStruct(Array target, std::size_t index) {
00077
00078 if (!target) target = mxCreateStructMatrix(1, index + 1, message_->getFieldNames().size(), const_cast<const char **>(message_->getFieldNames().data()));
00079
00080 for(Message::const_iterator field = message_->begin(); field != message_->end(); ++field) {
00081 const char *field_name = (*field)->getName();
00082
00083 if ((*field)->isMessage()) {
00084 MessagePtr field_message = messageByDataType((*field)->getDataType());
00085
00086 if (field_message) {
00087 Array child = mxCreateStructMatrix(1, (*field)->size(), field_message->getFieldNames().size(), const_cast<const char **>(field_message->getFieldNames().data()));
00088
00089
00090 for(std::size_t j = 0; j < (*field)->size(); j++) {
00091
00092 MessagePtr expanded = (*field)->expand(j);
00093 if (expanded) {
00094 Conversion(expanded).toStruct(child, j);
00095 } else {
00096 mexPrintf("Error during expansion of %s[%u] (%s)... %u\n", (*field)->getName(), j, (*field)->getDataType());
00097 }
00098 }
00099
00100 mxSetField(target, index, field_name, child);
00101
00102 } else {
00103 const char **field_names = { 0 };
00104 mxSetField(target, index, field_name, mxCreateStructMatrix(1, (*field)->size(), 0, field_names));
00105 }
00106
00107 } else {
00108 mxSetField(target, index, field_name, convertToMatlab(*field));
00109 }
00110 }
00111
00112 return target;
00113 }
00114
00115 MessagePtr Conversion::fromMatlab(ConstArray source, std::size_t index)
00116 {
00117 MessagePtr message = message_->introspect(message_->createInstance());
00118 fromMatlab(message, source, index);
00119 return message;
00120 }
00121
00122 void Conversion::fromMatlab(const MessagePtr& message, ConstArray source, std::size_t index)
00123 {
00124 if (mxIsStruct(source)) {
00125 fromStruct(message, source, index);
00126 return;
00127 }
00128
00129 if (mxIsDouble(source)) {
00130 fromDoubleMatrix(message, source, index);
00131 return;
00132 }
00133
00134 throw Exception("Cannot parse a message of class " + std::string(mxGetClassName(source)) + " as ROS message");
00135 }
00136
00137 void Conversion::fromDoubleMatrix(const MessagePtr& message, ConstArray source, std::size_t n)
00138 {
00139 if (!mxIsDouble(source)) return;
00140
00141 const double *begin = 0;
00142 const double *end = 0;
00143
00144 if (mxGetM(source) == 1 && n == 0) {
00145 begin = mxGetPr(source);
00146 end = begin + mxGetN(source);
00147 } else {
00148 if (n >= mxGetN(source)) throw Exception("Column index out of bounds");
00149 begin = mxGetPr(source) + mxGetM(source) * n;
00150 end = mxGetPr(source) + mxGetM(source) * (n + 1);
00151 }
00152
00153 fromDoubleMatrix(message, begin, end);
00154 }
00155
00156 void Conversion::fromDoubleMatrix(const MessagePtr &message, const double *begin, const double *end)
00157 {
00158 for(Message::const_iterator field = message->begin(); field != message->end(); ++field) {
00159 begin = convertFromDouble(*field, begin, end);
00160 }
00161 if (begin != end) throw Exception("Failed to parse a message of type " + std::string(message->getDataType()) + ": vector is too long");
00162 }
00163
00164 void Conversion::fromStruct(const MessagePtr &message, ConstArray source, std::size_t index)
00165 {
00166 if (!mxIsStruct(source)) return;
00167
00168 for(Message::const_iterator field = message->begin(); field != message->end(); ++field) {
00169 ConstArray field_source = mxGetField(source, index, (*field)->getName());
00170 if (!field_source) continue;
00171 convertFromMatlab(*field, field_source);
00172 }
00173 }
00174
00175 Array Conversion::convertToMatlab(const FieldPtr& field) {
00176 Array target = 0;
00177 TypePtr field_type = field->getType();
00178
00179
00180 try {
00181 if (field_type->isString()) {
00182 if (field->isArray()) {
00183 target = mxCreateCellMatrix(1, field->size());
00184 for(std::size_t i = 0; i < field->size(); i++) {
00185 mxSetCell(target, i, mxCreateString(field_type->as_string(field->get(i)).c_str()));
00186 }
00187 } else {
00188 target = mxCreateString(field_type->as_string(field->get()).c_str());
00189 }
00190 return target;
00191 }
00192
00193
00194 target = mxCreateDoubleMatrix(1, field->size(), mxREAL);
00195 double *x = mxGetPr(target);
00196
00197 for(std::size_t i = 0; i < field->size(); i++) {
00198 x[i] = field_type->as_double(field->get(i));
00199 }
00200
00201 } catch(boost::bad_any_cast &e) {
00202 mexPrintf("Catched bad_any_cast exception for field %s: %s", field->getName(), e.what());
00203 target = emptyArray();
00204 }
00205
00206 return target;
00207 }
00208
00209 void Conversion::convertFromMatlab(const FieldPtr &field, ConstArray source) {
00210 const char *field_name = field->getName();
00211 std::size_t field_size = mxIsChar(source) ? 1 : mxGetNumberOfElements(source);
00212
00213
00214 if (field->isArray() && field->size() != field_size) throw Exception("Failed to parse field " + std::string(field_name) + ": Array field must have length " + boost::lexical_cast<std::string>(field->size()));
00215 if (!field->isContainer() && field_size != 1) throw Exception("Failed to parse field " + std::string(field_name) + ": Scalar field must have exactly length 1");
00216 if (field->isVector()) field->resize(field_size);
00217
00218
00219 if (field->isMessage()) {
00220 MessagePtr field_message = messageByDataType(field->getDataType());
00221 if (!field_message) throw Exception("Failed to parse field " + std::string(field_name) + ": unknown datatype " + field->getDataType());
00222 Conversion child_conversion(field_message);
00223
00224
00225 for(std::size_t i = 0; i < field_size; i++) {
00226
00227 MessagePtr expanded = field->expand(i);
00228 if (expanded) {
00229 child_conversion.fromMatlab(expanded, source, i);
00230 } else {
00231 mexPrintf("Error during expansion of %s[%u] (%s)... %u\n", field->getName(), i, field->getDataType());
00232 }
00233 }
00234
00235 return;
00236 }
00237
00238
00239 if (field->getType()->isString()) {
00240 std::vector<char> buffer;
00241
00242 for(std::size_t i = 0; i < field->size(); i++) {
00243 if (mxIsCell(source) && mxIsChar(mxGetCell(source, i))) {
00244 buffer.resize(mxGetNumberOfElements(mxGetCell(source, i)) + 1);
00245 mxGetString(mxGetCell(source, i), buffer.data(), buffer.size());
00246 field->set(std::string(buffer.data(), buffer.size() - 1), i);
00247
00248 } else if (mxIsChar(source) && i == 0) {
00249 buffer.resize(mxGetN(source) + 1);
00250 mxGetString(source, buffer.data(), buffer.size());
00251 field->set(std::string(buffer.data(), buffer.size() - 1));
00252
00253 } else {
00254 throw Exception("Failed to parse string field " + std::string(field->getDataType()) + " " + std::string(field->getName()) + ": Array must be a cell string or a character array");
00255 }
00256 }
00257
00258 return;
00259 }
00260
00261
00262 if (!mxIsDouble(source)) throw Exception("Failed to parse field " + std::string(field->getDataType()) + " " + std::string(field->getName()) + ": Array must be a double array");
00263 const double *x = mxGetPr(source);
00264 convertFromDouble(field, x, x + mxGetN(source));
00265 }
00266
00267 const double *Conversion::convertFromDouble(const FieldPtr& field, const double *begin, const double *end)
00268 {
00269 const double *data = begin;
00270
00271 if (field->isVector() && end >= begin) {
00272
00273 field->resize(end - begin);
00274 }
00275
00276
00277 if (end - begin < field->size()) {
00278 throw Exception("Failed to parse field " + std::string(field->getName()) + ": vector is too short");
00279 }
00280
00281
00282 if (field->isMessage()) {
00283
00284 }
00285
00286
00287 if (field->getType()->isString()) {
00288 for(std::size_t i = 0; i < field->size(); i++) {
00289 field->set(std::string(), i);
00290 data++;
00291 }
00292 return data;
00293 }
00294
00295
00296 for(std::size_t i = 0; i < field->size(); i++) {
00297 field->set(*data++, i);
00298 }
00299
00300 return data;
00301 }
00302
00303 Array Conversion::emptyArray() const {
00304 return mxCreateDoubleMatrix(0, 0, mxREAL);
00305 }
00306
00307 const MessagePtr& Conversion::expanded() {
00308 if (!expanded_) {
00309 expanded_ = expand(message_);
00310
00311 }
00312 return expanded_;
00313 }
00314
00315 }