From 1252624c05f864957ec442484e53bc7903c56560 Mon Sep 17 00:00:00 2001 From: nkwn Date: Sat, 6 Jan 2024 21:08:02 +0700 Subject: [PATCH] Add viewbox class and handle some input cases (#34) authored-by: hoangfitus --- src/Graphics.hpp | 1 + src/Parser.cpp | 21 ++++++++------- src/Parser.hpp | 5 ++-- src/graphics/ViewBox.cpp | 13 +++++++++ src/graphics/ViewBox.hpp | 58 ++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 33 ++++++++++++++++------- 6 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 src/graphics/ViewBox.cpp create mode 100644 src/graphics/ViewBox.hpp diff --git a/src/Graphics.hpp b/src/Graphics.hpp index e5e1937..e7c9168 100644 --- a/src/Graphics.hpp +++ b/src/Graphics.hpp @@ -13,5 +13,6 @@ #include "graphics/RadialGradient.hpp" #include "graphics/Rect.hpp" #include "graphics/Text.hpp" +#include "graphics/ViewBox.hpp" #endif // GRAPHICS_HPP_ diff --git a/src/Parser.cpp b/src/Parser.cpp index b883b93..6df98d3 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -209,8 +209,9 @@ SVGElement *Parser::parseElements(std::string file_name) { std::string viewbox = getAttribute(svg, "viewBox"); if (viewbox != "") { std::stringstream ss(viewbox); - ss >> this->viewbox.first.x >> this->viewbox.first.y >> - this->viewbox.second.x >> this->viewbox.second.y; + float x, y, w, h; + ss >> x >> y >> w >> h; + this->viewbox = ViewBox(x, y, w, h); } rapidxml::xml_node<> *node = svg->first_node(); rapidxml::xml_node<> *prev = NULL; @@ -355,19 +356,19 @@ float Parser::getFloatAttribute(rapidxml::xml_node<> *node, std::string name) { if (name == "x1" || name == "y1" || name == "fr") result = 0; else if (name == "cx" || name == "cy") - result = name == "cx" ? 0.5 * this->viewbox.second.x - : 0.5 * this->viewbox.second.y; + result = name == "cx" ? 0.5 * this->viewbox.getWidth() + : 0.5 * this->viewbox.getHeight(); else if (name == "r") { - result = sqrt((pow(this->viewbox.second.x, 2) + - pow(this->viewbox.second.y, 2)) / + result = sqrt((pow(this->viewbox.getWidth(), 2) + + pow(this->viewbox.getHeight(), 2)) / 2) / 2; } else if (name == "fx" || name == "fy") result = name == "fx" ? getFloatAttribute(node, "cx") : getFloatAttribute(node, "cy"); else - result = name == "x2" ? this->viewbox.second.x - : this->viewbox.second.y; + result = name == "x2" ? this->viewbox.getWidth() + : this->viewbox.getHeight(); } else { // Handle default float attribute values for other elements if (name == "stroke-width" || name == "stroke-opacity" || @@ -383,7 +384,7 @@ float Parser::getFloatAttribute(rapidxml::xml_node<> *node, std::string name) { std::string value = node->first_attribute(name.c_str())->value(); if (value.find("%") != std::string::npos) { result = std::stof(value.substr(0, value.find("%"))) * - this->viewbox.second.x / 100; + this->viewbox.getWidth() / 100; } else if (value.find("pt") != std::string::npos) { result = std::stof(value.substr(0, value.find("pt"))) * 1.33; } else { @@ -907,7 +908,7 @@ Parser::~Parser() { void Parser::printShapesData() { root->printData(); } // Get the viewBox of the SVG document -std::pair< Vector2Df, Vector2Df > Parser::getViewBox() const { return viewbox; } +ViewBox Parser::getViewBox() const { return viewbox; } // Get the viewport of the SVG document Vector2Df Parser::getViewPort() const { return viewport; } \ No newline at end of file diff --git a/src/Parser.hpp b/src/Parser.hpp index a7e3491..04f20a1 100644 --- a/src/Parser.hpp +++ b/src/Parser.hpp @@ -61,7 +61,7 @@ class Parser { * * @return The viewbox of the SVG file. */ - std::pair< Vector2Df, Vector2Df > getViewBox() const; + ViewBox getViewBox() const; /** * @brief Gets the viewport of the SVG file. @@ -278,8 +278,7 @@ class Parser { SVGElement* root; ///< The root of the SVG file. std::map< std::string, Gradient* > gradients; ///< The gradients of the SVG ///< file. - std::pair< Vector2Df, Vector2Df > - viewbox; ///< The viewbox of the SVG file. + ViewBox viewbox; ///< The viewbox of the SVG file. Vector2Df viewport; ///< The viewport of the SVG file. }; diff --git a/src/graphics/ViewBox.cpp b/src/graphics/ViewBox.cpp new file mode 100644 index 0000000..a6eaa69 --- /dev/null +++ b/src/graphics/ViewBox.cpp @@ -0,0 +1,13 @@ +#include "ViewBox.hpp" + +ViewBox::ViewBox() : x(0), y(0), w(0), h(0) {} + +ViewBox::ViewBox(float X, float Y, float W, float H) : x(X), y(Y), w(W), h(H) {} + +float ViewBox::getX() const { return x; } + +float ViewBox::getY() const { return y; } + +float ViewBox::getWidth() const { return w; } + +float ViewBox::getHeight() const { return h; } \ No newline at end of file diff --git a/src/graphics/ViewBox.hpp b/src/graphics/ViewBox.hpp new file mode 100644 index 0000000..4babb1f --- /dev/null +++ b/src/graphics/ViewBox.hpp @@ -0,0 +1,58 @@ +#ifndef VIEWBOX_HPP_ +#define VIEWBOX_HPP_ + +class ViewBox { +public: + /** + * @brief Default constructor + * + * Creates a ViewBox(0, 0, 0, 0). + */ + ViewBox(); + + /** + * @brief Construct the ViewBox from its coordinates + * + * @param X X coordinate + * @param Y Y coordinate + * @param W Width + * @param H Height + */ + ViewBox(float X, float Y, float W, float H); + + /** + * @brief Get the X coordinate of the ViewBox + * + * @return X coordinate of the ViewBox + */ + float getX() const; + + /** + * @brief Get the Y coordinate of the ViewBox + * + * @return Y coordinate of the ViewBox + */ + float getY() const; + + /** + * @brief Get the width of the ViewBox + * + * @return Width of the ViewBox + */ + float getWidth() const; + + /** + * @brief Get the height of the ViewBox + * + * @return Height of the ViewBox + */ + float getHeight() const; + +private: + float x; ///< X coordinate of the ViewBox + float y; ///< Y coordinate of the ViewBox + float w; ///< Width of the ViewBox + float h; ///< Height of the ViewBox +}; + +#endif // VIEWBOX_HPP_ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8c68f2b..7118360 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,7 @@ void OnPaint(HDC hdc, const std::string& filePath, Viewer& viewer) { // Set up Viewbox and Viewport Vector2Df viewport = parser->getViewPort(); - std::pair< Vector2Df, Vector2Df > viewbox = parser->getViewBox(); + ViewBox viewbox = parser->getViewBox(); if (viewport.x == 0 && viewport.y == 0) { viewport.x = viewer.window_size.x; viewport.y = viewer.window_size.y; @@ -35,23 +35,24 @@ void OnPaint(HDC hdc, const std::string& filePath, Viewer& viewer) { graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQuality); graphics.SetClip(Gdiplus::Rect(0, 0, viewport.x, viewport.y)); - if ((viewport.x != viewbox.second.x || viewport.y != viewbox.second.y) && - viewbox.second.x != 0 && viewbox.second.y != 0) { - float scale_x = viewport.x / viewbox.second.x; - float scale_y = viewport.y / viewbox.second.y; + if ((viewport.x != viewbox.getWidth() || + viewport.y != viewbox.getHeight()) && + viewbox.getWidth() != 0 && viewbox.getHeight() != 0) { + float scale_x = viewport.x / viewbox.getWidth(); + float scale_y = viewport.y / viewbox.getHeight(); float scale = std::min(scale_x, scale_y); graphics.ScaleTransform(scale, scale); float offset_x = 0.0f; float offset_y = 0.0f; - if (viewport.x > viewbox.second.x) { - offset_x = (viewport.x - viewbox.second.x * scale) / 2 / scale; + if (viewport.x > viewbox.getWidth()) { + offset_x = (viewport.x - viewbox.getWidth() * scale) / 2 / scale; } - if (viewport.y > viewbox.second.y) { - offset_y = (viewport.y - viewbox.second.y * scale) / 2 / scale; + if (viewport.y > viewbox.getHeight()) { + offset_y = (viewport.y - viewbox.getHeight() * scale) / 2 / scale; } graphics.TranslateTransform(offset_x, offset_y); } - graphics.TranslateTransform(-viewbox.first.x, -viewbox.first.y); + graphics.TranslateTransform(-viewbox.getX(), -viewbox.getY()); Gdiplus::Matrix matrix; Gdiplus::Region region; @@ -124,6 +125,18 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, std::string filePath; if (__argc > 1) { filePath = __argv[1]; + std::ifstream file(filePath); + if (!file.good()) { + std::cerr << "Error: File path is invalid or does not exist." + << std::endl; + PostQuitMessage(0); + return 0; + } + file.close(); + } else { + std::cerr << "Error: No file path provided." << std::endl; + PostQuitMessage(0); + return 0; } Viewer* viewer = Viewer::getInstance(); switch (message) {