Improve node to svg conversion.
This commit is contained in:
parent
64f0b3e77a
commit
26ecae46b3
22 changed files with 403 additions and 126 deletions
|
@ -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<CircleNode>(loc, mSize / 2.0);
|
||||
mInnerCircle->setMinorRadius(mSize / 4.0);
|
||||
|
||||
mOuterCircle = std::make_unique<CircleNode>(loc, mSize/2.0);
|
||||
|
||||
addChild(mOuterCircle.get());
|
||||
mCentreCircle = std::make_unique<CircleNode>(loc, mSize / 50.0);
|
||||
mCentreCircle->setFillColor(Color(0, 0, 0));
|
||||
mCentreCircle->setHasStrokeColor(false);
|
||||
|
||||
addChild(mInnerCircle.get());
|
||||
addChild(mOuterCircle.get());
|
||||
addChild(mCentreCircle.get());
|
||||
}
|
|
@ -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<BlochSphereNode>(Point(0.5, 0.5));
|
||||
|
||||
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
||||
|
||||
auto bloch_sphere = std::make_unique<BlochSphere>(state);
|
||||
|
||||
node->setSize(100);
|
||||
node->setContent(bloch_sphere.get());
|
||||
|
||||
auto scene = std::make_unique<Scene>();
|
||||
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");
|
||||
}
|
|
@ -17,6 +17,7 @@ public:
|
|||
TRIANGLE,
|
||||
POINT,
|
||||
PATH,
|
||||
CIRCLE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
|
|
|
@ -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<unsigned char>* grid) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Circle::Bounds Circle::getSize() const
|
||||
{
|
||||
return Bounds{ 2.0 * mRadius, 2.0 * mMinorRadius };
|
||||
}
|
||||
|
||||
Circle::Type Circle::getType() const
|
||||
{
|
||||
return Type::CIRCLE;
|
||||
}
|
|
@ -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<unsigned char>* grid) const override;
|
||||
|
||||
Bounds getSize() const override;
|
||||
|
||||
Type getType() const override;
|
||||
|
||||
private:
|
||||
double mMinorRadius{ 0.5 };
|
||||
double mRadius{ 0.5 };
|
||||
Point mCentre;
|
||||
};
|
|
@ -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<SvgDocument> SvgConverter::convert(Scene* scene)
|
||||
#include "SvgShapeElements.h"
|
||||
#include "XmlAttribute.h"
|
||||
|
||||
std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene, double width, double height) const
|
||||
{
|
||||
auto doc = std::make_unique<SvgDocument>();
|
||||
doc->setViewBox(0.0, 0.0, width, height);
|
||||
|
||||
scene->update();
|
||||
|
||||
|
@ -22,44 +28,125 @@ std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene)
|
|||
{
|
||||
if (item->getType() == SceneItem::Type::MODEL)
|
||||
{
|
||||
auto mesh = dynamic_cast<SceneModel*>(item)->getMesh();
|
||||
auto transform = item->getTransform();
|
||||
auto model = dynamic_cast<SceneModel*>(item);
|
||||
if (model->getGeometry())
|
||||
{
|
||||
convertPrimitive(doc.get(), model);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertMesh(doc.get(), model, scene->shouldShowMeshOutline());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto text = dynamic_cast<SceneText*>(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<TriMesh*>(mesh)->getFaces())
|
||||
for (const auto& face : dynamic_cast<TriMesh*>(mesh)->getFaces())
|
||||
{
|
||||
auto svg_tri = std::make_unique<SvgPolygon>();
|
||||
|
||||
std::vector<DiscretePoint> points(3);
|
||||
std::vector<Point> points(3);
|
||||
unsigned count = 0;
|
||||
|
||||
auto face_locs = face->getNodeLocations();
|
||||
for(auto& loc : face_locs)
|
||||
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] = {static_cast<unsigned>(x), static_cast<unsigned>(y)};
|
||||
points[count] = { x, y };
|
||||
count++;
|
||||
}
|
||||
svg_tri->setPoints(points);
|
||||
svg_tri->setFill(item->getFillColor());
|
||||
doc->getRoot()->addChild(std::move(svg_tri));
|
||||
svg_tri->setFill(model->getFillColor());
|
||||
document->getRoot()->addChild(std::move(svg_tri));
|
||||
|
||||
if (scene->shouldShowMeshOutline())
|
||||
if (showOutline)
|
||||
{
|
||||
auto mesh_outline = std::make_unique<SvgPolyline>();
|
||||
points.push_back(points[0]);
|
||||
mesh_outline->setPoints(points);
|
||||
mesh_outline->setStrokeColor({0, 0, 0});
|
||||
mesh_outline->setStrokeColor({ 0, 0, 0 });
|
||||
mesh_outline->setStrokeWidth(0.1);
|
||||
doc->getRoot()->addChild(std::move(mesh_outline));
|
||||
document->getRoot()->addChild(std::move(mesh_outline));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return std::move(doc);
|
||||
}
|
||||
|
||||
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<SvgRectangle>();
|
||||
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<Circle*>(model->getGeometry());
|
||||
|
||||
auto circle = std::make_unique<SvgCircle>();
|
||||
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<XmlAttribute> SvgConverter::toTransform(const Transform& transform) const
|
||||
{
|
||||
auto svg_transform = std::make_unique<XmlAttribute>("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);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,28 @@
|
|||
#include <memory>
|
||||
|
||||
class SvgDocument;
|
||||
class SvgShapeElement;
|
||||
class XmlAttribute;
|
||||
|
||||
class Scene;
|
||||
class SceneModel;
|
||||
class SceneText;
|
||||
|
||||
class Transform;
|
||||
|
||||
class SvgConverter
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<SvgDocument> convert(Scene* scene);
|
||||
std::unique_ptr<SvgDocument> 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<XmlAttribute> toTransform(const Transform& transform) const;
|
||||
};
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include "AbstractMesh.h"
|
||||
#include "MeshPrimitives.h"
|
||||
#include "SceneInfo.h"
|
||||
|
||||
#include <iostream>
|
||||
#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<Circle>(Point{ 0, 0 }, 0.5);
|
||||
circle->setMinorRadius(mMinorRadius);
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(circle));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mesh = MeshPrimitives::buildCircleAsTriMesh();
|
||||
mBackgroundItem = std::make_unique<SceneModel>(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<SceneModel>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<SceneModel> mBackgroundItem;
|
||||
std::unique_ptr<SceneModel> mOutlineItem;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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<double>(mWidth), static_cast<double>(mHeight)});
|
||||
mBackgroundItem->updateTransform({mLocation, mWidth, mHeight});
|
||||
mTransformIsDirty = false;
|
||||
}
|
||||
|
||||
if (mMaterialIsDirty)
|
||||
{
|
||||
if (mHasFillColor)
|
||||
{
|
||||
mBackgroundItem->setFillColor(mFillColor);
|
||||
}
|
||||
if (mHasStrokeColor)
|
||||
{
|
||||
mBackgroundItem->setOutlineColor(mStrokeColor);
|
||||
}
|
||||
updateMaterial();
|
||||
mMaterialIsDirty = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
private:
|
||||
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||
void updateMaterial();
|
||||
double mWidth{1};
|
||||
double mHeight{1};
|
||||
|
||||
|
|
|
@ -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<GeometryNode>;
|
||||
|
|
|
@ -20,8 +20,19 @@ 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;
|
||||
|
@ -31,6 +42,8 @@ void MaterialNode::setFillColor(const Color& color)
|
|||
|
||||
void MaterialNode::setStrokeColor(const Color& color)
|
||||
{
|
||||
mHasStrokeColor = true;
|
||||
|
||||
if (mStrokeColor != color)
|
||||
{
|
||||
mMaterialIsDirty = true;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,6 +10,20 @@ SvgShapeElement::SvgShapeElement(const std::string& tagName)
|
|||
|
||||
}
|
||||
|
||||
void SvgShapeElement::setNoFill()
|
||||
{
|
||||
auto attr = std::make_unique<XmlAttribute>("fill");
|
||||
attr->setValue("none");
|
||||
addAttribute(std::move(attr));
|
||||
}
|
||||
|
||||
void SvgShapeElement::setNoStroke()
|
||||
{
|
||||
auto attr = std::make_unique<XmlAttribute>("stroke");
|
||||
attr->setValue("none");
|
||||
addAttribute(std::move(attr));
|
||||
}
|
||||
|
||||
void SvgShapeElement::setFill(const Color& fill)
|
||||
{
|
||||
auto attr = std::make_unique<XmlAttribute>("fill");
|
||||
|
|
|
@ -10,8 +10,11 @@ public:
|
|||
|
||||
void setFill(const Color& fill);
|
||||
|
||||
void setNoFill();
|
||||
|
||||
void setStrokeWidth(double width);
|
||||
|
||||
void setStrokeColor(const Color& stroke);
|
||||
|
||||
void setNoStroke();
|
||||
};
|
||||
|
|
|
@ -8,19 +8,19 @@ SvgCircle::SvgCircle()
|
|||
|
||||
}
|
||||
|
||||
void SvgCircle::setLocation(const DiscretePoint& loc)
|
||||
void SvgCircle::setLocation(const Point& loc)
|
||||
{
|
||||
auto cx = std::make_unique<XmlAttribute>("cx");
|
||||
auto cy = std::make_unique<XmlAttribute>("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<XmlAttribute>("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<XmlAttribute>("x");
|
||||
auto y = std::make_unique<XmlAttribute>("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<XmlAttribute>("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<XmlAttribute>("height");
|
||||
|
||||
|
@ -70,14 +70,14 @@ SvgPolygon::SvgPolygon()
|
|||
|
||||
}
|
||||
|
||||
void SvgPolygon::setPoints(const std::vector<DiscretePoint>& locs)
|
||||
void SvgPolygon::setPoints(const std::vector<Point>& locs)
|
||||
{
|
||||
auto points = std::make_unique<XmlAttribute>("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<DiscretePoint>& locs)
|
||||
void SvgPolyline::setPoints(const std::vector<Point>& locs)
|
||||
{
|
||||
auto points = std::make_unique<XmlAttribute>("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));
|
||||
|
|
|
@ -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<DiscretePoint>& loc);
|
||||
void setPoints(const std::vector<Point>& loc);
|
||||
};
|
||||
|
||||
class SvgPolyline : public SvgShapeElement
|
||||
|
@ -40,7 +40,7 @@ class SvgPolyline : public SvgShapeElement
|
|||
public:
|
||||
SvgPolyline();
|
||||
|
||||
void setPoints(const std::vector<DiscretePoint>& loc);
|
||||
void setPoints(const std::vector<Point>& loc);
|
||||
};
|
||||
|
||||
class SvgPath : public SvgShapeElement
|
||||
|
|
|
@ -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<DrawingSurface> mSurface;
|
||||
std::unique_ptr<DrawingContext> mDrawingContext;
|
||||
|
|
Loading…
Reference in a new issue