├── .idea ├── .name ├── fmt-eigen.iml ├── vcs.xml ├── .gitignore ├── misc.xml ├── modules.xml └── editor.xml ├── CMakeLists.txt ├── example.cpp ├── README.md └── fmt_eigen.h /.idea/.name: -------------------------------------------------------------------------------- 1 | example -------------------------------------------------------------------------------- /.idea/fmt-eigen.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(example) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | # use without ROS, and pure fmt 7 | # first install fmt from https://github.com/fmtlib/fmt 8 | 9 | find_package(fmt REQUIRED) 10 | add_executable(example example.cpp) 11 | target_link_libraries(example 12 | fmt::fmt 13 | ) 14 | 15 | 16 | # use with rosfmt 17 | # first install rosfmt with: sudo apt install ros-noetic-rosfmt 18 | 19 | #set(rosfmt_DIR /opt/ros/noetic/share/rosfmt/cmake) 20 | #find_package(rosfmt REQUIRED) 21 | #include_directories(${rosfmt_INCLUDE_DIRS}) 22 | #add_executable(example example.cpp) 23 | #target_link_libraries(example 24 | # ${rosfmt_LIBRARIES} 25 | #) 26 | 27 | 28 | # use with catkin and rosfmt 29 | # first install rosfmt with: sudo apt install ros-noetic-rosfmt 30 | # catkin_make 31 | #find_package(catkin REQUIRED COMPONENTS 32 | # roscpp 33 | # rosfmt) 34 | #include_directories(${catkin_INCLUDE_DIRS}) 35 | #add_executable(example example.cpp) 36 | #target_link_libraries(example 37 | # ${catkin_LIBRARIES} 38 | #) -------------------------------------------------------------------------------- /example.cpp: -------------------------------------------------------------------------------- 1 | #include "fmt_eigen.h" 2 | #include "fmt/color.h" 3 | 4 | int main() { 5 | Eigen::Matrix matrix; 6 | matrix << 1.234567, 2.345678, 3.456789, 4.567890; 7 | 8 | Eigen::Matrix transposed = matrix.transpose(); 9 | Eigen::Matrix int_matrix; 10 | int_matrix << 1, 2, 3, 4; 11 | 12 | Eigen::Vector3d vec(1, 2, 3); 13 | 14 | fmt::print("Matrix:\n{}\n vector:\n{}\n", matrix, vec); 15 | fmt::print("Int Matrix:\n{}\n", int_matrix); 16 | 17 | fmt::print("Matrix:\n{0:.3f}\n vector:\n{1:.4f}\n", matrix, vec); // Specify precision of 4 18 | 19 | fmt::print("Matrix Transposed:\n{:.4f}\n", transposed); // Specify precision of 4 20 | fmt::print("Matrix col or row:\n{:.4f}\n", matrix.col(0)); // Specify precision of 4 21 | fmt::print("Matrix Bolck:\n{}\n", matrix.block<1, 1>(0, 0)); // Specify precision of 4 22 | fmt::print("Matrix Diagonal:\n{}\n", matrix.diagonal()); // Specify precision of 4 23 | 24 | fmt::print(fg(fmt::color::steel_blue), "Matrix:\n{}\n vector:\n{}\n", matrix, vec); 25 | fmt::print(bg(fmt::color::lime_green) | fg(fmt::color::indian_red), 26 | "Matrix:\n{0:.3f}\n vector:\n{1:.4f}\n", matrix, vec); 27 | fmt::print(fg(fmt::color::gold) | fmt::emphasis::blink, "Matrix Transposed:\n{:.4f}\n", transposed); 28 | fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::bold, "Matrix Transposed:\n{:.4f}\n", transposed); 29 | 30 | 31 | getchar(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /.idea/editor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fmt-eigen 2 | A header-only formatter function customized for the Eigen library. 3 | 4 | ## Why fmt 5 | 6 | The `fmt` library offers several advantages over traditional methods of formatting and printing data in C++. In this chapter, we will explore why `fmt` is preferred for these tasks. 7 | 8 | #### Easy to Format 9 | 10 | With `fmt`, formatting and printing data becomes simple and intuitive. Using the `fmt::print` function, you can easily format output by providing values and placeholders within the format string. 11 | 12 | #### Type-Safe and Type-Free Printing 13 | 14 | `fmt` supports a wide range of data types, making it type-safe and eliminating the need for explicit format specifiers. It automatically handles the formatting based on the provided arguments. 15 | 16 | #### Fast Print Performance 17 | 18 | `fmt` is highly optimized for speed, often surpassing the performance of `cout` by more than **10 times**. Its efficient implementation and utilization of modern techniques contribute to its superior performance. 19 | 20 | ## Usage 21 | 22 | Copy the header file `fmt_eigen.h` to your project or copy to the `fmt` library path 23 | 24 | ```bash 25 | sudo cp ./fmt_eigen.h /usr/local/include/fmt 26 | ``` 27 | 28 | Include the header file `fmt_eigen.h` in your code 29 | 30 | ```cpp 31 | #include "fmt_eigen.h" 32 | ``` 33 | 34 | Then you can easily print `Eigen` types with `fmt::print` function 35 | 36 | ```cpp 37 | fmt::print("Matrix:\n{}\n vector:\n{}\n", matrix, vec); 38 | ``` 39 | 40 | Control the printing precision: 41 | 42 | ``` 43 | fmt::print("Matrix:\n{0:.3f}\n vector:\n{1:.4f}\n", matrix, vec); // Specify precision of 4 44 | ``` 45 | 46 | and also support the `block`, `Diagonal`, `Transpose` functions. 47 | 48 | ```cpp 49 | fmt::print("Matrix Transposed:\n{:.4f}\n", transposed); // Specify precision of 4 50 | fmt::print("Matrix col or row:\n{:.4f}\n", matrix.col(0)); // Specify precision of 4 51 | fmt::print("Matrix Bolck:\n{}\n", matrix.block<1,1>(0,0)); // Specify precision of 4 52 | fmt::print("Matrix Diagonal:\n{}\n", matrix.diagonal()); // Specify precision of 4 53 | ``` 54 | 55 | Take advantage of the colorful printing inherent to `fmt::print`: 56 | 57 | ```cpp 58 | fmt::print(fg(fmt::color::steel_blue), "Matrix:\n{}\n vector:\n{}\n", matrix, vec); 59 | fmt::print(bg(fmt::color::lime_green)|fg(fmt::color::indian_red), 60 | "Matrix:\n{0:.3f}\n vector:\n{1:.4f}\n", matrix, vec); 61 | fmt::print(fg(fmt::color::gold)|fmt::emphasis::blink, "Matrix Transposed:\n{:.4f}\n", transposed); 62 | fmt::print(fg(fmt::color::steel_blue)|fmt::emphasis::bold, "Matrix Transposed:\n{:.4f}\n", transposed); 63 | ``` 64 | 65 | For more details and examples, please refer to the `example.cpp` file and the user guide of fmt at https://hackingcpp.com/cpp/libs/fmt.html. 66 | 67 | ## Install fmt 68 | 69 | There are three ways to include `libfmt` in your project. 70 | 71 | ### Use with ROS and catkin 72 | 73 | For ROS users (tested with ROS Noetic), the easiest way to install `fmt` is by installing `rosfmt`: 74 | 75 | ```bash 76 | sudo apt-get install ros-noetic-rosfmt 77 | ``` 78 | 79 | To link `fmt` in your project, there are two ways provided. The first way is to use `catkin`: 80 | 81 | ```cmake 82 | find_package(catkin REQUIRED COMPONENTS 83 | roscpp 84 | rosfmt) 85 | include_directories(${catkin_INCLUDE_DIRS}) 86 | add_executable(example example.cpp) 87 | target_link_libraries(example 88 | ${catkin_LIBRARIES} 89 | ) 90 | ``` 91 | 92 | The second way is to use pure CMake: 93 | 94 | ```cmake 95 | set(rosfmt_DIR /opt/ros/noetic/share/rosfmt/cmake) 96 | find_package(rosfmt REQUIRED) 97 | include_directories(${rosfmt_INCLUDE_DIRS}) 98 | add_executable(example example.cpp) 99 | target_link_libraries(example 100 | ${rosfmt_LIBRARIES} 101 | ) 102 | ``` 103 | 104 | ### ROS-free 105 | 106 | For non-ROS users, you can install `libfmt` using the following commands: 107 | 108 | ```bash 109 | sudo add-apt-repository universe 110 | sudo apt update 111 | sudo apt install libfmt-dev 112 | ``` 113 | 114 | Alternatively, you can download the source code and compile it: 115 | 116 | ```bash 117 | git clone https://github.com/fmtlib/fmt.git 118 | cd fmt 119 | mkdir build 120 | cd build 121 | cmake .. 122 | make 123 | sudo make install 124 | ``` 125 | 126 | To add `libfmt` to your project's `CMakelists.txt`, use the following: 127 | 128 | ```cmake 129 | find_package(fmt REQUIRED) 130 | add_executable(example example.cpp) 131 | target_link_libraries(example 132 | fmt::fmt 133 | ) 134 | ``` 135 | -------------------------------------------------------------------------------- /fmt_eigen.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 Yunfan REN (renyf@connect.hku.hk) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef FMT_EIGEN_HPP 26 | #define FMT_EIGEN_HPP 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | template 35 | class MatrixFormatter : fmt::formatter { 36 | private: 37 | int precision = 6; // Default precision if not specified 38 | public: 39 | // Parse the format string to extract the precision 40 | template 41 | auto parse(ParseContext &ctx) { 42 | auto it = ctx.begin(); 43 | auto end = ctx.end(); 44 | // Check if precision is specified in the format string 45 | std::string input_str = std::string(it, end); 46 | std::regex re(R"(\.(\d+))"); 47 | std::smatch match; 48 | if (std::regex_search(input_str, match, re)) { 49 | precision = std::stoi(match[1]); 50 | } 51 | while (it != end && *it != '}') it++; // Skip to the end of the range 52 | // Return the iterator after parsing 53 | return it; 54 | } 55 | 56 | template 57 | typename std::enable_if::value>::type 58 | format_element(Scalar value, FormatContext &ctx) { 59 | fmt::format_to(ctx.out(), "{:.{}f} ", value, precision); 60 | } 61 | 62 | template 63 | typename std::enable_if::value>::type 64 | format_element(Scalar value, FormatContext &ctx) { 65 | fmt::format_to(ctx.out(), "{:d} ", value); 66 | } 67 | 68 | // Format the matrix with the specified precision 69 | template 70 | auto format(const MatrixType &matrix, FormatContext &ctx) { 71 | for (int i = 0; i < matrix.rows(); i++) { 72 | for (int j = 0; j < matrix.cols(); j++) { 73 | format_element(matrix(i, j), ctx); 74 | } 75 | if (i != matrix.rows() - 1) { 76 | fmt::format_to(ctx.out(), "\n"); 77 | } 78 | } 79 | return ctx.out(); 80 | } 81 | }; 82 | 83 | /// Specialize the formatter for Eigen::Matrix 84 | template 85 | struct fmt::formatter> : 86 | MatrixFormatter> { 87 | }; 88 | 89 | /// Specialize the formatter for Eigen::Transpose 90 | template 91 | struct fmt::formatter> : MatrixFormatter> { 92 | }; 93 | 94 | /// Specialize the formatter for Eigen::Block 95 | template 96 | struct fmt::formatter, BlockRows, BlockCols, InnerPanel>> : 97 | MatrixFormatter, BlockRows, BlockCols, InnerPanel>> { 98 | }; 99 | 100 | /// Specialize the formatter for Eigen::Diagno 101 | template 102 | struct fmt::formatter>> : 103 | MatrixFormatter>> { 104 | }; 105 | 106 | #endif 107 | --------------------------------------------------------------------------------