├── .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 |
5 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |
--------------------------------------------------------------------------------