Add path rendering.
This commit is contained in:
parent
f2ab532005
commit
97afa782a0
39 changed files with 1148 additions and 131 deletions
227
src/rendering/visual_elements/svg/SvgPainter.cpp
Normal file
227
src/rendering/visual_elements/svg/SvgPainter.cpp
Normal file
|
@ -0,0 +1,227 @@
|
|||
#include "SvgPainter.h"
|
||||
|
||||
#include "SvgDocument.h"
|
||||
#include "Scene.h"
|
||||
|
||||
#include "SceneItem.h"
|
||||
#include "SceneModel.h"
|
||||
#include "SceneText.h"
|
||||
|
||||
#include "AbstractGeometricItem.h"
|
||||
#include "AbstractMesh.h"
|
||||
#include "TriMesh.h"
|
||||
#include "AbstractFace.h"
|
||||
|
||||
#include "Circle.h"
|
||||
#include "Rectangle.h"
|
||||
#include "Path.h"
|
||||
|
||||
#include "SvgShapeElements.h"
|
||||
#include "SvgTextElement.h"
|
||||
#include "XmlAttribute.h"
|
||||
|
||||
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())
|
||||
{
|
||||
if (item->getType() == SceneItem::Type::MODEL)
|
||||
{
|
||||
auto model = dynamic_cast<SceneModel*>(item);
|
||||
if (model->getGeometry())
|
||||
{
|
||||
paintPrimitive(doc.get(), model);
|
||||
}
|
||||
else
|
||||
{
|
||||
paintMesh(doc.get(), model, scene->shouldShowMeshOutline());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto text = dynamic_cast<SceneText*>(item);
|
||||
paintText(doc.get(), text);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(doc);
|
||||
}
|
||||
|
||||
void SvgPainter::paintMesh(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 SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
|
||||
{
|
||||
auto transform = model->getTransform();
|
||||
|
||||
if (model->hasFillColor())
|
||||
{
|
||||
element->setFill(model->getFillColor());
|
||||
auto opacity = static_cast<float>(model->getFillColor().getAlpha());
|
||||
if (opacity != 1.0)
|
||||
{
|
||||
element->setFillOpacity(opacity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
element->setNoFill();
|
||||
}
|
||||
|
||||
if (model->hasOutlineColor())
|
||||
{
|
||||
element->setStrokeColor(model->getOutlineColor());
|
||||
element->setStrokeWidth(model->getOutlineThickness());
|
||||
}
|
||||
else
|
||||
{
|
||||
element->setNoStroke();
|
||||
}
|
||||
|
||||
if (!transform.isDefaultTransform())
|
||||
{
|
||||
element->addAttribute(std::move(toTransform(transform)));
|
||||
}
|
||||
}
|
||||
|
||||
void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
|
||||
{
|
||||
paintRect(document, model);
|
||||
}
|
||||
else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::CIRCLE)
|
||||
{
|
||||
paintCircle(document, model);
|
||||
}
|
||||
else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::PATH)
|
||||
{
|
||||
paintPath(document, model);
|
||||
}
|
||||
}
|
||||
|
||||
void SvgPainter::paintRect(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_rect = dynamic_cast<ntk::Rectangle*>(model->getGeometry());
|
||||
|
||||
auto rect = std::make_unique<SvgRectangle>();
|
||||
rect->setWidth(model_rect->getWidth());
|
||||
rect->setHeight(model_rect->getHeight());
|
||||
|
||||
if (model_rect->getRadius() > 0.0)
|
||||
{
|
||||
rect->setRadius(model_rect->getRadius());
|
||||
}
|
||||
|
||||
setStyle(model, rect.get());
|
||||
document->getRoot()->addChild(std::move(rect));
|
||||
}
|
||||
|
||||
void SvgPainter::paintCircle(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_circle = dynamic_cast<Circle*>(model->getGeometry());
|
||||
|
||||
auto is_ellipse = model_circle->getMinorRadius() != model_circle->getRadius();
|
||||
auto circle = std::make_unique<SvgCircle>(model_circle->isEllipse() ? SvgCircle::Type::ELLIPSE : SvgCircle::Type::REGULAR);
|
||||
circle->setRadius(model_circle->getRadius());
|
||||
if (model_circle->isEllipse())
|
||||
{
|
||||
circle->setMinorRadius(model_circle->getMinorRadius());
|
||||
}
|
||||
|
||||
setStyle(model, circle.get());
|
||||
document->getRoot()->addChild(std::move(circle));
|
||||
}
|
||||
|
||||
void SvgPainter::paintPath(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_path = dynamic_cast<GeometryPath*>(model->getGeometry());
|
||||
|
||||
auto path_string = model_path->getAsPostScript();
|
||||
|
||||
auto svg_path = std::make_unique<SvgPath>();
|
||||
svg_path->setPath(path_string);
|
||||
|
||||
setStyle(model, svg_path.get());
|
||||
document->getRoot()->addChild(std::move(svg_path));
|
||||
}
|
||||
|
||||
void SvgPainter::paintText(SvgDocument* document, SceneText* text) const
|
||||
{
|
||||
auto svg_text = std::make_unique<SvgTextElement>();
|
||||
svg_text->setContent(text->getTextData().mContent);
|
||||
auto loc = text->getTransform().getLocation();
|
||||
|
||||
loc.move(text->getTextWidth() / 2.0, text->getTextHeight()/2.0);
|
||||
svg_text->setLocation(loc);
|
||||
|
||||
svg_text->setFontFamily(text->getTextData().mFont.getFaceName());
|
||||
svg_text->setFill(text->getFillColor());
|
||||
auto opacity = static_cast<float>(text->getFillColor().getAlpha());
|
||||
if (opacity != 1.0)
|
||||
{
|
||||
svg_text->setFillOpacity(opacity);
|
||||
}
|
||||
|
||||
svg_text->setFontSize(text->getTextData().mFont.getSize());
|
||||
|
||||
document->getRoot()->addChild(std::move(svg_text));
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlAttribute> SvgPainter::toTransform(const Transform& transform) const
|
||||
{
|
||||
auto svg_transform = std::make_unique<XmlAttribute>("transform");
|
||||
|
||||
std::string ops;
|
||||
if (!transform.hasDefaultLocation())
|
||||
{
|
||||
ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") ";
|
||||
}
|
||||
if (!transform.hasDefaultScale())
|
||||
{
|
||||
ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") ";
|
||||
}
|
||||
svg_transform->setValue(ops);
|
||||
|
||||
return std::move(svg_transform);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue