cpp_drawing/main.cpp

112 lines
2.6 KiB
C++

#include <iostream>
#include <stdexcept>
#include <tuple>
#include "input_file.hpp"
#include "renderers/pgm_renderer.hpp"
#include "renderers/svg_renderer.hpp"
#include <charconv>
/**
* @brief Render shapes using a specific renderer and save to a file
*
* @tparam T Renderer type
* @param shapes Shapes to render
* @param path Output file path
* @param width Width
* @param height Height
*/
template <class T>
void Render(const shapes::Group& shapes, const std::filesystem::path& path, size_t width, size_t height)
{
T renderer(width, height);
shapes.Draw(renderer);
renderer.Save(path);
}
/**
* @brief Parse a single dimension from a string
*
* @param start Pointer to the start of the dimension string
* @param end Pointer to the end of the dimension string
* @return Parsed dimension
*/
static size_t ParseDim(const char* start, const char* end)
{
size_t val;
auto [ptr, ec] = std::from_chars(start, end, val);
if (ec != std::errc())
{
throw std::runtime_error("Cannot parse size");
}
return val;
}
/**
* Parse a size string
*
* @param sizeStr Size string in the format of `<width>x<height>`
* @return Tuple of width and height
*/
static std::tuple<size_t, size_t> ParseSize(const std::string& sizeStr)
{
auto xPos = sizeStr.find('x');
if (xPos == std::string::npos)
throw std::runtime_error("Size must be in format of <width>x<height>");
size_t width = ParseDim(sizeStr.data(), sizeStr.data() + xPos);
size_t height = ParseDim(sizeStr.data() + xPos + 1, sizeStr.data() + sizeStr.size());
return std::make_tuple(width, height);
}
/**
* @brief Run the drawing process
*/
static void Run(const std::string& inputFile, const std::string& outputFile, const std::string& sizeStr)
{
try
{
auto [width, height] = ParseSize(sizeStr);
InputFile file(inputFile);
shapes::Group shapes = file.Parse();
if (outputFile.ends_with(".svg"))
Render<SvgRenderer>(shapes, outputFile, width, height);
else
Render<PgmRenderer>(shapes, outputFile, width, height);
std::cout << "OK" << std::endl;
std::cout << file.GetNumProcessedCmds() << std::endl;
}
catch (const std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
}
/**
* @brief Main entry point
*/
int main(int argc, char** argv)
{
if (argc < 4)
{
const char* command = "drawing";
if (argc > 0)
command = argv[0];
std::cerr << "Usage: " << command << " <input_file> <output_file> <size>" << std::endl;
return 1;
}
Run(argv[1], argv[2], argv[3]);
return 0;
}