众所周知,python可以使用matplotlib库实现比较简单的绘图操作。
本例使用C++ 调用python的matplotlib库,实现简单的绘图操作。
本例使用conanio/gcc9的镜像来实现使用C++调用python matplotlib库的操作。
使用conan镜像的原因是比较容易完成对C++的依赖设置,而且大家也比较容易克隆出相同的环境来实现效果。
本例的实现是使用docker镜像来完成,代码是跨平台可用的。
实现步骤,
- 在coanio/gcc9容器中安装matplotlib
pip install matplotlib
- 使用如下CMakeLists.txt文件
注意需要链接上该环境中的python3.7m的相关头文件和库文件
cmake_minimum_required(VERSION 3.3)
project(45_matplot_lib)
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig/")
set ( CMAKE_CXX_FLAGS "-pthread")
set(CMAKE_CXX_STANDARD 17)
add_definitions(-g)
add_definitions(-DSAVE_PERCEPTION_CONCAT_IMG)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
include_directories(${INCLUDE_DIRS} /opt/pyenv/versions/3.7.13/include/python3.7m/)
LINK_DIRECTORIES(${LINK_DIRS} /opt/pyenv/versions/3.7.13/lib/)
file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file( GLOB source_files ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
foreach( main_file ${main_file_list} )
file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
string(REPLACE ".cpp" "" file ${filename})
add_executable(${file} ${main_file} ${source_files})
target_link_libraries(${file} ${CONAN_LIBS} pthread python3.7m)
endforeach( main_file ${main_file_list})
conanfile.txt
本例使用了boost/algorithm/string.hpp中的相关算法,来简化我们的字符串操作,所以需要安装boost依赖。nlohmannn_json库不需要[可选]
[requires]
nlohmann_json/3.11.3
boost/1.72.0
[generators]
cmake
相关代码,
consts.h
#ifndef _FREDRIC_CONST_H_
#define _FREDRIC_CONST_H_
#include <string>
extern std::string PointTemp;
#endif
consts.cc
#include "consts.h"
std::string PointTemp = R"("p{0}": { "x": {1}, "y": {2}},)";
point.h
#ifndef _FREDRIC_POINT_H_
#define _FREDRIC_POINT_H_
struct point_t {
float x;
float y;
};
struct parking_lot_t {
point_t p0;
point_t p1;
point_t p2;
point_t p3;
};
#endif
matplotlibcpp.h 请从这里下载
https://github.com/lava/matplotlib-cpp/tree/master
main.cpp
#include <iostream>
#include <sstream>
#include "point.h"
#include "consts.h"
#include <vector>
#include <boost/algorithm/string.hpp>
#define WITHOUT_NUMPY
#include "matplotlibcpp.h"
namespace plt = matplotlibcpp;
enum ps_type_t {
TWO_VERTICALS,
TWO_VERTICALS_STEPPED,
VERTICAL_AND_HORIZONTAL,
MULTI_VERTICALS_STEPPED
};
struct parking_lot_maker_t {
std::vector<parking_lot_t> two_verticals() {
std::vector<parking_lot_t> results;
point_t p0 {4, -2.2};
point_t p1 {4, -2.2 - 5.5};
point_t p2 {4 + 2.4, -2.2 - 5.5};
point_t p3 {4 + 2.4, -2.2};
parking_lot_t vert {p0, p1, p2, p3};
point_t h_p0 {p3.x + 0.3 + 5.5, p3.y};
point_t h_p1 {p3.x + 0.3, p3.y};
point_t h_p2 {h_p1.x, h_p1.y - 2.4};
point_t h_p3 {h_p2.x + 5.5, h_p2.y};
parking_lot_t hori {h_p0, h_p1, h_p2, h_p3};
results.push_back(vert);
results.push_back(hori);
return results;
}
std::vector<parking_lot_t> two_verticals_stepped() {
std::vector<parking_lot_t> results;
point_t p0 {4, -2.2};
point_t p1 {4, -2.2 - 5.5};
point_t p2 {4 + 2.4, -2.2 - 5.5};
point_t p3 {4 + 2.4, -2.2};
parking_lot_t vert {p0, p1, p2, p3};
point_t h_p0 {p3.x + 0.3 + 5.5, p3.y+0.4};
point_t h_p1 {p3.x + 0.3, h_p0.y};
point_t h_p2 {h_p1.x, h_p1.y - 2.4 + 0.4};
point_t h_p3 {h_p2.x + 5.5, h_p2.y};
parking_lot_t hori {h_p0, h_p1, h_p2, h_p3};
results.push_back(vert);
results.push_back(hori);
return results;
}
std::vector<parking_lot_t> vertical_and_horizontal() {
std::vector<parking_lot_t> results;
point_t p0 {4, -2.2};
point_t p1 {4, -2.2 - 5.5};
point_t p2 {4 + 2.4, -2.2 - 5.5};
point_t p3 {4 + 2.4, -2.2};
parking_lot_t vert {p0, p1, p2, p3};
point_t v_p0 {p3.x + 0.3, p3.y};
point_t v_p1 {v_p0.x, v_p0.y - 2.4};
point_t v_p2 {v_p1.x + 5.5, v_p1.y};
point_t v_p3 {v_p2.x, v_p2.y + 2.4};
parking_lot_t vert1 {v_p0, v_p1, v_p2, v_p3};
results.push_back(vert);
results.push_back(vert1);
return results;
}
std::vector<parking_lot_t> multi_verticals_stepped() {
std::vector<parking_lot_t> results;
point_t p0 {4, -2.2};
point_t p1 {4, -2.2 - 5.5};
point_t p2 {4 + 2.4, -2.2 - 5.5};
point_t p3 {4 + 2.4, -2.2};
parking_lot_t vert {p0, p1, p2, p3};
results.push_back(vert);
for(std::size_t i=1; i<=3; ++i) {
parking_lot_t vert1 {{p0.x + i*(0.3 + 2.4), p0.y + i* 0.4}, {p1.x + i*(0.3 + 2.4), p1.y + i* 0.4},
{p2.x +i*(0.3 + 2.4), p2.y + i * 0.4}, {p3.x + i*(0.3 + 2.4), p3.y + i* 0.4}};
results.push_back(vert1);
}
return results;
}
void print_a_plot(parking_lot_t const& ps) {
std::string replaced_0_str = boost::algorithm::replace_all_copy(PointTemp, "{0}", "0");
boost::algorithm::replace_all(replaced_0_str, "{1}", std::to_string(ps.p0.x));
boost::algorithm::replace_all(replaced_0_str, "{2}", std::to_string(ps.p0.y));
std::string replaced_1_str = boost::algorithm::replace_all_copy(PointTemp, "{0}", "1");
boost::algorithm::replace_all(replaced_1_str, "{1}", std::to_string(ps.p1.x));
boost::algorithm::replace_all(replaced_1_str, "{2}", std::to_string(ps.p1.y));
std::string replaced_2_str = boost::algorithm::replace_all_copy(PointTemp, "{0}", "2");
boost::algorithm::replace_all(replaced_2_str, "{1}", std::to_string(ps.p2.x));
boost::algorithm::replace_all(replaced_2_str, "{2}", std::to_string(ps.p2.y));
std::string replaced_3_str = boost::algorithm::replace_all_copy(PointTemp, "{0}", "3");
boost::algorithm::replace_all(replaced_3_str, "{1}", std::to_string(ps.p3.x));
boost::algorithm::replace_all(replaced_3_str, "{2}", std::to_string(ps.p3.y));
std::cout << replaced_0_str << replaced_1_str << replaced_2_str << replaced_3_str << std::endl;
}
void plot_and_save_plot_file(parking_lot_t const& ps) {
std::vector<float> x_values;
std::vector<float> y_values;
x_values.push_back(ps.p0.x); x_values.push_back(ps.p1.x);
x_values.push_back(ps.p2.x); x_values.push_back(ps.p3.x);
y_values.push_back(ps.p0.y); y_values.push_back(ps.p1.y);
y_values.push_back(ps.p2.y); y_values.push_back(ps.p3.y);
plt::scatter(x_values, y_values, 50.0);
}
void save_results(std::string const& title, std::vector<parking_lot_t> const& results) {
plt::clf();
std::cout << title << "========" << std::endl;
for(auto const& ps: results) {
print_a_plot(ps);
plot_and_save_plot_file(ps);
}
std::stringstream result_ss;
result_ss << title << ".png";
plt::save(result_ss.str());
std::cout << title << "========" << std::endl;
std::cout << std::endl;
}
void operator()(ps_type_t type_) {
switch (type_) {
case TWO_VERTICALS:{
auto res = two_verticals();
save_results("Two verticals", res);
}
break;
case TWO_VERTICALS_STEPPED:{
auto res = two_verticals_stepped();
save_results("Two verticals stepped", res);
}
break;
case VERTICAL_AND_HORIZONTAL: {
auto res = vertical_and_horizontal();
save_results("Vertical and horizontal", res);
}
break;
case MULTI_VERTICALS_STEPPED: {
auto res = multi_verticals_stepped();
save_results("Multi verticals stepped", res);
}
default:
break;
}
}
};
int main(int argc, char* argv[]) {
parking_lot_maker_t p_lot_maker;
p_lot_maker(ps_type_t::TWO_VERTICALS);
p_lot_maker(ps_type_t::TWO_VERTICALS_STEPPED);
p_lot_maker(ps_type_t::VERTICAL_AND_HORIZONTAL);
p_lot_maker(ps_type_t::MULTI_VERTICALS_STEPPED);
return EXIT_SUCCESS;
}
程序输出如下