Add svg conversion.
This commit is contained in:
parent
1f85954e98
commit
dfbc87cb09
33 changed files with 602 additions and 79 deletions
|
@ -27,4 +27,17 @@ double Transform::getScaleY() const
|
||||||
double Transform::getScaleZ() const
|
double Transform::getScaleZ() const
|
||||||
{
|
{
|
||||||
return mScaleZ;
|
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;
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,6 +7,10 @@ class Transform
|
||||||
public:
|
public:
|
||||||
Transform(const Point& location = {}, double scaleX = 1.0, double scaleY = 1.0, double scaleZ = 1.0);
|
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;
|
const Point& getLocation() const;
|
||||||
|
|
||||||
double getScaleX() const;
|
double getScaleX() const;
|
||||||
|
|
|
@ -89,3 +89,10 @@ void Point::apply(const Transform& transform)
|
||||||
mY *= transform.getScaleY();
|
mY *= transform.getScaleY();
|
||||||
mZ *= transform.getScaleZ();
|
mZ *= transform.getScaleZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Point::move(double x, double y, double z)
|
||||||
|
{
|
||||||
|
mX += x;
|
||||||
|
mY += y;
|
||||||
|
mZ += z;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ public:
|
||||||
|
|
||||||
void apply(const Transform& transform);
|
void apply(const Transform& transform);
|
||||||
|
|
||||||
|
void move(double x, double y, double z = 0);
|
||||||
|
|
||||||
double getX() const;
|
double getX() const;
|
||||||
|
|
||||||
double getY() const;
|
double getY() const;
|
||||||
|
|
|
@ -10,12 +10,13 @@ list(APPEND publishing_HEADERS
|
||||||
pdf/PdfXRefTable.h
|
pdf/PdfXRefTable.h
|
||||||
pdf/PdfWriter.h
|
pdf/PdfWriter.h
|
||||||
plotting/GraphPlotter.h
|
plotting/GraphPlotter.h
|
||||||
plotting/SvgConverter.h
|
|
||||||
plotting/PlotNode.h
|
plotting/PlotNode.h
|
||||||
plotting/EquationNode.h
|
plotting/EquationNode.h
|
||||||
latex/LatexDocument.h
|
latex/LatexDocument.h
|
||||||
latex/LatexMathExpression.h
|
latex/LatexMathExpression.h
|
||||||
latex/LatexSymbols.h
|
latex/LatexSymbols.h
|
||||||
|
svg/SvgNode.h
|
||||||
|
svg/SvgPainter.h
|
||||||
DocumentConverter.h
|
DocumentConverter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,10 +35,11 @@ list(APPEND publishing_LIB_INCLUDES
|
||||||
latex/LatexMathExpression.cpp
|
latex/LatexMathExpression.cpp
|
||||||
latex/LatexSymbols.cpp
|
latex/LatexSymbols.cpp
|
||||||
plotting/GraphPlotter.h
|
plotting/GraphPlotter.h
|
||||||
plotting/SvgConverter.cpp
|
|
||||||
plotting/PlotNode.cpp
|
plotting/PlotNode.cpp
|
||||||
plotting/EquationNode.cpp
|
plotting/EquationNode.cpp
|
||||||
DocumentConverter.cpp
|
DocumentConverter.cpp
|
||||||
|
svg/SvgNode.cpp
|
||||||
|
svg/SvgPainter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(publishing SHARED ${publishing_LIB_INCLUDES} ${publishing_INCLUDES} ${publishing_HEADERS})
|
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}/pdf
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plotting
|
${CMAKE_CURRENT_SOURCE_DIR}/plotting
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/latex
|
${CMAKE_CURRENT_SOURCE_DIR}/latex
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/svg
|
||||||
)
|
)
|
||||||
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
target_link_libraries( publishing PUBLIC core web graphics visual_elements)
|
target_link_libraries( publishing PUBLIC core web graphics visual_elements)
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
90
src/publishing/svg/SvgNode.cpp
Normal file
90
src/publishing/svg/SvgNode.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
25
src/publishing/svg/SvgNode.h
Normal file
25
src/publishing/svg/SvgNode.h
Normal 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;
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
#include "SvgConverter.h"
|
#include "SvgPainter.h"
|
||||||
|
|
||||||
#include "SvgDocument.h"
|
#include "SvgDocument.h"
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
|
@ -17,38 +17,38 @@
|
||||||
#include "SvgShapeElements.h"
|
#include "SvgShapeElements.h"
|
||||||
#include "XmlAttribute.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>();
|
auto doc = std::make_unique<SvgDocument>();
|
||||||
doc->setViewBox(0.0, 0.0, width, height);
|
doc->setViewBox(0.0, 0.0, width, height);
|
||||||
|
|
||||||
scene->update();
|
scene->update();
|
||||||
|
|
||||||
for(auto item : scene->getItems())
|
for (auto item : scene->getItems())
|
||||||
{
|
{
|
||||||
if (item->getType() == SceneItem::Type::MODEL)
|
if (item->getType() == SceneItem::Type::MODEL)
|
||||||
{
|
{
|
||||||
auto model = dynamic_cast<SceneModel*>(item);
|
auto model = dynamic_cast<SceneModel*>(item);
|
||||||
if (model->getGeometry())
|
if (model->getGeometry())
|
||||||
{
|
{
|
||||||
convertPrimitive(doc.get(), model);
|
paintPrimitive(doc.get(), model);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
convertMesh(doc.get(), model, scene->shouldShowMeshOutline());
|
paintMesh(doc.get(), model, scene->shouldShowMeshOutline());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto text = dynamic_cast<SceneText*>(item);
|
auto text = dynamic_cast<SceneText*>(item);
|
||||||
convertText(doc.get(), text);
|
paintText(doc.get(), text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(doc);
|
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 mesh = model->getMesh();
|
||||||
auto transform = model->getTransform();
|
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();
|
auto transform = model->getTransform();
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ void SvgConverter::setStyle(SceneModel* model, SvgShapeElement* element) const
|
||||||
element->addAttribute(std::move(toTransform(transform)));
|
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)
|
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");
|
auto svg_transform = std::make_unique<XmlAttribute>("transform");
|
||||||
|
|
32
src/publishing/svg/SvgPainter.h
Normal file
32
src/publishing/svg/SvgPainter.h
Normal 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;
|
||||||
|
};
|
|
@ -3,6 +3,8 @@
|
||||||
#include "DirectX2dInterface.h"
|
#include "DirectX2dInterface.h"
|
||||||
#include "AbstractGeometricItem.h"
|
#include "AbstractGeometricItem.h"
|
||||||
#include "Rectangle.h"
|
#include "Rectangle.h"
|
||||||
|
#include "Circle.h"
|
||||||
|
|
||||||
#include "SceneModel.h"
|
#include "SceneModel.h"
|
||||||
|
|
||||||
void DirectX2dPainter::startDrawing()
|
void DirectX2dPainter::startDrawing()
|
||||||
|
@ -49,6 +51,25 @@ void DirectX2dPainter::paint(SceneModel* model)
|
||||||
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
|
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)
|
void DirectX2dPainter::setD2dInterface(DirectX2dInterface* d2dIterface)
|
||||||
|
|
|
@ -29,10 +29,12 @@ list(APPEND web_LIB_INCLUDES
|
||||||
html/elements/HtmlParagraphElement.cpp
|
html/elements/HtmlParagraphElement.cpp
|
||||||
svg/SvgDocument.h
|
svg/SvgDocument.h
|
||||||
svg/SvgWriter.h
|
svg/SvgWriter.h
|
||||||
|
svg/SvgReader.h
|
||||||
svg/SvgShapeElement.h
|
svg/SvgShapeElement.h
|
||||||
svg/SvgElement.h
|
svg/SvgElement.h
|
||||||
svg/elements/SvgShapeElements.h
|
svg/elements/SvgShapeElements.h
|
||||||
svg/SvgDocument.cpp
|
svg/SvgDocument.cpp
|
||||||
|
svg/SvgReader.cpp
|
||||||
svg/SvgWriter.cpp
|
svg/SvgWriter.cpp
|
||||||
svg/SvgShapeElement.cpp
|
svg/SvgShapeElement.cpp
|
||||||
svg/SvgElement.cpp
|
svg/SvgElement.cpp
|
||||||
|
|
|
@ -10,7 +10,7 @@ std::string HtmlParagraphElement::toString(unsigned depth, bool keepInline) cons
|
||||||
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto num_children = getNumChildren();
|
const auto num_children = mChildren.size();
|
||||||
if (num_children == 0 && getText().empty())
|
if (num_children == 0 && getText().empty())
|
||||||
{
|
{
|
||||||
content += "/>\n";
|
content += "/>\n";
|
||||||
|
@ -30,9 +30,9 @@ std::string HtmlParagraphElement::toString(unsigned depth, bool keepInline) cons
|
||||||
{
|
{
|
||||||
content += "\n";
|
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);
|
content += child->toString(depth+1, true);
|
||||||
}
|
}
|
||||||
if (num_children>0)
|
if (num_children>0)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "SvgDocument.h"
|
#include "SvgDocument.h"
|
||||||
|
|
||||||
#include "XmlAttribute.h"
|
#include "XmlAttribute.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -19,10 +20,39 @@ SvgDocument::SvgDocument()
|
||||||
|
|
||||||
void SvgDocument::setViewBox(double x, double y, double w, double h)
|
void SvgDocument::setViewBox(double x, double y, double w, double h)
|
||||||
{
|
{
|
||||||
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
|
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << x << " " << y << " " << w << " " << h;
|
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));
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,18 @@
|
||||||
class SvgDocument : public XmlDocument
|
class SvgDocument : public XmlDocument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct ViewBox
|
||||||
|
{
|
||||||
|
double mX{ 0 };
|
||||||
|
double mY{ 0 };
|
||||||
|
double mW{ 0 };
|
||||||
|
double mH{ 0 };
|
||||||
|
};
|
||||||
|
|
||||||
SvgDocument();
|
SvgDocument();
|
||||||
|
|
||||||
|
ViewBox getViewBox() const;
|
||||||
|
|
||||||
|
void setViewBox(const std::string& data);
|
||||||
void setViewBox(double x, double y, double w, double h);
|
void setViewBox(double x, double y, double w, double h);
|
||||||
};
|
};
|
||||||
|
|
76
src/web/svg/SvgReader.cpp
Normal file
76
src/web/svg/SvgReader.cpp
Normal 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
20
src/web/svg/SvgReader.h
Normal 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;
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
#include "SvgShapeElement.h"
|
#include "SvgShapeElement.h"
|
||||||
|
|
||||||
#include "XmlAttribute.h"
|
#include "XmlAttribute.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <sstream>
|
#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()
|
void SvgShapeElement::setNoFill()
|
||||||
{
|
{
|
||||||
auto attr = std::make_unique<XmlAttribute>("fill");
|
auto attr = std::make_unique<XmlAttribute>("fill");
|
||||||
|
|
|
@ -2,12 +2,17 @@
|
||||||
|
|
||||||
#include "SvgElement.h"
|
#include "SvgElement.h"
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
|
#include "Transform.h"
|
||||||
|
|
||||||
class SvgShapeElement : public SvgElement
|
class SvgShapeElement : public SvgElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SvgShapeElement(const std::string& tagName);
|
SvgShapeElement(const std::string& tagName);
|
||||||
|
|
||||||
|
Transform getTransform() const;
|
||||||
|
|
||||||
|
bool hasTransform() const;
|
||||||
|
|
||||||
void setFill(const Color& fill);
|
void setFill(const Color& fill);
|
||||||
|
|
||||||
void setNoFill();
|
void setNoFill();
|
||||||
|
@ -17,4 +22,8 @@ public:
|
||||||
void setStrokeColor(const Color& stroke);
|
void setStrokeColor(const Color& stroke);
|
||||||
|
|
||||||
void setNoStroke();
|
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "SvgWriter.h"
|
#include "SvgWriter.h"
|
||||||
|
|
||||||
#include "SvgDocument.h"
|
#include "SvgDocument.h"
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
std::string SvgWriter::toString(SvgDocument* document)
|
std::string SvgWriter::toString(SvgDocument* document) const
|
||||||
{
|
{
|
||||||
std::string content = "";
|
std::string content = "";
|
||||||
if (auto root = document->getRoot())
|
if (auto root = document->getRoot())
|
||||||
|
@ -11,3 +12,9 @@ std::string SvgWriter::toString(SvgDocument* document)
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SvgWriter::toFile(const Path& path, SvgDocument* document) const
|
||||||
|
{
|
||||||
|
File out_file(path);
|
||||||
|
out_file.writeText(toString(document));
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
class SvgDocument;
|
class SvgDocument;
|
||||||
|
|
||||||
class SvgWriter
|
class SvgWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string toString(SvgDocument* document);
|
std::string toString(SvgDocument* document) const;
|
||||||
|
|
||||||
|
void toFile(const Path& path, SvgDocument* document) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
void SvgCircle::setLocation(const Point& loc)
|
||||||
{
|
{
|
||||||
auto cx = std::make_unique<XmlAttribute>("cx");
|
auto cx = std::make_unique<XmlAttribute>("cx");
|
||||||
|
|
|
@ -16,6 +16,14 @@ public:
|
||||||
|
|
||||||
SvgCircle(Type type = Type::REGULAR);
|
SvgCircle(Type type = Type::REGULAR);
|
||||||
|
|
||||||
|
Point getLocation() const;
|
||||||
|
|
||||||
|
double getRadius() const;
|
||||||
|
|
||||||
|
Type getType() const;
|
||||||
|
|
||||||
|
double getMinorRadius() const;
|
||||||
|
|
||||||
void setLocation(const Point& loc);
|
void setLocation(const Point& loc);
|
||||||
|
|
||||||
void setRadius(double rad);
|
void setRadius(double rad);
|
||||||
|
|
|
@ -193,6 +193,7 @@ void XmlParser::onRightBracket()
|
||||||
case LS::Await_Attribute_Name:
|
case LS::Await_Attribute_Name:
|
||||||
case LS::Await_Attribute_Name_End:
|
case LS::Await_Attribute_Name_End:
|
||||||
case LS::Await_Attribute_Value:
|
case LS::Await_Attribute_Value:
|
||||||
|
case LS::Await_Tag_Inline_Close:
|
||||||
{
|
{
|
||||||
onTagClose();
|
onTagClose();
|
||||||
break;
|
break;
|
||||||
|
@ -220,13 +221,21 @@ void XmlParser::onQuestionMark()
|
||||||
|
|
||||||
void XmlParser::onForwardSlash()
|
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;
|
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()
|
void XmlParser::onEquals()
|
||||||
|
@ -270,6 +279,13 @@ void XmlParser::onTagClose()
|
||||||
{
|
{
|
||||||
onTagNameEnd();
|
onTagNameEnd();
|
||||||
}
|
}
|
||||||
|
else if (mLineState == LS::Await_Tag_Inline_Close)
|
||||||
|
{
|
||||||
|
if (!mWorkingElements.empty())
|
||||||
|
{
|
||||||
|
mWorkingElements.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
onElementTagEnd();
|
onElementTagEnd();
|
||||||
}
|
}
|
||||||
else if(mDocumentState == DS::Close_Element)
|
else if(mDocumentState == DS::Close_Element)
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
Await_Tag_Follower,
|
Await_Tag_Follower,
|
||||||
Await_Tag_Name,
|
Await_Tag_Name,
|
||||||
Await_Tag_Name_End,
|
Await_Tag_Name_End,
|
||||||
|
Await_Tag_Inline_Close,
|
||||||
Await_Attribute_Name,
|
Await_Attribute_Name,
|
||||||
Await_Attribute_Name_End,
|
Await_Attribute_Name_End,
|
||||||
Await_Attribute_Value,
|
Await_Attribute_Value,
|
||||||
|
@ -82,8 +83,6 @@ private:
|
||||||
|
|
||||||
void onAttributeValueEnd();
|
void onAttributeValueEnd();
|
||||||
|
|
||||||
void onPrologId();
|
|
||||||
|
|
||||||
void onStartProlog();
|
void onStartProlog();
|
||||||
|
|
||||||
void onFinishProlog();
|
void onFinishProlog();
|
||||||
|
|
|
@ -34,6 +34,13 @@ void XmlElement::addAttribute(XmlAttributePtr attribute)
|
||||||
mAttributes[attribute->getName()] = std::move(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
|
const std::string& XmlElement::getTagName() const
|
||||||
{
|
{
|
||||||
return mTagName;
|
return mTagName;
|
||||||
|
@ -62,6 +69,11 @@ XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool XmlElement::hasAttribute(const std::string& attribute) const
|
||||||
|
{
|
||||||
|
return (bool)(getAttribute(attribute));
|
||||||
|
}
|
||||||
|
|
||||||
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
|
XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
|
||||||
{
|
{
|
||||||
if (auto iter = mAttributes.find(attributeName); iter != mAttributes.end())
|
if (auto iter = mAttributes.find(attributeName); iter != mAttributes.end())
|
||||||
|
@ -76,14 +88,9 @@ const std::unordered_map<std::string, XmlAttributePtr>& XmlElement::getAttribute
|
||||||
return mAttributes;
|
return mAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t XmlElement::getNumChildren() const
|
const std::vector<std::unique_ptr<XmlElement> >& XmlElement::getChildren() const
|
||||||
{
|
{
|
||||||
return mChildren.size();
|
return mChildren;
|
||||||
}
|
|
||||||
|
|
||||||
XmlElement* XmlElement::getChild(std::size_t index) const
|
|
||||||
{
|
|
||||||
return mChildren[index].get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XmlElement::toString(unsigned depth, bool keepInline) const
|
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() + "\"";
|
content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto num_children = getNumChildren();
|
const auto num_children = mChildren.size();
|
||||||
if (num_children == 0 && getText().empty())
|
if (num_children == 0 && getText().empty())
|
||||||
{
|
{
|
||||||
content += "/>" + line_ending;
|
content += "/>" + line_ending;
|
||||||
|
@ -118,9 +125,9 @@ std::string XmlElement::toString(unsigned depth, bool keepInline) const
|
||||||
{
|
{
|
||||||
content += line_ending;
|
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);
|
content += child->toString(depth+1, keepInline);
|
||||||
}
|
}
|
||||||
if (num_children>0)
|
if (num_children>0)
|
||||||
|
|
|
@ -17,15 +17,17 @@ public:
|
||||||
static std::unique_ptr<XmlElement> Create(const std::string& tagName);
|
static std::unique_ptr<XmlElement> Create(const std::string& tagName);
|
||||||
|
|
||||||
void addAttribute(XmlAttributePtr attribute);
|
void addAttribute(XmlAttributePtr attribute);
|
||||||
|
void addAttribute(const std::string& name, const std::string& value);
|
||||||
void addChild(std::unique_ptr<XmlElement> child);
|
void addChild(std::unique_ptr<XmlElement> child);
|
||||||
|
|
||||||
const std::string& getTagName() const;
|
const std::string& getTagName() const;
|
||||||
const std::string& getText() const;
|
const std::string& getText() const;
|
||||||
|
|
||||||
|
bool hasAttribute(const std::string& attribute) const;
|
||||||
XmlAttribute* getAttribute(const std::string& attribute) const;
|
XmlAttribute* getAttribute(const std::string& attribute) const;
|
||||||
const std::unordered_map<std::string, XmlAttributePtr>& getAttributes() const;
|
const std::unordered_map<std::string, XmlAttributePtr>& getAttributes() const;
|
||||||
|
|
||||||
std::size_t getNumChildren() const;
|
const std::vector<std::unique_ptr<XmlElement> >& getChildren() const;
|
||||||
XmlElement* getChild(std::size_t index) const;
|
|
||||||
|
|
||||||
XmlElement* getFirstChildWithTagName(const std::string& tag);
|
XmlElement* getFirstChildWithTagName(const std::string& tag);
|
||||||
|
|
||||||
|
|
5
test/data/circles.svg
Normal file
5
test/data/circles.svg
Normal 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 |
|
@ -34,11 +34,9 @@ TEST_CASE(TestD2dWidgetRendering, "graphics")
|
||||||
auto scene = gui_app->getMainWindowScene();
|
auto scene = gui_app->getMainWindowScene();
|
||||||
|
|
||||||
Widget widget;
|
Widget widget;
|
||||||
widget.setBackgroundColor({ 0, 200, 0 });
|
|
||||||
widget.setBounds(300, 300);
|
widget.setBounds(300, 300);
|
||||||
|
|
||||||
auto button = Button::Create();
|
auto button = Button::Create();
|
||||||
button->setBackgroundColor({ 200, 0, 0 });
|
|
||||||
button->setLabel("Test Button");
|
button->setLabel("Test Button");
|
||||||
button->setMaxWidth(100);
|
button->setMaxWidth(100);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
set(PUBLISHING_UNIT_TEST_FILES
|
set(PUBLISHING_UNIT_TEST_FILES
|
||||||
publishing/TestPdfWriter.cpp
|
publishing/TestPdfWriter.cpp
|
||||||
publishing/TestDocumentConverter.cpp
|
publishing/TestDocumentConverter.cpp
|
||||||
publishing/TestSvgConverter.cpp
|
publishing/TestSvgConverter.cpp
|
||||||
|
publishing/TestSvgToNodeConverter.cpp
|
||||||
publishing/TestLatexConverter.cpp
|
publishing/TestLatexConverter.cpp
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "SvgWriter.h"
|
#include "SvgWriter.h"
|
||||||
#include "SvgDocument.h"
|
#include "SvgDocument.h"
|
||||||
#include "SvgConverter.h"
|
#include "SvgPainter.h"
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
|
|
||||||
#include "CircleNode.h"
|
#include "CircleNode.h"
|
||||||
|
@ -24,13 +24,10 @@ TEST_CASE(TestSvgConverter, "[publishing]")
|
||||||
//rectangle.setFillColor({255, 0, 0});
|
//rectangle.setFillColor({255, 0, 0});
|
||||||
//scene.addNode(&rectangle);
|
//scene.addNode(&rectangle);
|
||||||
|
|
||||||
SvgConverter converter;
|
SvgPainter painter;
|
||||||
auto svg_document = converter.convert(&scene);
|
auto svg_document = painter.paint(&scene);
|
||||||
svg_document->setViewBox(0, 0, 200, 200);
|
svg_document->setViewBox(0, 0, 200, 200);
|
||||||
|
|
||||||
SvgWriter writer;
|
SvgWriter writer;
|
||||||
auto content = writer.toString(svg_document.get());
|
writer.toFile(TestUtils::getTestOutputDir(__FILE__) / "scene.svg", svg_document.get());
|
||||||
|
|
||||||
auto outFile = std::make_unique<File>(TestUtils::getTestOutputDir(__FILE__) / "scene.svg");
|
|
||||||
outFile->writeText(content);
|
|
||||||
}
|
}
|
||||||
|
|
25
test/publishing/TestSvgToNodeConverter.cpp
Normal file
25
test/publishing/TestSvgToNodeConverter.cpp
Normal 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");
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
#include "AbstractPainter.h"
|
#include "AbstractPainter.h"
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
|
|
||||||
#include "SvgConverter.h"
|
#include "SvgPainter.h"
|
||||||
#include "SvgWriter.h"
|
#include "SvgWriter.h"
|
||||||
#include "SvgDocument.h"
|
#include "SvgDocument.h"
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ public:
|
||||||
mDrawingContext = std::make_unique<DrawingContext>(mSurface.get());
|
mDrawingContext = std::make_unique<DrawingContext>(mSurface.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Scene* getScene() const
|
Scene* getScene() const
|
||||||
{
|
{
|
||||||
return mSurface->getScene();
|
return mSurface->getScene();
|
||||||
|
@ -47,8 +49,8 @@ public:
|
||||||
|
|
||||||
static void writeSvg(const Path& path, Scene* scene)
|
static void writeSvg(const Path& path, Scene* scene)
|
||||||
{
|
{
|
||||||
SvgConverter converter;
|
SvgPainter painter;
|
||||||
auto svg_document = converter.convert(scene);
|
auto svg_document = painter.paint(scene);
|
||||||
|
|
||||||
SvgWriter writer;
|
SvgWriter writer;
|
||||||
auto svg_content = writer.toString(svg_document.get());
|
auto svg_content = writer.toString(svg_document.get());
|
||||||
|
|
Loading…
Reference in a new issue