Improve node to svg conversion.

This commit is contained in:
jmsgrogan 2023-01-12 17:45:06 +00:00
parent 64f0b3e77a
commit 26ecae46b3
22 changed files with 403 additions and 126 deletions

View file

@ -5,16 +5,22 @@
#include "SceneItem.h"
#include "SceneModel.h"
#include "SceneText.h"
#include "AbstractGeometricItem.h"
#include "AbstractMesh.h"
#include "TriMesh.h"
#include "AbstractFace.h"
#include "SvgShapeElements.h"
#include "Circle.h"
std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene)
#include "SvgShapeElements.h"
#include "XmlAttribute.h"
std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene, double width, double height) const
{
auto doc = std::make_unique<SvgDocument>();
doc->setViewBox(0.0, 0.0, width, height);
scene->update();
@ -22,44 +28,125 @@ std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene)
{
if (item->getType() == SceneItem::Type::MODEL)
{
auto mesh = dynamic_cast<SceneModel*>(item)->getMesh();
auto transform = item->getTransform();
if (mesh->getType() == AbstractMesh::MeshType::TRI)
auto model = dynamic_cast<SceneModel*>(item);
if (model->getGeometry())
{
for(const auto& face : dynamic_cast<TriMesh*>(mesh)->getFaces())
{
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));
}
}
convertPrimitive(doc.get(), model);
}
else
{
convertMesh(doc.get(), model, scene->shouldShowMeshOutline());
}
}
else
{
auto text = dynamic_cast<SceneText*>(item);
convertText(doc.get(), text);
}
}
return std::move(doc);
}
void SvgConverter::convertMesh(SvgDocument* document, SceneModel* model, bool showOutline) const
{
auto mesh = model->getMesh();
auto transform = model->getTransform();
if (mesh->getType() == AbstractMesh::MeshType::TRI)
{
for (const auto& face : dynamic_cast<TriMesh*>(mesh)->getFaces())
{
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);
}

View file

@ -3,10 +3,28 @@
#include <memory>
class SvgDocument;
class SvgShapeElement;
class XmlAttribute;
class Scene;
class SceneModel;
class SceneText;
class Transform;
class SvgConverter
{
public:
std::unique_ptr<SvgDocument> convert(Scene* scene);
std::unique_ptr<SvgDocument> convert(Scene* scene, double width = 800.0, double height = 800.0) const;
private:
void convertMesh(SvgDocument* document, SceneModel* model, bool showOutline = false) const;
void convertPrimitive(SvgDocument* document, SceneModel* model) const;
void convertText(SvgDocument* document, SceneText* model) const;
void setStyle(SceneModel* model, SvgShapeElement* element) const;
std::unique_ptr<XmlAttribute> toTransform(const Transform& transform) const;
};