From 26ecae46b327f824e1d97bdf4312943f21908226 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Thu, 12 Jan 2023 17:45:06 +0000 Subject: [PATCH] Improve node to svg conversion. --- .../src/visuals/BlochSphereNode.cpp | 13 +- .../test/TestBlochSphereNode.cpp | 25 +-- src/geometry/AbstractGeometricItem.h | 1 + src/geometry/Circle.cpp | 43 +++++ src/geometry/Circle.h | 29 ++++ src/publishing/plotting/SvgConverter.cpp | 159 ++++++++++++++---- src/publishing/plotting/SvgConverter.h | 20 ++- .../basic_shapes/CircleNode.cpp | 60 +++++-- src/visual_elements/basic_shapes/CircleNode.h | 8 +- src/visual_elements/basic_shapes/LineNode.h | 18 ++ .../basic_shapes/RectangleNode.cpp | 28 ++- .../basic_shapes/RectangleNode.h | 1 + src/visual_elements/nodes/GeometryNode.h | 16 -- src/visual_elements/nodes/MaterialNode.cpp | 17 +- src/visual_elements/nodes/MaterialNode.h | 2 + src/visual_elements/scene/Scene.cpp | 4 +- src/web/CMakeLists.txt | 5 + src/web/svg/SvgShapeElement.cpp | 14 ++ src/web/svg/SvgShapeElement.h | 3 + src/web/svg/elements/SvgShapeElements.cpp | 26 +-- src/web/svg/elements/SvgShapeElements.h | 16 +- test/test_utils/TestRenderUtils.h | 21 ++- 22 files changed, 403 insertions(+), 126 deletions(-) diff --git a/plugins/quantum_computing/src/visuals/BlochSphereNode.cpp b/plugins/quantum_computing/src/visuals/BlochSphereNode.cpp index d502bc7..ae4c08a 100644 --- a/plugins/quantum_computing/src/visuals/BlochSphereNode.cpp +++ b/plugins/quantum_computing/src/visuals/BlochSphereNode.cpp @@ -1,6 +1,7 @@ #include "BlochSphereNode.h" #include "CircleNode.h" +#include "LineNode.h" BlochSphereNode::BlochSphereNode(const Point& location) : AbstractVisualNode(location, "BlochSphereNode") @@ -32,9 +33,17 @@ void BlochSphereNode::update(SceneInfo* sceneInfo) mChildren.clear(); - auto loc = DiscretePoint(mSize / 2.0, mSize / 2.0); + auto loc = Point(mSize / 2.0, mSize / 2.0); + mInnerCircle = std::make_unique(loc, mSize / 2.0); + mInnerCircle->setMinorRadius(mSize / 4.0); + mOuterCircle = std::make_unique(loc, mSize/2.0); - addChild(mOuterCircle.get()); + mCentreCircle = std::make_unique(loc, mSize / 50.0); + mCentreCircle->setFillColor(Color(0, 0, 0)); + mCentreCircle->setHasStrokeColor(false); + addChild(mInnerCircle.get()); + addChild(mOuterCircle.get()); + addChild(mCentreCircle.get()); } \ No newline at end of file diff --git a/plugins/quantum_computing/test/TestBlochSphereNode.cpp b/plugins/quantum_computing/test/TestBlochSphereNode.cpp index 2a6ced1..f7ffc87 100644 --- a/plugins/quantum_computing/test/TestBlochSphereNode.cpp +++ b/plugins/quantum_computing/test/TestBlochSphereNode.cpp @@ -1,36 +1,23 @@ #include "TestFramework.h" #include "TestUtils.h" +#include "TestRenderUtils.h" #include "BlochSphereNode.h" #include "BlochSphere.h" -#include "Scene.h" - -#include "SvgConverter.h" -#include "SvgWriter.h" -#include "SvgDocument.h" - -#include "File.h" TEST_CASE(TestBlochSphereNode, "quantum_computing") { + TestRenderer renderer(100, 100); + auto node = std::make_unique(Point(0.5, 0.5)); Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 }); auto bloch_sphere = std::make_unique(state); + node->setSize(100); node->setContent(bloch_sphere.get()); - auto scene = std::make_unique(); - scene->addNode(node.get()); - scene->update(); - - SvgConverter converter; - auto svg_document = converter.convert(scene.get()); - - SvgWriter writer; - auto svg_content = writer.toString(svg_document.get()); - - File svg_file(TestUtils::getTestOutputDir(__FILE__) / "bloch_sphere.svg"); - svg_file.writeText(svg_content); + renderer.getScene()->addNode(node.get()); + renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "bloch_sphere.svg"); } \ No newline at end of file diff --git a/src/geometry/AbstractGeometricItem.h b/src/geometry/AbstractGeometricItem.h index 25a963e..723a37a 100644 --- a/src/geometry/AbstractGeometricItem.h +++ b/src/geometry/AbstractGeometricItem.h @@ -17,6 +17,7 @@ public: TRIANGLE, POINT, PATH, + CIRCLE, UNKNOWN }; diff --git a/src/geometry/Circle.cpp b/src/geometry/Circle.cpp index e69de29..be208ac 100644 --- a/src/geometry/Circle.cpp +++ b/src/geometry/Circle.cpp @@ -0,0 +1,43 @@ +#include "Circle.h" + +Circle::Circle(const Point& centre, double radius) + : mCentre(centre), + mRadius(radius) +{ + mMinorRadius = mRadius; +} + +const Point& Circle::getLocation() const +{ + return mCentre; +} + +double Circle::getRadius() const +{ + return mRadius; +} + +double Circle::getMinorRadius() const +{ + return mMinorRadius; +} + +void Circle::setMinorRadius(double radius) +{ + mMinorRadius = radius; +} + +void Circle::sample(Grid* grid) const +{ + +} + +Circle::Bounds Circle::getSize() const +{ + return Bounds{ 2.0 * mRadius, 2.0 * mMinorRadius }; +} + +Circle::Type Circle::getType() const +{ + return Type::CIRCLE; +} \ No newline at end of file diff --git a/src/geometry/Circle.h b/src/geometry/Circle.h index e69de29..41666fa 100644 --- a/src/geometry/Circle.h +++ b/src/geometry/Circle.h @@ -0,0 +1,29 @@ +#pragma once + +#include "AbstractGeometricItem.h" +#include "Point.h" + +class Circle : public AbstractGeometricItem +{ +public: + Circle(const Point& centre, double radius = 0.5); + + const Point& getLocation() const override; + + double getRadius() const; + + double getMinorRadius() const; + + void setMinorRadius(double radius); + + void sample(Grid* grid) const override; + + Bounds getSize() const override; + + Type getType() const override; + +private: + double mMinorRadius{ 0.5 }; + double mRadius{ 0.5 }; + Point mCentre; +}; \ No newline at end of file diff --git a/src/publishing/plotting/SvgConverter.cpp b/src/publishing/plotting/SvgConverter.cpp index 91dc021..08f5eae 100644 --- a/src/publishing/plotting/SvgConverter.cpp +++ b/src/publishing/plotting/SvgConverter.cpp @@ -5,16 +5,22 @@ #include "SceneItem.h" #include "SceneModel.h" +#include "SceneText.h" +#include "AbstractGeometricItem.h" #include "AbstractMesh.h" #include "TriMesh.h" #include "AbstractFace.h" -#include "SvgShapeElements.h" +#include "Circle.h" -std::unique_ptr SvgConverter::convert(Scene* scene) +#include "SvgShapeElements.h" +#include "XmlAttribute.h" + +std::unique_ptr SvgConverter::convert(Scene* scene, double width, double height) const { auto doc = std::make_unique(); + doc->setViewBox(0.0, 0.0, width, height); scene->update(); @@ -22,44 +28,125 @@ std::unique_ptr SvgConverter::convert(Scene* scene) { if (item->getType() == SceneItem::Type::MODEL) { - auto mesh = dynamic_cast(item)->getMesh(); - auto transform = item->getTransform(); - - if (mesh->getType() == AbstractMesh::MeshType::TRI) + auto model = dynamic_cast(item); + if (model->getGeometry()) { - for(const auto& face : dynamic_cast(mesh)->getFaces()) - { - auto svg_tri = std::make_unique(); - - std::vector points(3); - unsigned count = 0; - - auto face_locs = face->getNodeLocations(); - for(auto& loc : face_locs) - { - const auto x = loc.getX() * transform.getScaleX() + transform.getLocation().getX(); - const auto y = loc.getY() * transform.getScaleY() + transform.getLocation().getY(); - points[count] = {static_cast(x), static_cast(y)}; - count++; - } - svg_tri->setPoints(points); - svg_tri->setFill(item->getFillColor()); - doc->getRoot()->addChild(std::move(svg_tri)); - - if (scene->shouldShowMeshOutline()) - { - auto mesh_outline = std::make_unique(); - points.push_back(points[0]); - mesh_outline->setPoints(points); - mesh_outline->setStrokeColor({0, 0, 0}); - mesh_outline->setStrokeWidth(0.1); - doc->getRoot()->addChild(std::move(mesh_outline)); - } - } + convertPrimitive(doc.get(), model); } + else + { + convertMesh(doc.get(), model, scene->shouldShowMeshOutline()); + } + } + else + { + auto text = dynamic_cast(item); + convertText(doc.get(), text); } } - return std::move(doc); } + +void SvgConverter::convertMesh(SvgDocument* document, SceneModel* model, bool showOutline) const +{ + auto mesh = model->getMesh(); + auto transform = model->getTransform(); + + if (mesh->getType() == AbstractMesh::MeshType::TRI) + { + for (const auto& face : dynamic_cast(mesh)->getFaces()) + { + auto svg_tri = std::make_unique(); + + std::vector points(3); + unsigned count = 0; + + auto face_locs = face->getNodeLocations(); + for (const auto& loc : face_locs) + { + const auto x = loc.getX() * transform.getScaleX() + transform.getLocation().getX(); + const auto y = loc.getY() * transform.getScaleY() + transform.getLocation().getY(); + points[count] = { x, y }; + count++; + } + svg_tri->setPoints(points); + svg_tri->setFill(model->getFillColor()); + document->getRoot()->addChild(std::move(svg_tri)); + + if (showOutline) + { + auto mesh_outline = std::make_unique(); + points.push_back(points[0]); + mesh_outline->setPoints(points); + mesh_outline->setStrokeColor({ 0, 0, 0 }); + mesh_outline->setStrokeWidth(0.1); + document->getRoot()->addChild(std::move(mesh_outline)); + } + } + } +} + +void SvgConverter::setStyle(SceneModel* model, SvgShapeElement* element) const +{ + auto transform = model->getTransform(); + + if (model->hasFillColor()) + { + element->setFill(model->getFillColor()); + } + else + { + element->setNoFill(); + } + if (model->hasOutlineColor()) + { + element->setStrokeColor(model->getOutlineColor()); + element->setStrokeWidth(1.0 / transform.getScaleX()); + } + else + { + element->setNoStroke(); + } + element->addAttribute(std::move(toTransform(transform))); +} + +void SvgConverter::convertPrimitive(SvgDocument* document, SceneModel* model) const +{ + if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE) + { + auto rect = std::make_unique(); + rect->setWidth(1.0); + rect->setHeight(1.0); + + setStyle(model, rect.get()); + document->getRoot()->addChild(std::move(rect)); + } + else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::CIRCLE) + { + auto model_circle = dynamic_cast(model->getGeometry()); + + auto circle = std::make_unique(); + circle->setRadius(model_circle->getRadius()); + + setStyle(model, circle.get()); + document->getRoot()->addChild(std::move(circle)); + } +} + +void SvgConverter::convertText(SvgDocument* document, SceneText* model) const +{ + +} + +std::unique_ptr SvgConverter::toTransform(const Transform& transform) const +{ + auto svg_transform = std::make_unique("transform"); + + std::string ops; + ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") "; + ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") "; + svg_transform->setValue(ops); + + return std::move(svg_transform); +} diff --git a/src/publishing/plotting/SvgConverter.h b/src/publishing/plotting/SvgConverter.h index 2b4abd0..716bf1b 100644 --- a/src/publishing/plotting/SvgConverter.h +++ b/src/publishing/plotting/SvgConverter.h @@ -3,10 +3,28 @@ #include class SvgDocument; +class SvgShapeElement; +class XmlAttribute; + class Scene; +class SceneModel; +class SceneText; + +class Transform; class SvgConverter { public: - std::unique_ptr convert(Scene* scene); + std::unique_ptr convert(Scene* scene, double width = 800.0, double height = 800.0) const; + +private: + void convertMesh(SvgDocument* document, SceneModel* model, bool showOutline = false) const; + + void convertPrimitive(SvgDocument* document, SceneModel* model) const; + + void convertText(SvgDocument* document, SceneText* model) const; + + void setStyle(SceneModel* model, SvgShapeElement* element) const; + + std::unique_ptr toTransform(const Transform& transform) const; }; diff --git a/src/visual_elements/basic_shapes/CircleNode.cpp b/src/visual_elements/basic_shapes/CircleNode.cpp index 0a0d546..87c351a 100644 --- a/src/visual_elements/basic_shapes/CircleNode.cpp +++ b/src/visual_elements/basic_shapes/CircleNode.cpp @@ -5,8 +5,7 @@ #include "AbstractMesh.h" #include "MeshPrimitives.h" #include "SceneInfo.h" - -#include +#include "Circle.h" CircleNode::CircleNode(const Point& location, double radius) : GeometryNode(location), @@ -51,22 +50,53 @@ void CircleNode::setRadius(double radius) } } +void CircleNode::setMinorRadius(double radius) +{ + if (mMinorRadius != radius) + { + mMinorRadius = radius; + mTransformIsDirty = true; + } +} + +void CircleNode::createOrUpdateGeometry(SceneInfo* sceneInfo) +{ + if (sceneInfo->mSupportsGeometryPrimitives) + { + auto circle = std::make_unique(Point{ 0, 0 }, 0.5); + circle->setMinorRadius(mMinorRadius); + mBackgroundItem = std::make_unique(std::move(circle)); + } + else + { + auto mesh = MeshPrimitives::buildCircleAsTriMesh(); + mBackgroundItem = std::make_unique(std::move(mesh)); + } + mBackgroundItem->setName(mName + "_Model"); +} + +void CircleNode::updateMaterial() +{ + if (!mBackgroundItem) + { + return; + } + + if (mHasFillColor) + { + mBackgroundItem->setFillColor(mFillColor); + } + if (mHasStrokeColor) + { + mBackgroundItem->setOutlineColor(mStrokeColor); + } +} + void CircleNode::update(SceneInfo* sceneInfo) { if (!mBackgroundItem || mGeometryIsDirty) { - auto mesh = MeshPrimitives::buildCircleAsTriMesh(); - - if (!mBackgroundItem) - { - mBackgroundItem = std::make_unique(std::move(mesh)); - mBackgroundItem->setName(mName + "_Model"); - mBackgroundItem->setFillColor(mFillColor); - } - else - { - mBackgroundItem->updateMesh(std::move(mesh)); - } + createOrUpdateGeometry(sceneInfo); mGeometryIsDirty = false; } @@ -78,7 +108,7 @@ void CircleNode::update(SceneInfo* sceneInfo) if (mMaterialIsDirty) { - mBackgroundItem->setFillColor(mFillColor); + updateMaterial(); mMaterialIsDirty = false; } } diff --git a/src/visual_elements/basic_shapes/CircleNode.h b/src/visual_elements/basic_shapes/CircleNode.h index 52be1c6..640096b 100644 --- a/src/visual_elements/basic_shapes/CircleNode.h +++ b/src/visual_elements/basic_shapes/CircleNode.h @@ -7,18 +7,22 @@ class CircleNode : public GeometryNode public: CircleNode(const Point& location, double radius); - Type getType(); + Type getType() override; double getRadius() const; SceneItem* getSceneItem(std::size_t idx) const override; std::size_t getNumSceneItems() const override; + void setMinorRadius(double radius); void setRadius(double radius); void update(SceneInfo* sceneInfo) override; private: - double mRadius{1}; + void createOrUpdateGeometry(SceneInfo* sceneInfo); + void updateMaterial(); + double mRadius{1.0}; + double mMinorRadius{ 1.0 }; std::unique_ptr mBackgroundItem; std::unique_ptr mOutlineItem; diff --git a/src/visual_elements/basic_shapes/LineNode.h b/src/visual_elements/basic_shapes/LineNode.h index e69de29..f830cbb 100644 --- a/src/visual_elements/basic_shapes/LineNode.h +++ b/src/visual_elements/basic_shapes/LineNode.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GeometryNode.h" + +class LineNode : public GeometryNode +{ +public: + LineNode(const Point& location) + : GeometryNode(location) + { + + } + + Type getType() + { + return Type::Line; + } +}; \ No newline at end of file diff --git a/src/visual_elements/basic_shapes/RectangleNode.cpp b/src/visual_elements/basic_shapes/RectangleNode.cpp index 03610af..49140f4 100644 --- a/src/visual_elements/basic_shapes/RectangleNode.cpp +++ b/src/visual_elements/basic_shapes/RectangleNode.cpp @@ -86,6 +86,23 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo) mBackgroundItem->setName(mName + "_Model"); } +void RectangleNode::updateMaterial() +{ + if (!mBackgroundItem) + { + return; + } + + if (mHasFillColor) + { + mBackgroundItem->setFillColor(mFillColor); + } + if (mHasStrokeColor) + { + mBackgroundItem->setOutlineColor(mStrokeColor); + } +} + void RectangleNode::update(SceneInfo* sceneInfo) { if (!mBackgroundItem || mGeometryIsDirty) @@ -96,20 +113,13 @@ void RectangleNode::update(SceneInfo* sceneInfo) if (mTransformIsDirty) { - mBackgroundItem->updateTransform({mLocation, static_cast(mWidth), static_cast(mHeight)}); + mBackgroundItem->updateTransform({mLocation, mWidth, mHeight}); mTransformIsDirty = false; } if (mMaterialIsDirty) { - if (mHasFillColor) - { - mBackgroundItem->setFillColor(mFillColor); - } - if (mHasStrokeColor) - { - mBackgroundItem->setOutlineColor(mStrokeColor); - } + updateMaterial(); mMaterialIsDirty = false; } } diff --git a/src/visual_elements/basic_shapes/RectangleNode.h b/src/visual_elements/basic_shapes/RectangleNode.h index a2e1e9a..1fe65ad 100644 --- a/src/visual_elements/basic_shapes/RectangleNode.h +++ b/src/visual_elements/basic_shapes/RectangleNode.h @@ -24,6 +24,7 @@ public: private: void createOrUpdateGeometry(SceneInfo* sceneInfo); + void updateMaterial(); double mWidth{1}; double mHeight{1}; diff --git a/src/visual_elements/nodes/GeometryNode.h b/src/visual_elements/nodes/GeometryNode.h index 4705f5a..1514c4d 100644 --- a/src/visual_elements/nodes/GeometryNode.h +++ b/src/visual_elements/nodes/GeometryNode.h @@ -27,23 +27,7 @@ public: protected: unsigned mStrokeThickness{0}; Type mType; - bool mGeometryIsDirty{true}; }; -class LineNode : public GeometryNode -{ -public: - LineNode(const Point& location) - : GeometryNode(location) - { - - } - - Type getType() - { - return Type::Line; - } -}; - using GeometryNodePtr = std::unique_ptr; diff --git a/src/visual_elements/nodes/MaterialNode.cpp b/src/visual_elements/nodes/MaterialNode.cpp index 1eb9b8b..1833141 100644 --- a/src/visual_elements/nodes/MaterialNode.cpp +++ b/src/visual_elements/nodes/MaterialNode.cpp @@ -20,20 +20,33 @@ const Color& MaterialNode::getStrokeColor() const return mStrokeColor; } +void MaterialNode::setHasStrokeColor(bool hasStroke) +{ + if (mHasStrokeColor != hasStroke) + { + mHasStrokeColor = hasStroke; + mMaterialIsDirty = true; + } +} + void MaterialNode::setFillColor(const Color& color) { + mHasFillColor = true; + if (mFillColor != color) { mMaterialIsDirty = true; - mFillColor = color; + mFillColor = color; } } void MaterialNode::setStrokeColor(const Color& color) { + mHasStrokeColor = true; + if (mStrokeColor != color) { mMaterialIsDirty = true; - mStrokeColor = color; + mStrokeColor = color; } } diff --git a/src/visual_elements/nodes/MaterialNode.h b/src/visual_elements/nodes/MaterialNode.h index 3318ca3..aee2016 100644 --- a/src/visual_elements/nodes/MaterialNode.h +++ b/src/visual_elements/nodes/MaterialNode.h @@ -12,6 +12,8 @@ public: const Color& getFillColor() const; const Color& getStrokeColor() const; + void setHasStrokeColor(bool hasStroke); + void setFillColor(const Color& color); void setStrokeColor(const Color& color); diff --git a/src/visual_elements/scene/Scene.cpp b/src/visual_elements/scene/Scene.cpp index 5543817..8cfd5f5 100644 --- a/src/visual_elements/scene/Scene.cpp +++ b/src/visual_elements/scene/Scene.cpp @@ -47,6 +47,8 @@ void Scene::setBackgroundColor(const Color& color) void Scene::updateNode(AbstractVisualNode* node) { + node->update(mSceneInfo.get()); + for (auto child : node->getChildren()) { if (child->getIsVisible()) @@ -55,8 +57,6 @@ void Scene::updateNode(AbstractVisualNode* node) } } - node->update(mSceneInfo.get()); - for (std::size_t idx=0; idx< node->getNumSceneItems(); idx++) { if (auto item = node->getSceneItem(idx)) diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt index 13f7e21..b01dc6e 100644 --- a/src/web/CMakeLists.txt +++ b/src/web/CMakeLists.txt @@ -27,6 +27,11 @@ list(APPEND web_LIB_INCLUDES html/elements/HtmlHeadElement.cpp html/elements/HtmlBodyElement.cpp html/elements/HtmlParagraphElement.cpp + svg/SvgDocument.h + svg/SvgWriter.h + svg/SvgShapeElement.h + svg/SvgElement.h + svg/elements/SvgShapeElements.h svg/SvgDocument.cpp svg/SvgWriter.cpp svg/SvgShapeElement.cpp diff --git a/src/web/svg/SvgShapeElement.cpp b/src/web/svg/SvgShapeElement.cpp index 60d9642..497bcc6 100644 --- a/src/web/svg/SvgShapeElement.cpp +++ b/src/web/svg/SvgShapeElement.cpp @@ -10,6 +10,20 @@ SvgShapeElement::SvgShapeElement(const std::string& tagName) } +void SvgShapeElement::setNoFill() +{ + auto attr = std::make_unique("fill"); + attr->setValue("none"); + addAttribute(std::move(attr)); +} + +void SvgShapeElement::setNoStroke() +{ + auto attr = std::make_unique("stroke"); + attr->setValue("none"); + addAttribute(std::move(attr)); +} + void SvgShapeElement::setFill(const Color& fill) { auto attr = std::make_unique("fill"); diff --git a/src/web/svg/SvgShapeElement.h b/src/web/svg/SvgShapeElement.h index 872145d..94e394a 100644 --- a/src/web/svg/SvgShapeElement.h +++ b/src/web/svg/SvgShapeElement.h @@ -10,8 +10,11 @@ public: void setFill(const Color& fill); + void setNoFill(); + void setStrokeWidth(double width); void setStrokeColor(const Color& stroke); + void setNoStroke(); }; diff --git a/src/web/svg/elements/SvgShapeElements.cpp b/src/web/svg/elements/SvgShapeElements.cpp index be3c13f..a4961b1 100644 --- a/src/web/svg/elements/SvgShapeElements.cpp +++ b/src/web/svg/elements/SvgShapeElements.cpp @@ -8,19 +8,19 @@ SvgCircle::SvgCircle() } -void SvgCircle::setLocation(const DiscretePoint& loc) +void SvgCircle::setLocation(const Point& loc) { auto cx = std::make_unique("cx"); auto cy = std::make_unique("cy"); - cx->setValue(std::to_string(loc.GetX())); - cy->setValue(std::to_string(loc.GetY())); + cx->setValue(std::to_string(loc.getX())); + cy->setValue(std::to_string(loc.getY())); addAttribute(std::move(cx)); addAttribute(std::move(cy)); } -void SvgCircle::setRadius(unsigned rad) +void SvgCircle::setRadius(double rad) { auto r = std::make_unique("r"); r->setValue(std::to_string(rad)); @@ -33,19 +33,19 @@ SvgRectangle::SvgRectangle() } -void SvgRectangle::setLocation(const DiscretePoint& loc) +void SvgRectangle::setLocation(const Point& loc) { auto x = std::make_unique("x"); auto y = std::make_unique("y"); - x->setValue(std::to_string(loc.GetX())); - y->setValue(std::to_string(loc.GetY())); + x->setValue(std::to_string(loc.getX())); + y->setValue(std::to_string(loc.getY())); addAttribute(std::move(x)); addAttribute(std::move(y)); } -void SvgRectangle::setWidth(unsigned w) +void SvgRectangle::setWidth(double w) { auto width = std::make_unique("width"); @@ -54,7 +54,7 @@ void SvgRectangle::setWidth(unsigned w) addAttribute(std::move(width)); } -void SvgRectangle::setHeight(unsigned h) +void SvgRectangle::setHeight(double h) { auto height = std::make_unique("height"); @@ -70,14 +70,14 @@ SvgPolygon::SvgPolygon() } -void SvgPolygon::setPoints(const std::vector& locs) +void SvgPolygon::setPoints(const std::vector& locs) { auto points = std::make_unique("points"); std::stringstream sstr; for (const auto& loc : locs) { - sstr << loc.GetX() << "," << loc.GetY() << " "; + sstr << loc.getX() << "," << loc.getY() << " "; } points->setValue(sstr.str()); addAttribute(std::move(points)); @@ -91,14 +91,14 @@ SvgPolyline::SvgPolyline() addAttribute(std::move(fill)); } -void SvgPolyline::setPoints(const std::vector& locs) +void SvgPolyline::setPoints(const std::vector& locs) { auto points = std::make_unique("points"); std::stringstream sstr; for (const auto& loc : locs) { - sstr << loc.GetX() << "," << loc.GetY() << " "; + sstr << loc.getX() << "," << loc.getY() << " "; } points->setValue(sstr.str()); addAttribute(std::move(points)); diff --git a/src/web/svg/elements/SvgShapeElements.h b/src/web/svg/elements/SvgShapeElements.h index d8825aa..1e72e0f 100644 --- a/src/web/svg/elements/SvgShapeElements.h +++ b/src/web/svg/elements/SvgShapeElements.h @@ -1,7 +1,7 @@ #pragma once #include "SvgShapeElement.h" -#include "DiscretePoint.h" +#include "Point.h" #include "XmlAttribute.h" @@ -10,9 +10,9 @@ class SvgCircle : public SvgShapeElement public: SvgCircle(); - void setLocation(const DiscretePoint& loc); + void setLocation(const Point& loc); - void setRadius(unsigned rad); + void setRadius(double rad); }; class SvgRectangle : public SvgShapeElement @@ -20,11 +20,11 @@ class SvgRectangle : public SvgShapeElement public: SvgRectangle(); - void setLocation(const DiscretePoint& loc); + void setLocation(const Point& loc); - void setWidth(unsigned width); + void setWidth(double width); - void setHeight(unsigned height); + void setHeight(double height); }; class SvgPolygon : public SvgShapeElement @@ -32,7 +32,7 @@ class SvgPolygon : public SvgShapeElement public: SvgPolygon(); - void setPoints(const std::vector& loc); + void setPoints(const std::vector& loc); }; class SvgPolyline : public SvgShapeElement @@ -40,7 +40,7 @@ class SvgPolyline : public SvgShapeElement public: SvgPolyline(); - void setPoints(const std::vector& loc); + void setPoints(const std::vector& loc); }; class SvgPath : public SvgShapeElement diff --git a/test/test_utils/TestRenderUtils.h b/test/test_utils/TestRenderUtils.h index 3750f58..83f093a 100644 --- a/test/test_utils/TestRenderUtils.h +++ b/test/test_utils/TestRenderUtils.h @@ -3,9 +3,16 @@ #include "DrawingSurface.h" #include "DrawingContext.h" #include "AbstractPainter.h" +#include "Scene.h" + +#include "SvgConverter.h" +#include "SvgWriter.h" +#include "SvgDocument.h" + #include "Image.h" #include "PngWriter.h" -#include "Scene.h" + +#include "File.h" class TestRenderer { @@ -34,6 +41,18 @@ public: writer.write(image); } + void writeSvg(const Path& path) + { + SvgConverter converter; + auto svg_document = converter.convert(mSurface->getScene()); + + SvgWriter writer; + auto svg_content = writer.toString(svg_document.get()); + + File svg_file(path); + svg_file.writeText(svg_content); + } + private: std::unique_ptr mSurface; std::unique_ptr mDrawingContext;