#include "pds.hpp" #include "graphio.hpp" #include "draw_grid.hpp" #include #include #include #include void writeLayout(const pds::Layout& layout, const std::string& filename) { FILE* outfile = fopen(filename.c_str(), "wb"); if (outfile == nullptr) throw std::system_error(std::error_code(errno, std::system_category())); fmt::print(outfile, "Layout V1.0\n"); for (auto [k, v]: layout) { fmt::print(outfile, "{} {} {}\n", k, v.x, v.y); } fclose(outfile); } struct ParseError : std::exception { std::string reason; ParseError(const std::string& reason, size_t line) : reason(fmt::format("{}: {}", line, reason)) { } const char * what() const noexcept override { return reason.c_str(); } }; std::vector split(const std::string_view& in, char delim) { std::vector pieces; size_t start = 0; size_t end; while (start != std::string::npos) { end = in.find(delim, start); pieces.emplace_back(in.substr(start, end - start)); if (end == std::string::npos) { start = std::string::npos; } else { start = end + 1; } } return pieces; } pds::Layout readLayout(const std::string& filename) { std::ifstream infile(filename); std::string line; size_t lineno = 0; pds::Layout layout; std::getline(infile, line); ++lineno; if (line != "Layout V1.0") throw ParseError { fmt::format("unknown format: {}", line), lineno }; while (infile) { std::getline(infile, line); ++lineno; auto pieces = split(line, ' '); if (pieces.size() == 1 && pieces[0] == "") continue; // empty line if (pieces.size() != 3) throw ParseError { "not a triple", lineno }; try { long v = std::stoi(std::string{pieces[0]}); double x = std::stoi(std::string{pieces[1]}); double y = std::stoi(std::string{pieces[2]}); layout[v] = {x, y}; } catch(const std::exception& ex) { throw ParseError { fmt::format("could not read number: {}", ex.what()), lineno }; } } return layout; } void restrictLayout(pds::Layout& layout, const pds::PowerGrid& graph) { pds::set ids = ranges::transform_view(graph.vertices(), [&graph](auto v) { return graph[v].id; }) | ranges::to>; erase_if(layout,[&ids](const auto& kv) { return !ids.contains(kv.first);}); } int main(int argc, const char** argv) { namespace po = boost::program_options; using std::string; using namespace pds; po::options_description desc; desc.add_options() ("layout,l", po::value(), "load layout from file") ("save-layout,s", po::value(), "save layout to file") ("graph,g", po::value()->required(), "graph file") ("draw,d", po::value(), "create graph svg file") ("layout-bounds,b", "use bounds from layout for drawing") ("help,h", "show this help") ; po::positional_options_description pos; pos.add("graph", 1); po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).positional(pos).run(), vm); if (vm.count("help")) { desc.print(std::cout); return EXIT_FAILURE; } auto graph = readAutoGraph(vm["graph"].as()); Layout layout; if (vm.count("layout")) { layout = readLayout(vm["layout"].as()); if (!vm.count("layout-bounds")) { restrictLayout(layout, graph); } } else { layout = layoutGraph(graph); } if (vm.count("draw")) { PdsState state(graph); drawGrid(state, vm["draw"].as(), layout); } if (vm.count("save-layout")) { writeLayout(layout, vm["save-layout"].as()); } }