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 "BlochSphereNode.h"
|
||||||
|
|
||||||
#include "CircleNode.h"
|
#include "CircleNode.h"
|
||||||
|
#include "LineNode.h"
|
||||||
|
|
||||||
BlochSphereNode::BlochSphereNode(const Point& location)
|
BlochSphereNode::BlochSphereNode(const Point& location)
|
||||||
: AbstractVisualNode(location, "BlochSphereNode")
|
: AbstractVisualNode(location, "BlochSphereNode")
|
||||||
|
@ -32,9 +33,17 @@ void BlochSphereNode::update(SceneInfo* sceneInfo)
|
||||||
|
|
||||||
mChildren.clear();
|
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);
|
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 "TestFramework.h"
|
||||||
#include "TestUtils.h"
|
#include "TestUtils.h"
|
||||||
|
#include "TestRenderUtils.h"
|
||||||
|
|
||||||
#include "BlochSphereNode.h"
|
#include "BlochSphereNode.h"
|
||||||
#include "BlochSphere.h"
|
#include "BlochSphere.h"
|
||||||
#include "Scene.h"
|
|
||||||
|
|
||||||
#include "SvgConverter.h"
|
|
||||||
#include "SvgWriter.h"
|
|
||||||
#include "SvgDocument.h"
|
|
||||||
|
|
||||||
#include "File.h"
|
|
||||||
|
|
||||||
TEST_CASE(TestBlochSphereNode, "quantum_computing")
|
TEST_CASE(TestBlochSphereNode, "quantum_computing")
|
||||||
{
|
{
|
||||||
|
TestRenderer renderer(100, 100);
|
||||||
|
|
||||||
auto node = std::make_unique<BlochSphereNode>(Point(0.5, 0.5));
|
auto node = std::make_unique<BlochSphereNode>(Point(0.5, 0.5));
|
||||||
|
|
||||||
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
||||||
|
|
||||||
auto bloch_sphere = std::make_unique<BlochSphere>(state);
|
auto bloch_sphere = std::make_unique<BlochSphere>(state);
|
||||||
|
|
||||||
|
node->setSize(100);
|
||||||
node->setContent(bloch_sphere.get());
|
node->setContent(bloch_sphere.get());
|
||||||
|
|
||||||
auto scene = std::make_unique<Scene>();
|
renderer.getScene()->addNode(node.get());
|
||||||
scene->addNode(node.get());
|
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "bloch_sphere.svg");
|
||||||
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);
|
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@ public:
|
||||||
TRIANGLE,
|
TRIANGLE,
|
||||||
POINT,
|
POINT,
|
||||||
PATH,
|
PATH,
|
||||||
|
CIRCLE,
|
||||||
UNKNOWN
|
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 "SceneItem.h"
|
||||||
#include "SceneModel.h"
|
#include "SceneModel.h"
|
||||||
|
#include "SceneText.h"
|
||||||
|
|
||||||
|
#include "AbstractGeometricItem.h"
|
||||||
#include "AbstractMesh.h"
|
#include "AbstractMesh.h"
|
||||||
#include "TriMesh.h"
|
#include "TriMesh.h"
|
||||||
#include "AbstractFace.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>();
|
auto doc = std::make_unique<SvgDocument>();
|
||||||
|
doc->setViewBox(0.0, 0.0, width, height);
|
||||||
|
|
||||||
scene->update();
|
scene->update();
|
||||||
|
|
||||||
|
@ -22,44 +28,125 @@ std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene)
|
||||||
{
|
{
|
||||||
if (item->getType() == SceneItem::Type::MODEL)
|
if (item->getType() == SceneItem::Type::MODEL)
|
||||||
{
|
{
|
||||||
auto mesh = dynamic_cast<SceneModel*>(item)->getMesh();
|
auto model = dynamic_cast<SceneModel*>(item);
|
||||||
auto transform = item->getTransform();
|
if (model->getGeometry())
|
||||||
|
|
||||||
if (mesh->getType() == AbstractMesh::MeshType::TRI)
|
|
||||||
{
|
{
|
||||||
for(const auto& face : dynamic_cast<TriMesh*>(mesh)->getFaces())
|
convertPrimitive(doc.get(), model);
|
||||||
{
|
|
||||||
auto svg_tri = std::make_unique<SvgPolygon>();
|
|
||||||
|
|
||||||
std::vector<DiscretePoint> 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<unsigned>(x), static_cast<unsigned>(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<SvgPolyline>();
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convertMesh(doc.get(), model, scene->shouldShowMeshOutline());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto text = dynamic_cast<SceneText*>(item);
|
||||||
|
convertText(doc.get(), text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return std::move(doc);
|
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())
|
||||||
|
{
|
||||||
|
auto svg_tri = std::make_unique<SvgPolygon>();
|
||||||
|
|
||||||
|
std::vector<Point> 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<SvgPolyline>();
|
||||||
|
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<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>
|
#include <memory>
|
||||||
|
|
||||||
class SvgDocument;
|
class SvgDocument;
|
||||||
|
class SvgShapeElement;
|
||||||
|
class XmlAttribute;
|
||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
|
class SceneModel;
|
||||||
|
class SceneText;
|
||||||
|
|
||||||
|
class Transform;
|
||||||
|
|
||||||
class SvgConverter
|
class SvgConverter
|
||||||
{
|
{
|
||||||
public:
|
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 "AbstractMesh.h"
|
||||||
#include "MeshPrimitives.h"
|
#include "MeshPrimitives.h"
|
||||||
#include "SceneInfo.h"
|
#include "SceneInfo.h"
|
||||||
|
#include "Circle.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
CircleNode::CircleNode(const Point& location, double radius)
|
CircleNode::CircleNode(const Point& location, double radius)
|
||||||
: GeometryNode(location),
|
: 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)
|
void CircleNode::update(SceneInfo* sceneInfo)
|
||||||
{
|
{
|
||||||
if (!mBackgroundItem || mGeometryIsDirty)
|
if (!mBackgroundItem || mGeometryIsDirty)
|
||||||
{
|
{
|
||||||
auto mesh = MeshPrimitives::buildCircleAsTriMesh();
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
|
||||||
if (!mBackgroundItem)
|
|
||||||
{
|
|
||||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
|
|
||||||
mBackgroundItem->setName(mName + "_Model");
|
|
||||||
mBackgroundItem->setFillColor(mFillColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mBackgroundItem->updateMesh(std::move(mesh));
|
|
||||||
}
|
|
||||||
mGeometryIsDirty = false;
|
mGeometryIsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +108,7 @@ void CircleNode::update(SceneInfo* sceneInfo)
|
||||||
|
|
||||||
if (mMaterialIsDirty)
|
if (mMaterialIsDirty)
|
||||||
{
|
{
|
||||||
mBackgroundItem->setFillColor(mFillColor);
|
updateMaterial();
|
||||||
mMaterialIsDirty = false;
|
mMaterialIsDirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,22 @@ class CircleNode : public GeometryNode
|
||||||
public:
|
public:
|
||||||
CircleNode(const Point& location, double radius);
|
CircleNode(const Point& location, double radius);
|
||||||
|
|
||||||
Type getType();
|
Type getType() override;
|
||||||
|
|
||||||
double getRadius() const;
|
double getRadius() const;
|
||||||
|
|
||||||
SceneItem* getSceneItem(std::size_t idx) const override;
|
SceneItem* getSceneItem(std::size_t idx) const override;
|
||||||
std::size_t getNumSceneItems() const override;
|
std::size_t getNumSceneItems() const override;
|
||||||
|
|
||||||
|
void setMinorRadius(double radius);
|
||||||
void setRadius(double radius);
|
void setRadius(double radius);
|
||||||
|
|
||||||
void update(SceneInfo* sceneInfo) override;
|
void update(SceneInfo* sceneInfo) override;
|
||||||
private:
|
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> mBackgroundItem;
|
||||||
std::unique_ptr<SceneModel> mOutlineItem;
|
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");
|
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)
|
void RectangleNode::update(SceneInfo* sceneInfo)
|
||||||
{
|
{
|
||||||
if (!mBackgroundItem || mGeometryIsDirty)
|
if (!mBackgroundItem || mGeometryIsDirty)
|
||||||
|
@ -96,20 +113,13 @@ void RectangleNode::update(SceneInfo* sceneInfo)
|
||||||
|
|
||||||
if (mTransformIsDirty)
|
if (mTransformIsDirty)
|
||||||
{
|
{
|
||||||
mBackgroundItem->updateTransform({mLocation, static_cast<double>(mWidth), static_cast<double>(mHeight)});
|
mBackgroundItem->updateTransform({mLocation, mWidth, mHeight});
|
||||||
mTransformIsDirty = false;
|
mTransformIsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMaterialIsDirty)
|
if (mMaterialIsDirty)
|
||||||
{
|
{
|
||||||
if (mHasFillColor)
|
updateMaterial();
|
||||||
{
|
|
||||||
mBackgroundItem->setFillColor(mFillColor);
|
|
||||||
}
|
|
||||||
if (mHasStrokeColor)
|
|
||||||
{
|
|
||||||
mBackgroundItem->setOutlineColor(mStrokeColor);
|
|
||||||
}
|
|
||||||
mMaterialIsDirty = false;
|
mMaterialIsDirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
void updateMaterial();
|
||||||
double mWidth{1};
|
double mWidth{1};
|
||||||
double mHeight{1};
|
double mHeight{1};
|
||||||
|
|
||||||
|
|
|
@ -27,23 +27,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
unsigned mStrokeThickness{0};
|
unsigned mStrokeThickness{0};
|
||||||
Type mType;
|
Type mType;
|
||||||
|
|
||||||
bool mGeometryIsDirty{true};
|
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>;
|
using GeometryNodePtr = std::unique_ptr<GeometryNode>;
|
||||||
|
|
|
@ -20,8 +20,19 @@ const Color& MaterialNode::getStrokeColor() const
|
||||||
return mStrokeColor;
|
return mStrokeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MaterialNode::setHasStrokeColor(bool hasStroke)
|
||||||
|
{
|
||||||
|
if (mHasStrokeColor != hasStroke)
|
||||||
|
{
|
||||||
|
mHasStrokeColor = hasStroke;
|
||||||
|
mMaterialIsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MaterialNode::setFillColor(const Color& color)
|
void MaterialNode::setFillColor(const Color& color)
|
||||||
{
|
{
|
||||||
|
mHasFillColor = true;
|
||||||
|
|
||||||
if (mFillColor != color)
|
if (mFillColor != color)
|
||||||
{
|
{
|
||||||
mMaterialIsDirty = true;
|
mMaterialIsDirty = true;
|
||||||
|
@ -31,6 +42,8 @@ void MaterialNode::setFillColor(const Color& color)
|
||||||
|
|
||||||
void MaterialNode::setStrokeColor(const Color& color)
|
void MaterialNode::setStrokeColor(const Color& color)
|
||||||
{
|
{
|
||||||
|
mHasStrokeColor = true;
|
||||||
|
|
||||||
if (mStrokeColor != color)
|
if (mStrokeColor != color)
|
||||||
{
|
{
|
||||||
mMaterialIsDirty = true;
|
mMaterialIsDirty = true;
|
||||||
|
|
|
@ -12,6 +12,8 @@ public:
|
||||||
const Color& getFillColor() const;
|
const Color& getFillColor() const;
|
||||||
const Color& getStrokeColor() const;
|
const Color& getStrokeColor() const;
|
||||||
|
|
||||||
|
void setHasStrokeColor(bool hasStroke);
|
||||||
|
|
||||||
void setFillColor(const Color& color);
|
void setFillColor(const Color& color);
|
||||||
void setStrokeColor(const Color& color);
|
void setStrokeColor(const Color& color);
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ void Scene::setBackgroundColor(const Color& color)
|
||||||
|
|
||||||
void Scene::updateNode(AbstractVisualNode* node)
|
void Scene::updateNode(AbstractVisualNode* node)
|
||||||
{
|
{
|
||||||
|
node->update(mSceneInfo.get());
|
||||||
|
|
||||||
for (auto child : node->getChildren())
|
for (auto child : node->getChildren())
|
||||||
{
|
{
|
||||||
if (child->getIsVisible())
|
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++)
|
for (std::size_t idx=0; idx< node->getNumSceneItems(); idx++)
|
||||||
{
|
{
|
||||||
if (auto item = node->getSceneItem(idx))
|
if (auto item = node->getSceneItem(idx))
|
||||||
|
|
|
@ -27,6 +27,11 @@ list(APPEND web_LIB_INCLUDES
|
||||||
html/elements/HtmlHeadElement.cpp
|
html/elements/HtmlHeadElement.cpp
|
||||||
html/elements/HtmlBodyElement.cpp
|
html/elements/HtmlBodyElement.cpp
|
||||||
html/elements/HtmlParagraphElement.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/SvgDocument.cpp
|
||||||
svg/SvgWriter.cpp
|
svg/SvgWriter.cpp
|
||||||
svg/SvgShapeElement.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)
|
void SvgShapeElement::setFill(const Color& fill)
|
||||||
{
|
{
|
||||||
auto attr = std::make_unique<XmlAttribute>("fill");
|
auto attr = std::make_unique<XmlAttribute>("fill");
|
||||||
|
|
|
@ -10,8 +10,11 @@ public:
|
||||||
|
|
||||||
void setFill(const Color& fill);
|
void setFill(const Color& fill);
|
||||||
|
|
||||||
|
void setNoFill();
|
||||||
|
|
||||||
void setStrokeWidth(double width);
|
void setStrokeWidth(double width);
|
||||||
|
|
||||||
void setStrokeColor(const Color& stroke);
|
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 cx = std::make_unique<XmlAttribute>("cx");
|
||||||
auto cy = std::make_unique<XmlAttribute>("cy");
|
auto cy = std::make_unique<XmlAttribute>("cy");
|
||||||
|
|
||||||
cx->setValue(std::to_string(loc.GetX()));
|
cx->setValue(std::to_string(loc.getX()));
|
||||||
cy->setValue(std::to_string(loc.GetY()));
|
cy->setValue(std::to_string(loc.getY()));
|
||||||
|
|
||||||
addAttribute(std::move(cx));
|
addAttribute(std::move(cx));
|
||||||
addAttribute(std::move(cy));
|
addAttribute(std::move(cy));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgCircle::setRadius(unsigned rad)
|
void SvgCircle::setRadius(double rad)
|
||||||
{
|
{
|
||||||
auto r = std::make_unique<XmlAttribute>("r");
|
auto r = std::make_unique<XmlAttribute>("r");
|
||||||
r->setValue(std::to_string(rad));
|
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 x = std::make_unique<XmlAttribute>("x");
|
||||||
auto y = std::make_unique<XmlAttribute>("y");
|
auto y = std::make_unique<XmlAttribute>("y");
|
||||||
|
|
||||||
x->setValue(std::to_string(loc.GetX()));
|
x->setValue(std::to_string(loc.getX()));
|
||||||
y->setValue(std::to_string(loc.GetY()));
|
y->setValue(std::to_string(loc.getY()));
|
||||||
|
|
||||||
addAttribute(std::move(x));
|
addAttribute(std::move(x));
|
||||||
addAttribute(std::move(y));
|
addAttribute(std::move(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgRectangle::setWidth(unsigned w)
|
void SvgRectangle::setWidth(double w)
|
||||||
{
|
{
|
||||||
auto width = std::make_unique<XmlAttribute>("width");
|
auto width = std::make_unique<XmlAttribute>("width");
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ void SvgRectangle::setWidth(unsigned w)
|
||||||
addAttribute(std::move(width));
|
addAttribute(std::move(width));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgRectangle::setHeight(unsigned h)
|
void SvgRectangle::setHeight(double h)
|
||||||
{
|
{
|
||||||
auto height = std::make_unique<XmlAttribute>("height");
|
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");
|
auto points = std::make_unique<XmlAttribute>("points");
|
||||||
|
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
for (const auto& loc : locs)
|
for (const auto& loc : locs)
|
||||||
{
|
{
|
||||||
sstr << loc.GetX() << "," << loc.GetY() << " ";
|
sstr << loc.getX() << "," << loc.getY() << " ";
|
||||||
}
|
}
|
||||||
points->setValue(sstr.str());
|
points->setValue(sstr.str());
|
||||||
addAttribute(std::move(points));
|
addAttribute(std::move(points));
|
||||||
|
@ -91,14 +91,14 @@ SvgPolyline::SvgPolyline()
|
||||||
addAttribute(std::move(fill));
|
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");
|
auto points = std::make_unique<XmlAttribute>("points");
|
||||||
|
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
for (const auto& loc : locs)
|
for (const auto& loc : locs)
|
||||||
{
|
{
|
||||||
sstr << loc.GetX() << "," << loc.GetY() << " ";
|
sstr << loc.getX() << "," << loc.getY() << " ";
|
||||||
}
|
}
|
||||||
points->setValue(sstr.str());
|
points->setValue(sstr.str());
|
||||||
addAttribute(std::move(points));
|
addAttribute(std::move(points));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "SvgShapeElement.h"
|
#include "SvgShapeElement.h"
|
||||||
#include "DiscretePoint.h"
|
#include "Point.h"
|
||||||
|
|
||||||
#include "XmlAttribute.h"
|
#include "XmlAttribute.h"
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ class SvgCircle : public SvgShapeElement
|
||||||
public:
|
public:
|
||||||
SvgCircle();
|
SvgCircle();
|
||||||
|
|
||||||
void setLocation(const DiscretePoint& loc);
|
void setLocation(const Point& loc);
|
||||||
|
|
||||||
void setRadius(unsigned rad);
|
void setRadius(double rad);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SvgRectangle : public SvgShapeElement
|
class SvgRectangle : public SvgShapeElement
|
||||||
|
@ -20,11 +20,11 @@ class SvgRectangle : public SvgShapeElement
|
||||||
public:
|
public:
|
||||||
SvgRectangle();
|
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
|
class SvgPolygon : public SvgShapeElement
|
||||||
|
@ -32,7 +32,7 @@ class SvgPolygon : public SvgShapeElement
|
||||||
public:
|
public:
|
||||||
SvgPolygon();
|
SvgPolygon();
|
||||||
|
|
||||||
void setPoints(const std::vector<DiscretePoint>& loc);
|
void setPoints(const std::vector<Point>& loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SvgPolyline : public SvgShapeElement
|
class SvgPolyline : public SvgShapeElement
|
||||||
|
@ -40,7 +40,7 @@ class SvgPolyline : public SvgShapeElement
|
||||||
public:
|
public:
|
||||||
SvgPolyline();
|
SvgPolyline();
|
||||||
|
|
||||||
void setPoints(const std::vector<DiscretePoint>& loc);
|
void setPoints(const std::vector<Point>& loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SvgPath : public SvgShapeElement
|
class SvgPath : public SvgShapeElement
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
#include "DrawingSurface.h"
|
#include "DrawingSurface.h"
|
||||||
#include "DrawingContext.h"
|
#include "DrawingContext.h"
|
||||||
#include "AbstractPainter.h"
|
#include "AbstractPainter.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
|
||||||
|
#include "SvgConverter.h"
|
||||||
|
#include "SvgWriter.h"
|
||||||
|
#include "SvgDocument.h"
|
||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "PngWriter.h"
|
#include "PngWriter.h"
|
||||||
#include "Scene.h"
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
class TestRenderer
|
class TestRenderer
|
||||||
{
|
{
|
||||||
|
@ -34,6 +41,18 @@ public:
|
||||||
writer.write(image);
|
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:
|
private:
|
||||||
std::unique_ptr<DrawingSurface> mSurface;
|
std::unique_ptr<DrawingSurface> mSurface;
|
||||||
std::unique_ptr<DrawingContext> mDrawingContext;
|
std::unique_ptr<DrawingContext> mDrawingContext;
|
||||||
|
|
Loading…
Reference in a new issue