conversion.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2012, Johannes Meyer, TU Darmstadt
00003 // All rights reserved.
00004 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Flight Systems and Automatic Control group,
00013 //       TU Darmstadt, nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 //  mexPrintf("Constructing message %s (%s)...\n", message_->getName(), message_->getDataType());
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         // iterate over array
00090         for(std::size_t j = 0; j < (*field)->size(); j++) {
00091 //          mexPrintf("Expanding field %s[%u] (%s)... %u\n", (*field)->getName(), j, (*field)->getDataType());
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 //  mexPrintf("Constructing field %s (%s)...\n", field->getName(), field->getDataType());
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 //    mexPrintf("Constructing double vector with dimension %u for field %s\n", unsigned(field->size()), field->getName());
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   // check size
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   // parse ROS message
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     // iterate over array
00225     for(std::size_t i = 0; i < field_size; i++) {
00226 //     mexPrintf("Expanding field %s[%u] (%s)... %u\n", field->getName(), i, field->getDataType());
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   // parse string
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   // For all other types source must be a double array...
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     // eat up all the input (roar!!!)
00273     field->resize(end - begin);
00274   }
00275 
00276   // check size
00277   if (end - begin < field->size()) {
00278     throw Exception("Failed to parse field " + std::string(field->getName()) + ": vector is too short");
00279   }
00280 
00281   // parse ROS message
00282   if (field->isMessage()) {
00283     // TODO
00284   }
00285 
00286   // ignore strings (set to empty string)
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   // read doubles
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 //    mexPrintf("Expanded an instance of %s to %u fields", message_->getDataType(), expanded_->size());
00311   }
00312   return expanded_;
00313 }
00314 
00315 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


rosmatlab
Author(s): Johannes Meyer
autogenerated on Tue Jan 8 2013 17:31:00