Merge remote-tracking branch 'origin/develop' into feature/frobeniusfactor
						commit
						8739c372fb
					
				
							
								
								
									
										4
									
								
								gtsam.h
								
								
								
								
							
							
						
						
									
										4
									
								
								gtsam.h
								
								
								
								
							|  | @ -281,7 +281,7 @@ virtual class Value { | |||
| }; | ||||
| 
 | ||||
| #include <gtsam/base/GenericValue.h> | ||||
| template<T = {Vector, gtsam::Point2, gtsam::Point3, gtsam::Rot2, gtsam::Rot3, gtsam::Pose2, gtsam::Pose3, gtsam::StereoPoint2, gtsam::Cal3_S2, gtsam::CalibratedCamera, gtsam::SimpleCamera, gtsam::imuBias::ConstantBias}> | ||||
| template<T = {Vector, Matrix, gtsam::Point2, gtsam::Point3, gtsam::Rot2, gtsam::Rot3, gtsam::Pose2, gtsam::Pose3, gtsam::StereoPoint2, gtsam::Cal3_S2, gtsam::Cal3DS2, gtsam::Cal3Bundler, gtsam::EssentialMatrix, gtsam::CalibratedCamera, gtsam::SimpleCamera, gtsam::imuBias::ConstantBias}> | ||||
| virtual class GenericValue : gtsam::Value { | ||||
|   void serializable() const; | ||||
| }; | ||||
|  | @ -2984,6 +2984,7 @@ class PreintegratedImuMeasurements { | |||
|   gtsam::Rot3 deltaRij() const; | ||||
|   Vector deltaPij() const; | ||||
|   Vector deltaVij() const; | ||||
|   gtsam::imuBias::ConstantBias biasHat() const; | ||||
|   Vector biasHatVector() const; | ||||
|   gtsam::NavState predict(const gtsam::NavState& state_i, | ||||
|       const gtsam::imuBias::ConstantBias& bias) const; | ||||
|  | @ -3045,6 +3046,7 @@ class PreintegratedCombinedMeasurements { | |||
|   gtsam::Rot3 deltaRij() const; | ||||
|   Vector deltaPij() const; | ||||
|   Vector deltaVij() const; | ||||
|   gtsam::imuBias::ConstantBias biasHat() const; | ||||
|   Vector biasHatVector() const; | ||||
|   gtsam::NavState predict(const gtsam::NavState& state_i, | ||||
|       const gtsam::imuBias::ConstantBias& bias) const; | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ if(NOT GTSAM_USE_SYSTEM_EIGEN) | |||
| 	endforeach(eigen_dir) | ||||
| 
 | ||||
| 	if(GTSAM_WITH_EIGEN_UNSUPPORTED) | ||||
| 		message("-- Installing Eigen Unsupported modules") | ||||
| 		message(STATUS "Installing Eigen Unsupported modules") | ||||
| 		# do the same for the unsupported eigen folder | ||||
| 		file(GLOB_RECURSE  unsupported_eigen_headers "${CMAKE_CURRENT_SOURCE_DIR}/Eigen/unsupported/Eigen/*.h") | ||||
| 
 | ||||
|  |  | |||
|  | @ -181,7 +181,7 @@ public: | |||
|   // Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
 | ||||
|   enum { NeedsToAlign = (sizeof(T) % 16) == 0 }; | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| }; | ||||
| 
 | ||||
| /// use this macro instead of BOOST_CLASS_EXPORT for GenericValues
 | ||||
|  |  | |||
|  | @ -214,7 +214,7 @@ public: | |||
|   enum { NeedsToAlign = (sizeof(M1) % 16) == 0 || (sizeof(M2) % 16) == 0 | ||||
|   }; | ||||
| public: | ||||
| 	EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| 	GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| }; | ||||
| 
 | ||||
| // Define any direct product group to be a model of the multiplicative Group concept
 | ||||
|  |  | |||
|  | @ -0,0 +1,67 @@ | |||
| /* ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  * GTSAM Copyright 2020, Georgia Tech Research Corporation, | ||||
|  * Atlanta, Georgia 30332-0415 | ||||
|  * All Rights Reserved | ||||
|  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | ||||
| 
 | ||||
|  * See LICENSE for the license information | ||||
| 
 | ||||
|  * -------------------------------------------------------------------------- */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @file make_shared.h | ||||
|  * @brief make_shared trampoline function to ensure proper alignment | ||||
|  * @author Fan Jiang | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gtsam/base/types.h> | ||||
| 
 | ||||
| #include <Eigen/Core> | ||||
| 
 | ||||
| #include <boost/make_shared.hpp> | ||||
| 
 | ||||
| #include <type_traits> | ||||
| 
 | ||||
| namespace gtsam { | ||||
|   /// An shorthand alias for accessing the ::type inside std::enable_if that can be used in a template directly
 | ||||
|   template<bool B, class T = void> | ||||
|   using enable_if_t = typename std::enable_if<B, T>::type; | ||||
| } | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
|   /**
 | ||||
|    * Add our own `make_shared` as a layer of wrapping on `boost::make_shared` | ||||
|    * This solves the problem with the stock `make_shared` that custom alignment is not respected, causing SEGFAULTs | ||||
|    * at runtime, which is notoriously hard to debug. | ||||
|    * | ||||
|    * Explanation | ||||
|    * =============== | ||||
|    * The template `needs_eigen_aligned_allocator<T>::value` will evaluate to `std::true_type` if the type alias | ||||
|    * `_eigen_aligned_allocator_trait = void` is present in a class, which is automatically added by the | ||||
|    * `GTSAM_MAKE_ALIGNED_OPERATOR_NEW` macro. | ||||
|    * | ||||
|    * This function declaration will only be taken when the above condition is true, so if some object does not need to | ||||
|    * be aligned, `gtsam::make_shared` will fall back to the next definition, which is a simple wrapper for | ||||
|    * `boost::make_shared`. | ||||
|    * | ||||
|    * @tparam T The type of object being constructed | ||||
|    * @tparam Args Type of the arguments of the constructor | ||||
|    * @param args Arguments of the constructor | ||||
|    * @return The object created as a boost::shared_ptr<T> | ||||
|    */ | ||||
|   template<typename T, typename ... Args> | ||||
|   gtsam::enable_if_t<needs_eigen_aligned_allocator<T>::value, boost::shared_ptr<T>> make_shared(Args &&... args) { | ||||
|     return boost::allocate_shared<T>(Eigen::aligned_allocator<T>(), std::forward<Args>(args)...); | ||||
|   } | ||||
| 
 | ||||
|   /// Fall back to the boost version if no need for alignment
 | ||||
|   template<typename T, typename ... Args> | ||||
|   gtsam::enable_if_t<!needs_eigen_aligned_allocator<T>::value, boost::shared_ptr<T>> make_shared(Args &&... args) { | ||||
|     return boost::make_shared<T>(std::forward<Args>(args)...); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | @ -42,123 +42,218 @@ | |||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
| // Serialization directly to strings in compressed format
 | ||||
| template<class T> | ||||
| std::string serialize(const T& input) { | ||||
|   std::ostringstream out_archive_stream; | ||||
| /** @name Standard serialization
 | ||||
|  *  Serialization in default compressed format | ||||
|  */ | ||||
| ///@{
 | ||||
| /// serializes to a stream
 | ||||
| template <class T> | ||||
| void serializeToStream(const T& input, std::ostream& out_archive_stream) { | ||||
|   boost::archive::text_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << input; | ||||
|   return out_archive_stream.str(); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| void deserialize(const std::string& serialized, T& output) { | ||||
|   std::istringstream in_archive_stream(serialized); | ||||
| /// deserializes from a stream
 | ||||
| template <class T> | ||||
| void deserializeFromStream(std::istream& in_archive_stream, T& output) { | ||||
|   boost::archive::text_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> output; | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| /// serializes to a string
 | ||||
| template <class T> | ||||
| std::string serializeToString(const T& input) { | ||||
|   std::ostringstream out_archive_stream; | ||||
|   serializeToStream(input, out_archive_stream); | ||||
|   return out_archive_stream.str(); | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a string
 | ||||
| template <class T> | ||||
| void deserializeFromString(const std::string& serialized, T& output) { | ||||
|   std::istringstream in_archive_stream(serialized); | ||||
|   deserializeFromStream(in_archive_stream, output); | ||||
| } | ||||
| 
 | ||||
| /// serializes to a file
 | ||||
| template <class T> | ||||
| bool serializeToFile(const T& input, const std::string& filename) { | ||||
|   std::ofstream out_archive_stream(filename.c_str()); | ||||
|   if (!out_archive_stream.is_open()) | ||||
|     return false; | ||||
|   boost::archive::text_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << input; | ||||
|   if (!out_archive_stream.is_open()) return false; | ||||
|   serializeToStream(input, out_archive_stream); | ||||
|   out_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| /// deserializes from a file
 | ||||
| template <class T> | ||||
| bool deserializeFromFile(const std::string& filename, T& output) { | ||||
|   std::ifstream in_archive_stream(filename.c_str()); | ||||
|   if (!in_archive_stream.is_open()) | ||||
|     return false; | ||||
|   boost::archive::text_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> output; | ||||
|   if (!in_archive_stream.is_open()) return false; | ||||
|   deserializeFromStream(in_archive_stream, output); | ||||
|   in_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| // Serialization to XML format with named structures
 | ||||
| template<class T> | ||||
| std::string serializeXML(const T& input, const std::string& name="data") { | ||||
|   std::ostringstream out_archive_stream; | ||||
|   // braces to flush out_archive as it goes out of scope before taking str()
 | ||||
|   // fixes crash with boost 1.66-1.68
 | ||||
|   // see https://github.com/boostorg/serialization/issues/82
 | ||||
|   { | ||||
|     boost::archive::xml_oarchive out_archive(out_archive_stream); | ||||
|     out_archive << boost::serialization::make_nvp(name.c_str(), input); | ||||
|   } | ||||
|   return out_archive_stream.str(); | ||||
| /// serializes to a string
 | ||||
| template <class T> | ||||
| std::string serialize(const T& input) { | ||||
|   return serializeToString(input); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| void deserializeXML(const std::string& serialized, T& output, const std::string& name="data") { | ||||
|   std::istringstream in_archive_stream(serialized); | ||||
|   boost::archive::xml_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> boost::serialization::make_nvp(name.c_str(), output); | ||||
| /// deserializes from a string
 | ||||
| template <class T> | ||||
| void deserialize(const std::string& serialized, T& output) { | ||||
|   deserializeFromString(serialized, output); | ||||
| } | ||||
| ///@}
 | ||||
| 
 | ||||
| template<class T> | ||||
| bool serializeToXMLFile(const T& input, const std::string& filename, const std::string& name="data") { | ||||
|   std::ofstream out_archive_stream(filename.c_str()); | ||||
|   if (!out_archive_stream.is_open()) | ||||
|     return false; | ||||
| /** @name XML Serialization
 | ||||
|  *  Serialization to XML format with named structures | ||||
|  */ | ||||
| ///@{
 | ||||
| /// serializes to a stream in XML
 | ||||
| template <class T> | ||||
| void serializeToXMLStream(const T& input, std::ostream& out_archive_stream, | ||||
|                   const std::string& name = "data") { | ||||
|   boost::archive::xml_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << boost::serialization::make_nvp(name.c_str(), input);; | ||||
|   out_archive_stream.close(); | ||||
|   return true; | ||||
|   out_archive << boost::serialization::make_nvp(name.c_str(), input); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| bool deserializeFromXMLFile(const std::string& filename, T& output, const std::string& name="data") { | ||||
|   std::ifstream in_archive_stream(filename.c_str()); | ||||
|   if (!in_archive_stream.is_open()) | ||||
|     return false; | ||||
| /// deserializes from a stream in XML
 | ||||
| template <class T> | ||||
| void deserializeFromXMLStream(std::istream& in_archive_stream, T& output, | ||||
|                     const std::string& name = "data") { | ||||
|   boost::archive::xml_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> boost::serialization::make_nvp(name.c_str(), output); | ||||
|   in_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| // Serialization to binary format with named structures
 | ||||
| template<class T> | ||||
| std::string serializeBinary(const T& input, const std::string& name="data") { | ||||
| /// serializes to a string in XML
 | ||||
| template <class T> | ||||
| std::string serializeToXMLString(const T& input, | ||||
|                          const std::string& name = "data") { | ||||
|   std::ostringstream out_archive_stream; | ||||
|   boost::archive::binary_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << boost::serialization::make_nvp(name.c_str(), input); | ||||
|   serializeToXMLStream(input, out_archive_stream, name); | ||||
|   return out_archive_stream.str(); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| void deserializeBinary(const std::string& serialized, T& output, const std::string& name="data") { | ||||
| /// deserializes from a string in XML
 | ||||
| template <class T> | ||||
| void deserializeFromXMLString(const std::string& serialized, T& output, | ||||
|                     const std::string& name = "data") { | ||||
|   std::istringstream in_archive_stream(serialized); | ||||
|   boost::archive::binary_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> boost::serialization::make_nvp(name.c_str(), output); | ||||
|   deserializeFromXMLStream(in_archive_stream, output, name); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| bool serializeToBinaryFile(const T& input, const std::string& filename, const std::string& name="data") { | ||||
| /// serializes to an XML file
 | ||||
| template <class T> | ||||
| bool serializeToXMLFile(const T& input, const std::string& filename, | ||||
|                         const std::string& name = "data") { | ||||
|   std::ofstream out_archive_stream(filename.c_str()); | ||||
|   if (!out_archive_stream.is_open()) | ||||
|     return false; | ||||
|   boost::archive::binary_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << boost::serialization::make_nvp(name.c_str(), input); | ||||
|   if (!out_archive_stream.is_open()) return false; | ||||
|   serializeToXMLStream(input, out_archive_stream, name); | ||||
|   out_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| bool deserializeFromBinaryFile(const std::string& filename, T& output, const std::string& name="data") { | ||||
| /// deserializes from an XML file
 | ||||
| template <class T> | ||||
| bool deserializeFromXMLFile(const std::string& filename, T& output, | ||||
|                             const std::string& name = "data") { | ||||
|   std::ifstream in_archive_stream(filename.c_str()); | ||||
|   if (!in_archive_stream.is_open()) | ||||
|     return false; | ||||
|   boost::archive::binary_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> boost::serialization::make_nvp(name.c_str(), output); | ||||
|   if (!in_archive_stream.is_open()) return false; | ||||
|   deserializeFromXMLStream(in_archive_stream, output, name); | ||||
|   in_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| } // \namespace gtsam
 | ||||
| /// serializes to a string in XML
 | ||||
| template <class T> | ||||
| std::string serializeXML(const T& input, | ||||
|                          const std::string& name = "data") { | ||||
|   return serializeToXMLString(input, name); | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a string in XML
 | ||||
| template <class T> | ||||
| void deserializeXML(const std::string& serialized, T& output, | ||||
|                     const std::string& name = "data") { | ||||
|   deserializeFromXMLString(serialized, output, name); | ||||
| } | ||||
| ///@}
 | ||||
| 
 | ||||
| /** @name Binary Serialization
 | ||||
|  *  Serialization to binary format with named structures | ||||
|  */ | ||||
| ///@{
 | ||||
| /// serializes to a stream in binary
 | ||||
| template <class T> | ||||
| void serializeToBinaryStream(const T& input, std::ostream& out_archive_stream, | ||||
|                      const std::string& name = "data") { | ||||
|   boost::archive::binary_oarchive out_archive(out_archive_stream); | ||||
|   out_archive << boost::serialization::make_nvp(name.c_str(), input); | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a stream in binary
 | ||||
| template <class T> | ||||
| void deserializeFromBinaryStream(std::istream& in_archive_stream, T& output, | ||||
|                        const std::string& name = "data") { | ||||
|   boost::archive::binary_iarchive in_archive(in_archive_stream); | ||||
|   in_archive >> boost::serialization::make_nvp(name.c_str(), output); | ||||
| } | ||||
| 
 | ||||
| /// serializes to a string in binary
 | ||||
| template <class T> | ||||
| std::string serializeToBinaryString(const T& input, | ||||
|                             const std::string& name = "data") { | ||||
|   std::ostringstream out_archive_stream; | ||||
|   serializeToBinaryStream(input, out_archive_stream, name); | ||||
|   return out_archive_stream.str(); | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a string in binary
 | ||||
| template <class T> | ||||
| void deserializeFromBinaryString(const std::string& serialized, T& output, | ||||
|                        const std::string& name = "data") { | ||||
|   std::istringstream in_archive_stream(serialized); | ||||
|   deserializeFromBinaryStream(in_archive_stream, output, name); | ||||
| } | ||||
| 
 | ||||
| /// serializes to a binary file
 | ||||
| template <class T> | ||||
| bool serializeToBinaryFile(const T& input, const std::string& filename, | ||||
|                            const std::string& name = "data") { | ||||
|   std::ofstream out_archive_stream(filename.c_str()); | ||||
|   if (!out_archive_stream.is_open()) return false; | ||||
|   serializeToBinaryStream(input, out_archive_stream, name); | ||||
|   out_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a binary file
 | ||||
| template <class T> | ||||
| bool deserializeFromBinaryFile(const std::string& filename, T& output, | ||||
|                                const std::string& name = "data") { | ||||
|   std::ifstream in_archive_stream(filename.c_str()); | ||||
|   if (!in_archive_stream.is_open()) return false; | ||||
|   deserializeFromBinaryStream(in_archive_stream, output, name); | ||||
|   in_archive_stream.close(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /// serializes to a string in binary
 | ||||
| template <class T> | ||||
| std::string serializeBinary(const T& input, | ||||
|                             const std::string& name = "data") { | ||||
|   return serializeToBinaryString(input, name); | ||||
| } | ||||
| 
 | ||||
| /// deserializes from a string in binary
 | ||||
| template <class T> | ||||
| void deserializeBinary(const std::string& serialized, T& output, | ||||
|                        const std::string& name = "data") { | ||||
|   deserializeFromBinaryString(serialized, output, name); | ||||
| } | ||||
| ///@}
 | ||||
| 
 | ||||
| }  // namespace gtsam
 | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| #include <gtsam/base/serialization.h> | ||||
| 
 | ||||
| #include <boost/serialization/serialization.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| 
 | ||||
| 
 | ||||
| // whether to print the serialized text to stdout
 | ||||
|  | @ -40,22 +41,37 @@ T create() { | |||
|   return T(); | ||||
| } | ||||
| 
 | ||||
| // Creates or empties a folder in the build folder and returns the relative path
 | ||||
| boost::filesystem::path resetFilesystem( | ||||
|     boost::filesystem::path folder = "actual") { | ||||
|   boost::filesystem::remove_all(folder); | ||||
|   boost::filesystem::create_directory(folder); | ||||
|   return folder; | ||||
| } | ||||
| 
 | ||||
| // Templated round-trip serialization
 | ||||
| template<class T> | ||||
| void roundtrip(const T& input, T& output) { | ||||
|   // Serialize
 | ||||
|   std::string serialized = serialize(input); | ||||
|   if (verbose) std::cout << serialized << std::endl << std::endl; | ||||
| 
 | ||||
|   deserialize(serialized, output); | ||||
| } | ||||
| 
 | ||||
| // This version requires equality operator
 | ||||
| // Templated round-trip serialization using a file
 | ||||
| template<class T> | ||||
| void roundtripFile(const T& input, T& output) { | ||||
|   boost::filesystem::path path = resetFilesystem()/"graph.dat"; | ||||
|   serializeToFile(input, path.string()); | ||||
|   deserializeFromFile(path.string(), output); | ||||
| } | ||||
| 
 | ||||
| // This version requires equality operator and uses string and file round-trips
 | ||||
| template<class T> | ||||
| bool equality(const T& input = T()) { | ||||
|   T output = create<T>(); | ||||
|   T output = create<T>(), outputf = create<T>(); | ||||
|   roundtrip<T>(input,output); | ||||
|   return input==output; | ||||
|   roundtripFile<T>(input,outputf); | ||||
|   return (input==output) && (input==outputf); | ||||
| } | ||||
| 
 | ||||
| // This version requires Testable
 | ||||
|  | @ -77,20 +93,26 @@ bool equalsDereferenced(const T& input) { | |||
| // Templated round-trip serialization using XML
 | ||||
| template<class T> | ||||
| void roundtripXML(const T& input, T& output) { | ||||
|   // Serialize
 | ||||
|   std::string serialized = serializeXML<T>(input); | ||||
|   if (verbose) std::cout << serialized << std::endl << std::endl; | ||||
| 
 | ||||
|   // De-serialize
 | ||||
|   deserializeXML(serialized, output); | ||||
| } | ||||
| 
 | ||||
| // Templated round-trip serialization using XML File
 | ||||
| template<class T> | ||||
| void roundtripXMLFile(const T& input, T& output) { | ||||
|   boost::filesystem::path path = resetFilesystem()/"graph.xml"; | ||||
|   serializeToXMLFile(input, path.string()); | ||||
|   deserializeFromXMLFile(path.string(), output); | ||||
| } | ||||
| 
 | ||||
| // This version requires equality operator
 | ||||
| template<class T> | ||||
| bool equalityXML(const T& input = T()) { | ||||
|   T output = create<T>(); | ||||
|   T output = create<T>(), outputf = create<T>(); | ||||
|   roundtripXML<T>(input,output); | ||||
|   return input==output; | ||||
|   roundtripXMLFile<T>(input,outputf); | ||||
|   return (input==output) && (input==outputf); | ||||
| } | ||||
| 
 | ||||
| // This version requires Testable
 | ||||
|  | @ -112,20 +134,26 @@ bool equalsDereferencedXML(const T& input = T()) { | |||
| // Templated round-trip serialization using XML
 | ||||
| template<class T> | ||||
| void roundtripBinary(const T& input, T& output) { | ||||
|   // Serialize
 | ||||
|   std::string serialized = serializeBinary<T>(input); | ||||
|   if (verbose) std::cout << serialized << std::endl << std::endl; | ||||
| 
 | ||||
|   // De-serialize
 | ||||
|   deserializeBinary(serialized, output); | ||||
| } | ||||
| 
 | ||||
| // Templated round-trip serialization using Binary file
 | ||||
| template<class T> | ||||
| void roundtripBinaryFile(const T& input, T& output) { | ||||
|   boost::filesystem::path path = resetFilesystem()/"graph.bin"; | ||||
|   serializeToBinaryFile(input, path.string()); | ||||
|   deserializeFromBinaryFile(path.string(), output); | ||||
| } | ||||
| 
 | ||||
| // This version requires equality operator
 | ||||
| template<class T> | ||||
| bool equalityBinary(const T& input = T()) { | ||||
|   T output = create<T>(); | ||||
|   T output = create<T>(), outputf = create<T>(); | ||||
|   roundtripBinary<T>(input,output); | ||||
|   return input==output; | ||||
|   roundtripBinaryFile<T>(input,outputf); | ||||
|   return (input==output) && (input==outputf); | ||||
| } | ||||
| 
 | ||||
| // This version requires Testable
 | ||||
|  |  | |||
|  | @ -230,3 +230,50 @@ namespace std { | |||
| #ifdef ERROR | ||||
| #undef ERROR | ||||
| #endif | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
|   /// Convenience void_t as we assume C++11, it will not conflict the std one in C++17 as this is in `gtsam::`
 | ||||
|   template<typename ...> using void_t = void; | ||||
| 
 | ||||
|   /**
 | ||||
|    * A SFINAE trait to mark classes that need special alignment. | ||||
|    * | ||||
|    * This is required to make boost::make_shared and etc respect alignment, which is essential for the Python | ||||
|    * wrappers to work properly. | ||||
|    * | ||||
|    * Explanation | ||||
|    * ============= | ||||
|    * When a GTSAM type is not declared with the type alias `_eigen_aligned_allocator_trait = void`, the first template | ||||
|    * will be taken so `needs_eigen_aligned_allocator` will be resolved to `std::false_type`. | ||||
|    * | ||||
|    * Otherwise, it will resolve to the second template, which will be resolved to `std::true_type`. | ||||
|    * | ||||
|    * Please refer to `gtsam/base/make_shared.h` for an example. | ||||
|    */ | ||||
|   template<typename, typename = void_t<>> | ||||
|   struct needs_eigen_aligned_allocator : std::false_type { | ||||
|   }; | ||||
|   template<typename T> | ||||
|   struct needs_eigen_aligned_allocator<T, void_t<typename T::_eigen_aligned_allocator_trait>> : std::true_type { | ||||
|   }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * This marks a GTSAM object to require alignment. With this macro an object will automatically be allocated in aligned | ||||
|  * memory when one uses `gtsam::make_shared`. It reduces future misalignment problems that is hard to debug. | ||||
|  * See https://eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html for detailed explanation.
 | ||||
|  */ | ||||
| #define GTSAM_MAKE_ALIGNED_OPERATOR_NEW \ | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW \ | ||||
|   using _eigen_aligned_allocator_trait = void; | ||||
| 
 | ||||
| /**
 | ||||
|  * This marks a GTSAM object to require alignment. With this macro an object will automatically be allocated in aligned | ||||
|  * memory when one uses `gtsam::make_shared`. It reduces future misalignment problems that is hard to debug. | ||||
|  * See https://eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html for detailed explanation.
 | ||||
|  */ | ||||
| #define GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \ | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \ | ||||
|   using _eigen_aligned_allocator_trait = void; | ||||
|  |  | |||
|  | @ -162,7 +162,7 @@ private: | |||
|     NeedsToAlign = (sizeof(B) % 16) == 0 || (sizeof(R) % 16) == 0 | ||||
|   }; | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| }; | ||||
| 
 | ||||
| // Declare this to be both Testable and a Manifold
 | ||||
|  |  | |||
|  | @ -319,7 +319,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| template<class CAMERA> | ||||
|  |  | |||
|  | @ -212,7 +212,7 @@ class EssentialMatrix { | |||
|   /// @}
 | ||||
| 
 | ||||
|  public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| template<> | ||||
|  |  | |||
|  | @ -325,7 +325,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| // manifold traits
 | ||||
|  |  | |||
|  | @ -222,7 +222,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // end of class PinholeBaseK
 | ||||
| 
 | ||||
|  | @ -425,7 +425,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // end of class PinholePose
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -317,7 +317,7 @@ public: | |||
| 
 | ||||
| public: | ||||
|   // Align for Point2, which is either derived from, or is typedef, of Vector2
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; // Pose2
 | ||||
| 
 | ||||
| /** specialization for pose2 wedge function (generic template in Lie.h) */ | ||||
|  |  | |||
|  | @ -355,7 +355,7 @@ public: | |||
| #ifdef GTSAM_USE_QUATERNIONS | ||||
|   // Align if we are using Quaternions
 | ||||
|   public: | ||||
|     EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|     GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| #endif | ||||
| }; | ||||
| // Pose3 class
 | ||||
|  |  | |||
|  | @ -544,7 +544,7 @@ namespace gtsam { | |||
| #ifdef GTSAM_USE_QUATERNIONS | ||||
|   // only align if quaternion, Matrix3 has no alignment requirements
 | ||||
|   public: | ||||
|     EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|     GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| #endif | ||||
|   }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,8 +20,8 @@ | |||
| 
 | ||||
| #include <gtsam/base/Lie.h> | ||||
| #include <gtsam/base/Manifold.h> | ||||
| #include <gtsam/base/make_shared.h> | ||||
| #include <gtsam/dllexport.h> | ||||
| 
 | ||||
| #include <Eigen/Core> | ||||
| 
 | ||||
| #include <iostream> // TODO(frank): how to avoid? | ||||
|  | @ -54,7 +54,7 @@ class SO : public LieGroup<SO<N>, internal::DimensionSO(N)> { | |||
|   using VectorN2 = Eigen::Matrix<double, internal::NSquaredSO(N), 1>; | ||||
|   using MatrixDD = Eigen::Matrix<double, dimension, dimension>; | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(true) | ||||
| 
 | ||||
|  protected: | ||||
|   MatrixNN matrix_;  ///< Rotation matrix
 | ||||
|  |  | |||
|  | @ -214,7 +214,7 @@ private: | |||
|   /// @}
 | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| // Define GTSAM traits
 | ||||
|  |  | |||
|  | @ -215,7 +215,7 @@ struct CameraProjectionMatrix { | |||
| private: | ||||
|   const Matrix3 K_; | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -139,7 +139,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| /// traits
 | ||||
|  | @ -219,7 +219,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| /// traits
 | ||||
|  |  | |||
|  | @ -100,7 +100,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -210,7 +210,7 @@ public: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -332,7 +332,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // class CombinedImuFactor
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -171,7 +171,7 @@ private: | |||
| 
 | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   /// @}
 | ||||
| 
 | ||||
| }; // ConstantBias class
 | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ struct GTSAM_EXPORT PreintegratedRotationParams { | |||
| #ifdef GTSAM_USE_QUATERNIONS | ||||
|   // Align if we are using Quaternions
 | ||||
| public: | ||||
| 	EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 	GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  | @ -182,7 +182,7 @@ class GTSAM_EXPORT PreintegratedRotation { | |||
| #ifdef GTSAM_USE_QUATERNIONS | ||||
|   // Align if we are using Quaternions
 | ||||
|   public: | ||||
| 	  EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 	  GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -214,7 +214,7 @@ class GTSAM_EXPORT PreintegrationBase { | |||
| #endif | ||||
| 
 | ||||
|  public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| }  /// namespace gtsam
 | ||||
|  |  | |||
|  | @ -84,7 +84,7 @@ protected: | |||
| #ifdef GTSAM_USE_QUATERNIONS | ||||
|   // Align if we are using Quaternions
 | ||||
| public: | ||||
| 	EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 	GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -141,7 +141,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| } /// namespace gtsam
 | ||||
|  |  | |||
|  | @ -209,7 +209,7 @@ private: | |||
|  // Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
 | ||||
|  enum { NeedsToAlign = (sizeof(T) % 16) == 0 }; | ||||
|   public: | ||||
| 	  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| 	  GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| }; | ||||
| // ExpressionFactor
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -175,7 +175,7 @@ public: | |||
| 
 | ||||
|   /// @}
 | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|  | @ -265,7 +265,7 @@ public: | |||
|     traits<X>::Print(value_, "Value"); | ||||
|   } | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|  | @ -331,7 +331,7 @@ public: | |||
|     return traits<X>::Local(x1,x2); | ||||
|   } | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|  |  | |||
|  | @ -114,7 +114,7 @@ namespace gtsam { | |||
| 	// Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
 | ||||
| 	enum { NeedsToAlign = (sizeof(T) % 16) == 0 }; | ||||
|   public: | ||||
| 	EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
| 	GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
|   }; | ||||
| 
 | ||||
| } /// namespace gtsam
 | ||||
|  |  | |||
|  | @ -150,7 +150,7 @@ public: | |||
|     return constant_; | ||||
|   } | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| //-----------------------------------------------------------------------------
 | ||||
|  |  | |||
|  | @ -126,7 +126,7 @@ namespace gtsam { | |||
| 	  // Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
 | ||||
| 	  enum { NeedsToAlign = (sizeof(VALUE) % 16) == 0 }; | ||||
|     public: | ||||
|       EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
|       GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) | ||||
|   }; // \class BetweenFactor
 | ||||
| 
 | ||||
|   /// traits
 | ||||
|  |  | |||
|  | @ -105,7 +105,7 @@ private: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // \class EssentialMatrixConstraint
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -81,7 +81,7 @@ public: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -201,7 +201,7 @@ public: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // EssentialMatrixFactor2
 | ||||
| 
 | ||||
|  | @ -286,7 +286,7 @@ public: | |||
|   } | ||||
| 
 | ||||
| public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| // EssentialMatrixFactor3
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -189,7 +189,7 @@ namespace gtsam { | |||
|     } | ||||
| 
 | ||||
|   public: | ||||
|     EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|     GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| 
 | ||||
|   /// traits
 | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ public: | |||
|     return error; | ||||
|   } | ||||
| 
 | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| }; | ||||
| }  // namespace gtsam
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -81,7 +81,7 @@ protected: | |||
|   mutable FBlocks Fs; | ||||
| 
 | ||||
|  public: | ||||
|   EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||||
|   GTSAM_MAKE_ALIGNED_OPERATOR_NEW | ||||
| 
 | ||||
|   /// shorthand for a smart pointer to a factor
 | ||||
|   typedef boost::shared_ptr<This> shared_ptr; | ||||
|  |  | |||
|  | @ -0,0 +1,90 @@ | |||
| /**
 | ||||
|  *  @file   PoseToPointFactor.hpp | ||||
|  *  @brief  This factor can be used to track a 3D landmark over time by | ||||
|  *providing local measurements of its location. | ||||
|  *  @author David Wisth | ||||
|  **/ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gtsam/geometry/Point3.h> | ||||
| #include <gtsam/geometry/Pose3.h> | ||||
| #include <gtsam/nonlinear/NonlinearFactor.h> | ||||
| #include <ostream> | ||||
| 
 | ||||
| namespace gtsam { | ||||
| 
 | ||||
| /**
 | ||||
|  * A class for a measurement between a pose and a point. | ||||
|  * @addtogroup SLAM | ||||
|  */ | ||||
| class PoseToPointFactor : public NoiseModelFactor2<Pose3, Point3> { | ||||
|  private: | ||||
|   typedef PoseToPointFactor This; | ||||
|   typedef NoiseModelFactor2<Pose3, Point3> Base; | ||||
| 
 | ||||
|   Point3 measured_; /** the point measurement in local coordinates */ | ||||
| 
 | ||||
|  public: | ||||
|   // shorthand for a smart pointer to a factor
 | ||||
|   typedef boost::shared_ptr<PoseToPointFactor> shared_ptr; | ||||
| 
 | ||||
|   /** default constructor - only use for serialization */ | ||||
|   PoseToPointFactor() {} | ||||
| 
 | ||||
|   /** Constructor */ | ||||
|   PoseToPointFactor(Key key1, Key key2, const Point3& measured, | ||||
|                     const SharedNoiseModel& model) | ||||
|       : Base(model, key1, key2), measured_(measured) {} | ||||
| 
 | ||||
|   virtual ~PoseToPointFactor() {} | ||||
| 
 | ||||
|   /** implement functions needed for Testable */ | ||||
| 
 | ||||
|   /** print */ | ||||
|   virtual void print(const std::string& s, const KeyFormatter& keyFormatter = | ||||
|                                                DefaultKeyFormatter) const { | ||||
|     std::cout << s << "PoseToPointFactor(" << keyFormatter(this->key1()) << "," | ||||
|               << keyFormatter(this->key2()) << ")\n" | ||||
|               << "  measured: " << measured_.transpose() << std::endl; | ||||
|     this->noiseModel_->print("  noise model: "); | ||||
|   } | ||||
| 
 | ||||
|   /** equals */ | ||||
|   virtual bool equals(const NonlinearFactor& expected, | ||||
|                       double tol = 1e-9) const { | ||||
|     const This* e = dynamic_cast<const This*>(&expected); | ||||
|     return e != nullptr && Base::equals(*e, tol) && | ||||
|            traits<Point3>::Equals(this->measured_, e->measured_, tol); | ||||
|   } | ||||
| 
 | ||||
|   /** implement functions needed to derive from Factor */ | ||||
| 
 | ||||
|   /** vector of errors
 | ||||
|    * @brief Error = wTwi.inverse()*wPwp - measured_ | ||||
|    * @param wTwi The pose of the sensor in world coordinates | ||||
|    * @param wPwp The estimated point location in world coordinates | ||||
|    * | ||||
|    * Note: measured_ and the error are in local coordiantes. | ||||
|    */ | ||||
|   Vector evaluateError(const Pose3& wTwi, const Point3& wPwp, | ||||
|                        boost::optional<Matrix&> H1 = boost::none, | ||||
|                        boost::optional<Matrix&> H2 = boost::none) const { | ||||
|     return wTwi.transformTo(wPwp, H1, H2) - measured_; | ||||
|   } | ||||
| 
 | ||||
|   /** return the measured */ | ||||
|   const Point3& measured() const { return measured_; } | ||||
| 
 | ||||
|  private: | ||||
|   /** Serialization function */ | ||||
|   friend class boost::serialization::access; | ||||
|   template <class ARCHIVE> | ||||
|   void serialize(ARCHIVE& ar, const unsigned int /*version*/) { | ||||
|     ar& boost::serialization::make_nvp( | ||||
|         "NoiseModelFactor2", boost::serialization::base_object<Base>(*this)); | ||||
|     ar& BOOST_SERIALIZATION_NVP(measured_); | ||||
|   } | ||||
| 
 | ||||
| };  // \class PoseToPointFactor
 | ||||
| 
 | ||||
| }  // namespace gtsam
 | ||||
|  | @ -0,0 +1,86 @@ | |||
| /**
 | ||||
|  * @file   testPoseToPointFactor.cpp | ||||
|  * @brief | ||||
|  * @author David Wisth | ||||
|  * @date   June 20, 2020 | ||||
|  */ | ||||
| 
 | ||||
| #include <CppUnitLite/TestHarness.h> | ||||
| #include <gtsam/base/numericalDerivative.h> | ||||
| #include <gtsam_unstable/slam/PoseToPointFactor.h> | ||||
| 
 | ||||
| using namespace gtsam; | ||||
| using namespace gtsam::noiseModel; | ||||
| 
 | ||||
| /// Verify zero error when there is no noise
 | ||||
| TEST(PoseToPointFactor, errorNoiseless) { | ||||
|   Pose3 pose = Pose3::identity(); | ||||
|   Point3 point(1.0, 2.0, 3.0); | ||||
|   Point3 noise(0.0, 0.0, 0.0); | ||||
|   Point3 measured = t + noise; | ||||
| 
 | ||||
|   Key pose_key(1); | ||||
|   Key point_key(2); | ||||
|   PoseToPointFactor factor(pose_key, point_key, measured, | ||||
|                            Isotropic::Sigma(3, 0.05)); | ||||
|   Vector expectedError = Vector3(0.0, 0.0, 0.0); | ||||
|   Vector actualError = factor.evaluateError(pose, point); | ||||
|   EXPECT(assert_equal(expectedError, actualError, 1E-5)); | ||||
| } | ||||
| 
 | ||||
| /// Verify expected error in test scenario
 | ||||
| TEST(PoseToPointFactor, errorNoise) { | ||||
|   Pose3 pose = Pose3::identity(); | ||||
|   Point3 point(1.0, 2.0, 3.0); | ||||
|   Point3 noise(-1.0, 0.5, 0.3); | ||||
|   Point3 measured = t + noise; | ||||
| 
 | ||||
|   Key pose_key(1); | ||||
|   Key point_key(2); | ||||
|   PoseToPointFactor factor(pose_key, point_key, measured, | ||||
|                            Isotropic::Sigma(3, 0.05)); | ||||
|   Vector expectedError = noise; | ||||
|   Vector actualError = factor.evaluateError(pose, point); | ||||
|   EXPECT(assert_equal(expectedError, actualError, 1E-5)); | ||||
| } | ||||
| 
 | ||||
| /// Check Jacobians are correct
 | ||||
| TEST(PoseToPointFactor, jacobian) { | ||||
|   // Measurement
 | ||||
|   gtsam::Point3 l_meas = gtsam::Point3(1, 2, 3); | ||||
| 
 | ||||
|   // Linearisation point
 | ||||
|   gtsam::Point3 p_t = gtsam::Point3(-5, 12, 2); | ||||
|   gtsam::Rot3 p_R = gtsam::Rot3::RzRyRx(1.5 * M_PI, -0.3 * M_PI, 0.4 * M_PI); | ||||
|   Pose3 p(p_R, p_t); | ||||
| 
 | ||||
|   gtsam::Point3 l = gtsam::Point3(3, 0, 5); | ||||
| 
 | ||||
|   // Factor
 | ||||
|   Key pose_key(1); | ||||
|   Key point_key(2); | ||||
|   SharedGaussian noise = noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.1)); | ||||
|   PoseToPointFactor factor(pose_key, point_key, l_meas, noise); | ||||
| 
 | ||||
|   // Calculate numerical derivatives
 | ||||
|   auto f = boost::bind(&PoseToPointFactor::evaluateError, factor, _1, _2, | ||||
|                        boost::none, boost::none); | ||||
|   Matrix numerical_H1 = numericalDerivative21<Vector, Pose3, Point3>(f, p, l); | ||||
|   Matrix numerical_H2 = numericalDerivative22<Vector, Pose3, Point3>(f, p, l); | ||||
| 
 | ||||
|   // Use the factor to calculate the derivative
 | ||||
|   Matrix actual_H1; | ||||
|   Matrix actual_H2; | ||||
|   factor.evaluateError(p, l, actual_H1, actual_H2); | ||||
| 
 | ||||
|   // Verify we get the expected error
 | ||||
|   EXPECT_TRUE(assert_equal(numerical_H1, actual_H1, 1e-8)); | ||||
|   EXPECT_TRUE(assert_equal(numerical_H2, actual_H2, 1e-8)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| int main() { | ||||
|   TestResult tr; | ||||
|   return TestRegistry::runAllTests(tr); | ||||
| } | ||||
| /* ************************************************************************* */ | ||||
|  | @ -350,7 +350,10 @@ void Module::emit_cython_pxd(FileWriter& pxdFile) const { | |||
|                  "        T* get()\n" | ||||
|                  "        long use_count() const\n" | ||||
|                  "        T& operator*()\n\n" | ||||
|                  "    cdef shared_ptr[T] dynamic_pointer_cast[T,U](const shared_ptr[U]& r)\n" | ||||
|                  "    cdef shared_ptr[T] dynamic_pointer_cast[T,U](const shared_ptr[U]& r)\n\n"; | ||||
| 
 | ||||
|   // gtsam alignment-friendly shared_ptr
 | ||||
|   pxdFile.oss << "cdef extern from \"gtsam/base/make_shared.h\" namespace \"gtsam\":\n" | ||||
|                  "    cdef shared_ptr[T] make_shared[T](const T& r)\n\n"; | ||||
| 
 | ||||
|   for(const TypedefPair& types: typedefs) | ||||
|  |  | |||
|  | @ -16,6 +16,8 @@ cdef extern from "boost/shared_ptr.hpp" namespace "boost": | |||
|         T& operator*() | ||||
| 
 | ||||
|     cdef shared_ptr[T] dynamic_pointer_cast[T,U](const shared_ptr[U]& r) | ||||
| 
 | ||||
| cdef extern from "gtsam/base/make_shared.h" namespace "gtsam": | ||||
|     cdef shared_ptr[T] make_shared[T](const T& r) | ||||
| 
 | ||||
| cdef extern from "gtsam/geometry/Point2.h" namespace "gtsam": | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue