Add svg conversion.

This commit is contained in:
jmsgrogan 2023-01-17 17:41:27 +00:00
parent 1f85954e98
commit dfbc87cb09
33 changed files with 602 additions and 79 deletions

View file

@ -27,4 +27,17 @@ double Transform::getScaleY() const
double Transform::getScaleZ() const
{
return mScaleZ;
}
void Transform::setLocation(const Point& loc)
{
mLocation = loc;
}
void Transform::setScale(double scaleX, double scaleY, double scaleZ)
{
mScaleX = scaleX;
mScaleY = scaleY;
mScaleZ = scaleZ;
}

View file

@ -7,6 +7,10 @@ class Transform
public:
Transform(const Point& location = {}, double scaleX = 1.0, double scaleY = 1.0, double scaleZ = 1.0);
void setLocation(const Point& loc);
void setScale(double scaleX, double scaleY = 1.0, double scaleZ = 1.0);
const Point& getLocation() const;
double getScaleX() const;

View file

@ -89,3 +89,10 @@ void Point::apply(const Transform& transform)
mY *= transform.getScaleY();
mZ *= transform.getScaleZ();
}
void Point::move(double x, double y, double z)
{
mX += x;
mY += y;
mZ += z;
}

View file

@ -23,6 +23,8 @@ public:
void apply(const Transform& transform);
void move(double x, double y, double z = 0);
double getX() const;
double getY() const;

View file

@ -10,12 +10,13 @@ list(APPEND publishing_HEADERS
pdf/PdfXRefTable.h
pdf/PdfWriter.h
plotting/GraphPlotter.h
plotting/SvgConverter.h
plotting/PlotNode.h
plotting/EquationNode.h
latex/LatexDocument.h
latex/LatexMathExpression.h
latex/LatexSymbols.h
svg/SvgNode.h
svg/SvgPainter.h
DocumentConverter.h
)
@ -34,10 +35,11 @@ list(APPEND publishing_LIB_INCLUDES
latex/LatexMathExpression.cpp
latex/LatexSymbols.cpp
plotting/GraphPlotter.h
plotting/SvgConverter.cpp
plotting/PlotNode.cpp
plotting/EquationNode.cpp
DocumentConverter.cpp
svg/SvgNode.cpp
svg/SvgPainter.cpp
)
add_library(publishing SHARED ${publishing_LIB_INCLUDES} ${publishing_INCLUDES} ${publishing_HEADERS})
@ -47,6 +49,7 @@ target_include_directories(publishing PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/pdf
${CMAKE_CURRENT_SOURCE_DIR}/plotting
${CMAKE_CURRENT_SOURCE_DIR}/latex
${CMAKE_CURRENT_SOURCE_DIR}/svg
)
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_link_libraries( publishing PUBLIC core web graphics visual_elements)

View file

@ -1,30 +0,0 @@
#pragma once
#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, 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;
};

View file

@ -0,0 +1,90 @@
#include "SvgNode.h"
#include "CircleNode.h"
#include "SvgShapeElements.h"
SvgNode::SvgNode(const Point& location)
: AbstractVisualNode(location)
{
}
void SvgNode::setContent(std::unique_ptr<SvgDocument> doc)
{
mContent = std::move(doc);
mContentDirty = true;
mChildren.clear();
mManagedChildren.clear();
}
void SvgNode::updateTransform()
{
}
void SvgNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
{
if (!mContent->getRoot())
{
return;
}
auto viewbox = mContent->getViewBox();
for (const auto& svg_element : mContent->getRoot()->getChildren())
{
std::unique_ptr<AbstractVisualNode> node;
if (svg_element->getTagName() == "circle")
{
auto svg_circle = dynamic_cast<SvgCircle*>(svg_element.get());
auto loc = svg_circle->getLocation();
auto radius = svg_circle->getRadius();
auto minor_radius = radius;
if (svg_circle->getType() == SvgCircle::Type::ELLIPSE)
{
minor_radius = svg_circle->getMinorRadius();
}
if (svg_element->hasAttribute("transform"))
{
const auto transform = svg_circle->getTransform();
loc.move(transform.getLocation().getX(), transform.getLocation().getY());
radius *= transform.getScaleX();
minor_radius *= transform.getScaleY();
}
auto circle_node = std::make_unique<CircleNode>(loc, radius);
circle_node->setMinorRadius(minor_radius);
node = std::move(circle_node);
}
if (!node)
{
continue;
}
auto raw_node = node.get();
mManagedChildren.push_back(std::move(node));
addChild(raw_node);
}
}
void SvgNode::update(SceneInfo* sceneInfo)
{
if (mContent && mContentDirty)
{
createOrUpdateGeometry(sceneInfo);
mContentDirty = false;
}
if (mTransformIsDirty)
{
updateTransform();
mTransformIsDirty = false;
}
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "AbstractVisualNode.h"
#include "SvgDocument.h"
#include <memory>
#include <vector>
class SvgNode : public AbstractVisualNode
{
public:
SvgNode(const Point& location);
void setContent(std::unique_ptr<SvgDocument> doc);
void update(SceneInfo* sceneInfo);
private:
void createOrUpdateGeometry(SceneInfo* sceneInfo);
void updateTransform();
bool mContentDirty{ true };
std::vector<std::unique_ptr<AbstractVisualNode> > mManagedChildren;
std::unique_ptr<SvgDocument> mContent;
};

View file

@ -1,4 +1,4 @@
#include "SvgConverter.h"
#include "SvgPainter.h"
#include "SvgDocument.h"
#include "Scene.h"
@ -17,38 +17,38 @@
#include "SvgShapeElements.h"
#include "XmlAttribute.h"
std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene, double width, double height) const
std::unique_ptr<SvgDocument> SvgPainter::paint(Scene* scene, double width, double height) const
{
auto doc = std::make_unique<SvgDocument>();
doc->setViewBox(0.0, 0.0, width, height);
scene->update();
for(auto item : scene->getItems())
for (auto item : scene->getItems())
{
if (item->getType() == SceneItem::Type::MODEL)
{
auto model = dynamic_cast<SceneModel*>(item);
if (model->getGeometry())
{
convertPrimitive(doc.get(), model);
paintPrimitive(doc.get(), model);
}
else
{
convertMesh(doc.get(), model, scene->shouldShowMeshOutline());
paintMesh(doc.get(), model, scene->shouldShowMeshOutline());
}
}
else
{
auto text = dynamic_cast<SceneText*>(item);
convertText(doc.get(), text);
paintText(doc.get(), text);
}
}
return std::move(doc);
}
void SvgConverter::convertMesh(SvgDocument* document, SceneModel* model, bool showOutline) const
void SvgPainter::paintMesh(SvgDocument* document, SceneModel* model, bool showOutline) const
{
auto mesh = model->getMesh();
auto transform = model->getTransform();
@ -87,7 +87,7 @@ void SvgConverter::convertMesh(SvgDocument* document, SceneModel* model, bool sh
}
}
void SvgConverter::setStyle(SceneModel* model, SvgShapeElement* element) const
void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
{
auto transform = model->getTransform();
@ -111,7 +111,7 @@ void SvgConverter::setStyle(SceneModel* model, SvgShapeElement* element) const
element->addAttribute(std::move(toTransform(transform)));
}
void SvgConverter::convertPrimitive(SvgDocument* document, SceneModel* model) const
void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const
{
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
{
@ -139,12 +139,12 @@ void SvgConverter::convertPrimitive(SvgDocument* document, SceneModel* model) co
}
}
void SvgConverter::convertText(SvgDocument* document, SceneText* model) const
void SvgPainter::paintText(SvgDocument* document, SceneText* model) const
{
}
std::unique_ptr<XmlAttribute> SvgConverter::toTransform(const Transform& transform) const
std::unique_ptr<XmlAttribute> SvgPainter::toTransform(const Transform& transform) const
{
auto svg_transform = std::make_unique<XmlAttribute>("transform");

View file

@ -0,0 +1,32 @@
#pragma once
#include "AbstractPainter.h"
#include <memory>
class SvgDocument;
class SvgShapeElement;
class XmlAttribute;
class Scene;
class SceneModel;
class SceneText;
class Transform;
class SvgPainter
{
public:
std::unique_ptr<SvgDocument> paint(Scene* scene, double width = 800.0, double height = 800.0) const;
private:
void paintMesh(SvgDocument* document, SceneModel* model, bool showOutline = false) const;
void paintPrimitive(SvgDocument* document, SceneModel* model) const;
void paintText(SvgDocument* document, SceneText* model) const;
void setStyle(SceneModel* model, SvgShapeElement* element) const;
std::unique_ptr<XmlAttribute> toTransform(const Transform& transform) const;
};

View file

@ -3,6 +3,8 @@
#include "DirectX2dInterface.h"
#include "AbstractGeometricItem.h"
#include "Rectangle.h"
#include "Circle.h"
#include "SceneModel.h"
void DirectX2dPainter::startDrawing()
@ -49,6 +51,25 @@ void DirectX2dPainter::paint(SceneModel* model)
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
}
}
else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::CIRCLE)
{
const auto loc = model->getTransform().getLocation();
const auto scale_x = model->getTransform().getScaleX();
const auto scale_y = model->getTransform().getScaleY();
auto circle = dynamic_cast<Circle*>(model->getGeometry());
const auto radius = circle->getRadius() * scale_x;
const auto radiusy = circle->getMinorRadius() * scale_y;
D2D1_POINT_2F d2d_centre{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY()) };
D2D1_ELLIPSE ellipse{ d2d_centre, static_cast<float>(radius), static_cast<float>(radiusy) };
if (model->hasOutlineColor())
{
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor()));
rt->DrawEllipse(ellipse, mSolidBrush.Get(), 1.0f);
}
}
}
void DirectX2dPainter::setD2dInterface(DirectX2dInterface* d2dIterface)

View file

@ -29,10 +29,12 @@ list(APPEND web_LIB_INCLUDES
html/elements/HtmlParagraphElement.cpp
svg/SvgDocument.h
svg/SvgWriter.h
svg/SvgReader.h
svg/SvgShapeElement.h
svg/SvgElement.h
svg/elements/SvgShapeElements.h
svg/SvgDocument.cpp
svg/SvgReader.cpp
svg/SvgWriter.cpp
svg/SvgShapeElement.cpp
svg/SvgElement.cpp

View file

@ -10,7 +10,7 @@ std::string HtmlParagraphElement::toString(unsigned depth, bool keepInline) cons
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
}
const auto num_children = getNumChildren();
const auto num_children = mChildren.size();
if (num_children == 0 && getText().empty())
{
content += "/>\n";
@ -30,9 +30,9 @@ std::string HtmlParagraphElement::toString(unsigned depth, bool keepInline) cons
{
content += "\n";
}
for (std::size_t idx=0; idx< getNumChildren(); idx++)
for(const auto& child : mChildren)
{
auto child = getChild(idx);
content += child->toString(depth+1, true);
}
if (num_children>0)

View file

@ -1,6 +1,7 @@
#include "SvgDocument.h"
#include "XmlAttribute.h"
#include "StringUtils.h"
#include <sstream>
@ -19,10 +20,39 @@ SvgDocument::SvgDocument()
void SvgDocument::setViewBox(double x, double y, double w, double h)
{
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
std::stringstream sstr;
sstr << x << " " << y << " " << w << " " << h;
viewbox->setValue(sstr.str());
setViewBox(sstr.str());
}
void SvgDocument::setViewBox(const std::string& data)
{
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
viewbox->setValue(data);
getRoot()->addAttribute(std::move(viewbox));
}
SvgDocument::ViewBox SvgDocument::getViewBox() const
{
ViewBox viewBox;
if (!getRoot())
{
return viewBox;
}
if (auto vb_attr = getRoot()->getAttribute("viewBox"); vb_attr)
{
auto entries = StringUtils::split(vb_attr->getValue());
if (entries.size() != 4)
{
return viewBox;
}
viewBox.mX = std::stod(entries[0]);
viewBox.mY = std::stod(entries[1]);
viewBox.mW = std::stod(entries[2]);
viewBox.mH = std::stod(entries[3]);
}
return viewBox;
}

View file

@ -5,6 +5,18 @@
class SvgDocument : public XmlDocument
{
public:
struct ViewBox
{
double mX{ 0 };
double mY{ 0 };
double mW{ 0 };
double mH{ 0 };
};
SvgDocument();
ViewBox getViewBox() const;
void setViewBox(const std::string& data);
void setViewBox(double x, double y, double w, double h);
};

76
src/web/svg/SvgReader.cpp Normal file
View file

@ -0,0 +1,76 @@
#include "SvgReader.h"
#include "File.h"
#include "XmlParser.h"
#include "XmlAttribute.h"
#include "SvgShapeElements.h"
#include "FileLogger.h"
std::unique_ptr<SvgDocument> SvgReader::read(const Path& path) const
{
auto svg_doc = std::make_unique<SvgDocument>();
File in_file(path);
auto lines = in_file.readLines();
XmlParser parser;
for (const auto& line : lines)
{
parser.processLine(line);
}
auto xml_doc = parser.getDocument();
if (xml_doc->getRoot() && xml_doc->getRoot()->getTagName() == "svg")
{
onRoot(xml_doc->getRoot(), svg_doc.get());
}
return svg_doc;
}
void SvgReader::onRoot(XmlElement* element, SvgDocument* doc) const
{
for (const auto& attr : element->getAttributes())
{
doc->getRoot()->addAttribute(attr.first, attr.second->getValue());
}
for (const auto& child : element->getChildren())
{
onChild(child.get(), doc->getRoot());
}
}
void SvgReader::onChild(XmlElement* element, XmlElement* svg_parent) const
{
std::unique_ptr<XmlElement> new_svg;
if (element->getTagName() == "circle")
{
new_svg = std::make_unique<SvgCircle>();
}
else if (element->getTagName() == "ellipse")
{
new_svg = std::make_unique<SvgCircle>(SvgCircle::Type::ELLIPSE);
}
else if (element->getTagName() == "rect")
{
new_svg = std::make_unique<SvgRectangle>();
}
else
{
return;
}
for (const auto& attr : element->getAttributes())
{
new_svg->addAttribute(attr.first, attr.second->getValue());
}
for (const auto& child : element->getChildren())
{
onChild(child.get(), new_svg.get());
}
svg_parent->addChild(std::move(new_svg));
}

20
src/web/svg/SvgReader.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include "SvgDocument.h"
#include <filesystem>
using Path = std::filesystem::path;
class SvgElement;
class SvgReader
{
public:
std::unique_ptr<SvgDocument> read(const Path& path) const;
private:
void onRoot(XmlElement* element, SvgDocument* doc) const;
void onChild(XmlElement* element, XmlElement* svg_parent) const;
};

View file

@ -1,6 +1,7 @@
#include "SvgShapeElement.h"
#include "XmlAttribute.h"
#include "StringUtils.h"
#include <sstream>
@ -10,6 +11,96 @@ SvgShapeElement::SvgShapeElement(const std::string& tagName)
}
Transform SvgShapeElement::getTransform() const
{
Transform transform;
const std::string translate_key = "translate";
const std::string scale_key = "scale";
if (auto attr = getAttribute("transform"); attr)
{
const auto val = attr->getValue();
std::string working_string;
bool in_translate = false;
bool in_scale = false;
for (auto c : val)
{
if (StringUtils::stripSurroundingWhitepsace(working_string) == translate_key)
{
in_translate = true;
working_string.clear();
continue;
}
else if (StringUtils::stripSurroundingWhitepsace(working_string) == scale_key)
{
in_scale = true;
working_string.clear();
continue;
}
else if (c == '(')
{
continue;
}
else if (c == ')')
{
if (in_translate)
{
const auto loc = parsePoint(working_string, 0.0);
transform.setLocation(loc);
in_translate = false;
}
else if (in_scale)
{
const auto loc = parsePoint(working_string, 1.0);
transform.setScale(loc.getX(), loc.getY(), loc.getZ());
in_scale = false;
}
working_string.clear();
}
else
{
working_string += c;
}
}
}
return transform;
}
std::string SvgShapeElement::getLabelledContent(const std::string& key, const std::string& content) const
{
return content.substr(key.size(), content.size() - key.size() - 2);
}
Point SvgShapeElement::parsePoint(const std::string& pointString, double defaultVal) const
{
double x = defaultVal;
double y = defaultVal;
double z = defaultVal;
const auto split = StringUtils::split(pointString);
for (std::size_t idx = 0; idx < split.size(); idx++)
{
if (idx == 0)
{
x = std::stod(split[idx]);
}
else if (idx == 1)
{
y = std::stod(split[idx]);
}
else if (idx == 2)
{
z = std::stod(split[idx]);
}
}
return { x, y, z };
}
bool SvgShapeElement::hasTransform() const
{
return bool(getAttribute("transform"));
}
void SvgShapeElement::setNoFill()
{
auto attr = std::make_unique<XmlAttribute>("fill");

View file

@ -2,12 +2,17 @@
#include "SvgElement.h"
#include "Color.h"
#include "Transform.h"
class SvgShapeElement : public SvgElement
{
public:
SvgShapeElement(const std::string& tagName);
Transform getTransform() const;
bool hasTransform() const;
void setFill(const Color& fill);
void setNoFill();
@ -17,4 +22,8 @@ public:
void setStrokeColor(const Color& stroke);
void setNoStroke();
private:
std::string getLabelledContent(const std::string& key, const std::string& content) const;
Point parsePoint(const std::string& pointString, double defaultVal = 0.0) const;
};

View file

@ -1,8 +1,9 @@
#include "SvgWriter.h"
#include "SvgDocument.h"
#include "File.h"
std::string SvgWriter::toString(SvgDocument* document)
std::string SvgWriter::toString(SvgDocument* document) const
{
std::string content = "";
if (auto root = document->getRoot())
@ -11,3 +12,9 @@ std::string SvgWriter::toString(SvgDocument* document)
}
return content;
}
void SvgWriter::toFile(const Path& path, SvgDocument* document) const
{
File out_file(path);
out_file.writeText(toString(document));
}

View file

@ -1,11 +1,16 @@
#pragma once
#include <string>
#include <filesystem>
using Path = std::filesystem::path;
class SvgDocument;
class SvgWriter
{
public:
std::string toString(SvgDocument* document);
std::string toString(SvgDocument* document) const;
void toFile(const Path& path, SvgDocument* document) const;
};

View file

@ -9,6 +9,50 @@ SvgCircle::SvgCircle(Type type)
}
Point SvgCircle::getLocation() const
{
double cx = 0.0;
double cy = 0.0;
if (auto attr = getAttribute("cx"); attr)
{
cx = std::stod(attr->getValue());
}
if (auto attr = getAttribute("cy"); attr)
{
cy = std::stod(attr->getValue());
}
return { cx, cy };
}
double SvgCircle::getRadius() const
{
double radius = 1.0;
if (auto attr = getAttribute("rx"); attr)
{
radius = std::stod(attr->getValue());
}
else if (auto attr = getAttribute("r"); attr)
{
radius = std::stod(attr->getValue());
}
return radius;
}
SvgCircle::Type SvgCircle::getType() const
{
return mType;
}
double SvgCircle::getMinorRadius() const
{
double radius = 0.0;
if (auto attr = getAttribute("ry"); attr)
{
radius = std::stod(attr->getValue());
}
return radius;
}
void SvgCircle::setLocation(const Point& loc)
{
auto cx = std::make_unique<XmlAttribute>("cx");

View file

@ -16,6 +16,14 @@ public:
SvgCircle(Type type = Type::REGULAR);
Point getLocation() const;
double getRadius() const;
Type getType() const;
double getMinorRadius() const;
void setLocation(const Point& loc);
void setRadius(double rad);

View file

@ -193,6 +193,7 @@ void XmlParser::onRightBracket()
case LS::Await_Attribute_Name:
case LS::Await_Attribute_Name_End:
case LS::Await_Attribute_Value:
case LS::Await_Tag_Inline_Close:
{
onTagClose();
break;
@ -220,13 +221,21 @@ void XmlParser::onQuestionMark()
void XmlParser::onForwardSlash()
{
if(mLineState == LS::Await_Tag_Follower)
if (mLineState == LS::Await_Tag_Follower)
{
if(mDocumentState == DS::Await_Element || mDocumentState == DS::Build_Element)
if (mDocumentState == DS::Await_Element || mDocumentState == DS::Build_Element)
{
mDocumentState = DS::Close_Element;
}
}
else if(mLineState == LS::Await_Attribute_Name)
{
mLineState = LS::Await_Tag_Inline_Close;
}
else
{
onNonAlphaNumeric(StringUtils::FORWARD_SLASH);
}
}
void XmlParser::onEquals()
@ -270,6 +279,13 @@ void XmlParser::onTagClose()
{
onTagNameEnd();
}
else if (mLineState == LS::Await_Tag_Inline_Close)
{
if (!mWorkingElements.empty())
{
mWorkingElements.pop();
}
}
onElementTagEnd();
}
else if(mDocumentState == DS::Close_Element)

View file

@ -27,6 +27,7 @@ public:
Await_Tag_Follower,
Await_Tag_Name,
Await_Tag_Name_End,
Await_Tag_Inline_Close,
Await_Attribute_Name,
Await_Attribute_Name_End,
Await_Attribute_Value,
@ -82,8 +83,6 @@ private:
void onAttributeValueEnd();
void onPrologId();
void onStartProlog();
void onFinishProlog();

View file

@ -34,6 +34,13 @@ void XmlElement::addAttribute(XmlAttributePtr attribute)
mAttributes[attribute->getName()] = std::move(attribute);
}
void XmlElement::addAttribute(const std::string& name, const std::string& value)
{
auto attr = std::make_unique<XmlAttribute>(name);
attr->setValue(value);
addAttribute(std::move(attr));
}
const std::string& XmlElement::getTagName() const
{
return mTagName;
@ -62,6 +69,11 @@ XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag)
return nullptr;
}
bool XmlElement::hasAttribute(const std::string& attribute) const
{
return (bool)(getAttribute(attribute));
}
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
{
if (auto iter = mAttributes.find(attributeName); iter != mAttributes.end())
@ -76,14 +88,9 @@ const std::unordered_map<std::string, XmlAttributePtr>& XmlElement::getAttribute
return mAttributes;
}
std::size_t XmlElement::getNumChildren() const
const std::vector<std::unique_ptr<XmlElement> >& XmlElement::getChildren() const
{
return mChildren.size();
}
XmlElement* XmlElement::getChild(std::size_t index) const
{
return mChildren[index].get();
return mChildren;
}
std::string XmlElement::toString(unsigned depth, bool keepInline) const
@ -98,7 +105,7 @@ std::string XmlElement::toString(unsigned depth, bool keepInline) const
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
}
const auto num_children = getNumChildren();
const auto num_children = mChildren.size();
if (num_children == 0 && getText().empty())
{
content += "/>" + line_ending;
@ -118,9 +125,9 @@ std::string XmlElement::toString(unsigned depth, bool keepInline) const
{
content += line_ending;
}
for (std::size_t idx=0; idx< getNumChildren(); idx++)
for(const auto& child : mChildren)
{
auto child = getChild(idx);
content += child->toString(depth+1, keepInline);
}
if (num_children>0)

View file

@ -17,15 +17,17 @@ public:
static std::unique_ptr<XmlElement> Create(const std::string& tagName);
void addAttribute(XmlAttributePtr attribute);
void addAttribute(const std::string& name, const std::string& value);
void addChild(std::unique_ptr<XmlElement> child);
const std::string& getTagName() const;
const std::string& getText() const;
bool hasAttribute(const std::string& attribute) const;
XmlAttribute* getAttribute(const std::string& attribute) const;
const std::unordered_map<std::string, XmlAttributePtr>& getAttributes() const;
std::size_t getNumChildren() const;
XmlElement* getChild(std::size_t index) const;
const std::vector<std::unique_ptr<XmlElement> >& getChildren() const;
XmlElement* getFirstChildWithTagName(const std::string& tag);

5
test/data/circles.svg Normal file
View file

@ -0,0 +1,5 @@
<svg viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg">
<ellipse rx="0.500000" stroke-width="0.005000" ry="0.250000" fill="none" stroke="rgb(0,0,0)" transform="translate(50.000000 50.000000) scale(100.000000 100.000000) "/>
<circle stroke="rgb(0,0,0)" r="0.500000" fill="none" stroke-width="0.010000" transform="translate(50.000000 50.000000) scale(100.000000 100.000000) "/>
<circle stroke="none" r="0.500000" fill="rgb(0,0,0)" transform="translate(50.000000 50.000000) scale(4.000000 4.000000) "/>
</svg>

After

Width:  |  Height:  |  Size: 520 B

View file

@ -34,11 +34,9 @@ TEST_CASE(TestD2dWidgetRendering, "graphics")
auto scene = gui_app->getMainWindowScene();
Widget widget;
widget.setBackgroundColor({ 0, 200, 0 });
widget.setBounds(300, 300);
auto button = Button::Create();
button->setBackgroundColor({ 200, 0, 0 });
button->setLabel("Test Button");
button->setMaxWidth(100);

View file

@ -1,7 +1,8 @@
set(PUBLISHING_UNIT_TEST_FILES
publishing/TestPdfWriter.cpp
publishing/TestDocumentConverter.cpp
publishing/TestSvgConverter.cpp
publishing/TestSvgConverter.cpp
publishing/TestSvgToNodeConverter.cpp
publishing/TestLatexConverter.cpp
PARENT_SCOPE
)

View file

@ -1,6 +1,6 @@
#include "SvgWriter.h"
#include "SvgDocument.h"
#include "SvgConverter.h"
#include "SvgPainter.h"
#include "Scene.h"
#include "CircleNode.h"
@ -24,13 +24,10 @@ TEST_CASE(TestSvgConverter, "[publishing]")
//rectangle.setFillColor({255, 0, 0});
//scene.addNode(&rectangle);
SvgConverter converter;
auto svg_document = converter.convert(&scene);
SvgPainter painter;
auto svg_document = painter.paint(&scene);
svg_document->setViewBox(0, 0, 200, 200);
SvgWriter writer;
auto content = writer.toString(svg_document.get());
auto outFile = std::make_unique<File>(TestUtils::getTestOutputDir(__FILE__) / "scene.svg");
outFile->writeText(content);
writer.toFile(TestUtils::getTestOutputDir(__FILE__) / "scene.svg", svg_document.get());
}

View file

@ -0,0 +1,25 @@
#include "TestFramework.h"
#include "TestRenderUtils.h"
#include "TestUtils.h"
#include "SvgReader.h"
#include "SvgWriter.h"
#include "SvgNode.h"
TEST_CASE(TestSvgToNodeConverter, "publishing")
{
SvgReader svg_reader;
auto svg_doc = svg_reader.read(TestUtils::getTestDataDir() / "circles.svg");
SvgWriter svg_writer;
svg_writer.toFile(TestUtils::getTestOutputDir(__FILE__) / "TestSvgToNodeConverter.svg", svg_doc.get());
TestRenderer renderer;
auto svg_node = std::make_unique<SvgNode>(Point(0.0, 0.0));
svg_node->setContent(std::move(svg_doc));
renderer.getScene()->addNode(svg_node.get());
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "TestSvgToNodeConverter.png");
}

View file

@ -5,7 +5,7 @@
#include "AbstractPainter.h"
#include "Scene.h"
#include "SvgConverter.h"
#include "SvgPainter.h"
#include "SvgWriter.h"
#include "SvgDocument.h"
@ -25,6 +25,8 @@ public:
mDrawingContext = std::make_unique<DrawingContext>(mSurface.get());
}
Scene* getScene() const
{
return mSurface->getScene();
@ -47,8 +49,8 @@ public:
static void writeSvg(const Path& path, Scene* scene)
{
SvgConverter converter;
auto svg_document = converter.convert(scene);
SvgPainter painter;
auto svg_document = painter.paint(scene);
SvgWriter writer;
auto svg_content = writer.toString(svg_document.get());