Add path rendering and svg line output.
This commit is contained in:
parent
73051a5f27
commit
6274c41a80
15 changed files with 281 additions and 79 deletions
|
@ -3,7 +3,8 @@
|
|||
#include "PointParser.h"
|
||||
#include <sstream>
|
||||
|
||||
Arc::Arc(const Point& startPoint, const Point& endPoint, double rX, double rY, double rotation, bool largeArc, bool sweep)
|
||||
namespace ntk {
|
||||
Arc::Arc(const Point& startPoint, const Point& endPoint, double rX, double rY, double rotation, bool largeArc, bool sweep)
|
||||
: mStartPoint(startPoint),
|
||||
mEndPoint(endPoint),
|
||||
mRx(rX),
|
||||
|
@ -11,22 +12,22 @@ Arc::Arc(const Point& startPoint, const Point& endPoint, double rX, double rY, d
|
|||
mRotation(rotation),
|
||||
mLargeArc(largeArc),
|
||||
mSweep(sweep)
|
||||
{
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Point Arc::getFirstPoint() const
|
||||
{
|
||||
Point Arc::getFirstPoint() const
|
||||
{
|
||||
return mStartPoint;
|
||||
}
|
||||
}
|
||||
|
||||
Point Arc::getEndPoint() const
|
||||
{
|
||||
Point Arc::getEndPoint() const
|
||||
{
|
||||
return mEndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Arc::toPostScriptString(std::size_t precision) const
|
||||
{
|
||||
std::string Arc::toPostScriptString(std::size_t precision) const
|
||||
{
|
||||
const auto large = mLargeArc ? "1" : "0";
|
||||
const auto sweep = mSweep ? "1" : "0";
|
||||
std::stringstream sstr;
|
||||
|
@ -52,29 +53,55 @@ std::string Arc::toPostScriptString(std::size_t precision) const
|
|||
sstr << PointParser::toString(mEndPoint, 2, " ", precision);
|
||||
}
|
||||
return sstr.str();
|
||||
}
|
||||
}
|
||||
|
||||
Bounds Arc::getBounds() const
|
||||
{
|
||||
Bounds Arc::getBounds() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const Point& Arc::getLocation() const
|
||||
{
|
||||
const Point& Arc::getLocation() const
|
||||
{
|
||||
return mStartPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void Arc::sample(SparseGrid<bool>*) const
|
||||
{
|
||||
void Arc::sample(SparseGrid<bool>*) const
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Arc::Type Arc::getType() const
|
||||
{
|
||||
Arc::Type Arc::getType() const
|
||||
{
|
||||
return Type::CURVE;
|
||||
}
|
||||
}
|
||||
|
||||
Arc::CurveType Arc::getCurveType() const
|
||||
{
|
||||
Arc::CurveType Arc::getCurveType() const
|
||||
{
|
||||
return CurveType::ARC;
|
||||
}
|
||||
|
||||
double Arc::getRx() const
|
||||
{
|
||||
return mRx;
|
||||
}
|
||||
|
||||
double Arc::getRy() const
|
||||
{
|
||||
return mRy;
|
||||
}
|
||||
|
||||
double Arc::getRotation() const
|
||||
{
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
bool Arc::getUseLargeArc() const
|
||||
{
|
||||
return mLargeArc;
|
||||
}
|
||||
|
||||
bool Arc::getSweepParam() const
|
||||
{
|
||||
return mSweep;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Curve.h"
|
||||
#include "Point.h"
|
||||
|
||||
namespace ntk{
|
||||
class Arc : public Curve
|
||||
{
|
||||
public:
|
||||
|
@ -20,6 +21,16 @@ public:
|
|||
|
||||
CurveType getCurveType() const override;
|
||||
|
||||
double getRx() const;
|
||||
|
||||
double getRy() const;
|
||||
|
||||
double getRotation() const;
|
||||
|
||||
bool getUseLargeArc() const;
|
||||
|
||||
bool getSweepParam() const;
|
||||
|
||||
void sample(SparseGrid<bool>*) const override;
|
||||
|
||||
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||
|
@ -33,3 +44,4 @@ private:
|
|||
bool mLargeArc{ false };
|
||||
bool mSweep{ false };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,6 +21,16 @@ Point CubicBezierCurve::getEndPoint() const
|
|||
return mEndPoint;
|
||||
}
|
||||
|
||||
const Point& CubicBezierCurve::getStartControlPoint() const
|
||||
{
|
||||
return mStartControlPoint;
|
||||
}
|
||||
|
||||
const Point& CubicBezierCurve::getEndControlPoint() const
|
||||
{
|
||||
return mEndControlPoint;
|
||||
}
|
||||
|
||||
std::string CubicBezierCurve::toPostScriptString(std::size_t precision) const
|
||||
{
|
||||
if (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO)
|
||||
|
|
|
@ -12,6 +12,10 @@ public:
|
|||
|
||||
Point getEndPoint() const override;
|
||||
|
||||
const Point& getStartControlPoint() const;
|
||||
|
||||
const Point& getEndControlPoint() const;
|
||||
|
||||
Bounds getBounds() const override;
|
||||
|
||||
const Point& getLocation() const override;
|
||||
|
|
|
@ -249,12 +249,12 @@ PathElementPtr PathPostScriptConverter::onArc()
|
|||
if (mPositionState == PositionState::RELATIVE)
|
||||
{
|
||||
const auto end_point = Point(mCurrentPoint.getX() + mPointBuffer[5], mCurrentPoint.getY() + mPointBuffer[6]);
|
||||
element = std::make_unique<Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||
element = std::make_unique<ntk::Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto end_point = Point(mPointBuffer[5], mPointBuffer[6]);
|
||||
element = std::make_unique<Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||
element = std::make_unique<ntk::Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||
}
|
||||
}
|
||||
return element;
|
||||
|
|
|
@ -20,6 +20,11 @@ Point QuadraticBezierCurve::getEndPoint() const
|
|||
return mEndPoint;
|
||||
}
|
||||
|
||||
Point QuadraticBezierCurve::getControlPoint() const
|
||||
{
|
||||
return mControlPoint;
|
||||
}
|
||||
|
||||
std::string QuadraticBezierCurve::toPostScriptString(std::size_t precision) const
|
||||
{
|
||||
if (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO)
|
||||
|
|
|
@ -10,6 +10,8 @@ public:
|
|||
|
||||
Point getFirstPoint() const override;
|
||||
|
||||
Point getControlPoint() const;
|
||||
|
||||
Point getEndPoint() const override;
|
||||
|
||||
Bounds getBounds() const override;
|
||||
|
|
|
@ -195,7 +195,6 @@ void DirectX2dPainter::paintPath(SceneModel* model)
|
|||
for (const auto& feature : path_item->getFeatures())
|
||||
{
|
||||
const auto loc = feature->getLocation();
|
||||
MLOG_INFO("Starting feature at: " << loc.getX() << " " << loc.getY());
|
||||
path_sink->BeginFigure(toD2dPoint(loc), D2D1_FIGURE_BEGIN_FILLED);
|
||||
|
||||
for (const auto& element : feature->getElements())
|
||||
|
@ -246,39 +245,48 @@ void DirectX2dPainter::paintPath(SceneModel* model)
|
|||
mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
|
||||
rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f);
|
||||
}
|
||||
|
||||
rt->SetTransform(D2D1::Matrix3x2F::Identity());
|
||||
}
|
||||
|
||||
void DirectX2dPainter::onArc(Curve* element, ID2D1GeometrySink* sink)
|
||||
{
|
||||
auto arc = dynamic_cast<ntk::Arc*>(element);
|
||||
|
||||
const auto end = toD2dPoint(arc->getEndPoint());
|
||||
D2D1_SIZE_F size{static_cast<float>(arc->getRx()), static_cast<float>(arc->getRx()) };
|
||||
const auto angle = static_cast<float>(arc->getRotation());
|
||||
D2D1_SWEEP_DIRECTION direction = arc->getSweepParam() ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE;
|
||||
D2D1_ARC_SIZE arc_size = arc->getUseLargeArc() ? D2D1_ARC_SIZE_LARGE : D2D1_ARC_SIZE_SMALL;
|
||||
|
||||
D2D1_ARC_SEGMENT segment{ end , size , angle , direction , arc_size };
|
||||
sink->AddArc(segment);
|
||||
}
|
||||
|
||||
void DirectX2dPainter::onQuadraticBezier(Curve* element, ID2D1GeometrySink* sink)
|
||||
{
|
||||
|
||||
auto bezier = dynamic_cast<QuadraticBezierCurve*>(element);
|
||||
D2D1_QUADRATIC_BEZIER_SEGMENT segment{ toD2dPoint(bezier->getControlPoint()) , toD2dPoint(bezier->getEndPoint()) };
|
||||
sink->AddQuadraticBezier(segment);
|
||||
}
|
||||
|
||||
void DirectX2dPainter::onCubicBezier(Curve* element, ID2D1GeometrySink* sink)
|
||||
{
|
||||
|
||||
auto bezier = dynamic_cast<CubicBezierCurve*>(element);
|
||||
D2D1_BEZIER_SEGMENT segment{ toD2dPoint(bezier->getStartControlPoint()), toD2dPoint(bezier->getEndControlPoint()), toD2dPoint(bezier->getEndPoint()) };
|
||||
sink->AddBezier(segment);
|
||||
}
|
||||
|
||||
void DirectX2dPainter::onLine(PathElement* element, ID2D1GeometrySink* sink)
|
||||
{
|
||||
for (const auto& point : dynamic_cast<Line*>(element)->getPoints().getPoints())
|
||||
{
|
||||
MLOG_INFO("Adding line entry at: " << point.getX() << " " << point.getY());
|
||||
sink->AddLine(toD2dPoint(point));
|
||||
}
|
||||
MLOG_INFO("Finished line");
|
||||
}
|
||||
|
||||
void DirectX2dPainter::onLineSegment(PathElement* element, ID2D1GeometrySink* sink)
|
||||
{
|
||||
const auto loc = element->getEndPoint();
|
||||
MLOG_INFO("Adding segment entry at: " << loc.getX() << " " << loc.getY());
|
||||
sink->AddLine(toD2dPoint(loc));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "Circle.h"
|
||||
#include "Rectangle.h"
|
||||
#include "Path.h"
|
||||
#include "Line.h"
|
||||
#include "LineSegment.h"
|
||||
|
||||
#include "SvgShapeElements.h"
|
||||
#include "SvgTextElement.h"
|
||||
|
@ -139,6 +141,14 @@ void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const
|
|||
{
|
||||
paintPath(document, model);
|
||||
}
|
||||
else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::LINE)
|
||||
{
|
||||
paintLine(document, model);
|
||||
}
|
||||
else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::LINE_SEGMENT)
|
||||
{
|
||||
paintLineSegment(document, model);
|
||||
}
|
||||
}
|
||||
|
||||
void SvgPainter::paintRect(SvgDocument* document, SceneModel* model) const
|
||||
|
@ -173,6 +183,25 @@ void SvgPainter::paintCircle(SvgDocument* document, SceneModel* model) const
|
|||
document->getRoot()->addChild(std::move(circle));
|
||||
}
|
||||
|
||||
void SvgPainter::paintLine(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_line = dynamic_cast<Line*>(model->getGeometry());
|
||||
auto svg_line = std::make_unique<SvgPolyline>();
|
||||
svg_line->setPoints(model_line->getFirstPoint(), model_line->getPoints().getPoints());
|
||||
|
||||
setStyle(model, svg_line.get());
|
||||
document->getRoot()->addChild(std::move(svg_line));
|
||||
}
|
||||
|
||||
void SvgPainter::paintLineSegment(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_line = dynamic_cast<LineSegment*>(model->getGeometry());
|
||||
auto svg_line = std::make_unique<SvgLine>(model_line->getFirstPoint(), model_line->getEndPoint());
|
||||
|
||||
setStyle(model, svg_line.get());
|
||||
document->getRoot()->addChild(std::move(svg_line));
|
||||
}
|
||||
|
||||
void SvgPainter::paintPath(SvgDocument* document, SceneModel* model) const
|
||||
{
|
||||
auto model_path = dynamic_cast<GeometryPath*>(model->getGeometry());
|
||||
|
|
|
@ -26,6 +26,10 @@ private:
|
|||
|
||||
void paintCircle(SvgDocument* document, SceneModel* model) const;
|
||||
|
||||
void paintLine(SvgDocument* document, SceneModel* model) const;
|
||||
|
||||
void paintLineSegment(SvgDocument* document, SceneModel* model) const;
|
||||
|
||||
void paintPath(SvgDocument* document, SceneModel* model) const;
|
||||
|
||||
void paintText(SvgDocument* document, SceneText* model) const;
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
SvgShapeElement::SvgShapeElement(const std::string& tagName)
|
||||
: SvgElement(tagName)
|
||||
SvgShapeElement::SvgShapeElement(const std::string& tagName, std::size_t precision)
|
||||
: SvgElement(tagName),
|
||||
mPrecision(precision)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class SvgShapeElement : public SvgElement
|
||||
{
|
||||
public:
|
||||
SvgShapeElement(const std::string& tagName);
|
||||
SvgShapeElement(const std::string& tagName, std::size_t precision = 0);
|
||||
|
||||
Transform getTransform() const;
|
||||
|
||||
|
@ -25,6 +25,9 @@ public:
|
|||
|
||||
void setNoStroke();
|
||||
|
||||
protected:
|
||||
std::size_t mPrecision{ 0 };
|
||||
|
||||
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,5 +1,6 @@
|
|||
#include "SvgShapeElements.h"
|
||||
|
||||
#include "PointParser.h"
|
||||
#include <sstream>
|
||||
|
||||
SvgCircle::SvgCircle(Type type)
|
||||
|
@ -174,6 +175,45 @@ void SvgPolyline::setPoints(const std::vector<Point>& locs)
|
|||
addAttribute(std::move(points));
|
||||
}
|
||||
|
||||
void SvgPolyline::setPoints(const Point& startPoint, const std::vector<Point>& locs)
|
||||
{
|
||||
auto points = std::make_unique<XmlAttribute>("points");
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << startPoint.getX() << "," << startPoint.getY() << " ";
|
||||
|
||||
for (const auto& loc : locs)
|
||||
{
|
||||
sstr << loc.getX() << "," << loc.getY() << " ";
|
||||
}
|
||||
points->setValue(sstr.str());
|
||||
addAttribute(std::move(points));
|
||||
}
|
||||
|
||||
SvgLine::SvgLine(const Point& startPoint, const Point& endPoint, std::size_t precision)
|
||||
: SvgShapeElement("line", precision)
|
||||
{
|
||||
auto fill = std::make_unique<XmlAttribute>("fill");
|
||||
fill->setValue("none");
|
||||
addAttribute(std::move(fill));
|
||||
|
||||
auto x1 = std::make_unique<XmlAttribute>("x1");
|
||||
x1->setValue(PointParser::toString(startPoint.getX(), mPrecision));
|
||||
addAttribute(std::move(x1));
|
||||
|
||||
auto y1 = std::make_unique<XmlAttribute>("y1");
|
||||
y1->setValue(PointParser::toString(startPoint.getY(), mPrecision));
|
||||
addAttribute(std::move(y1));
|
||||
|
||||
auto x2 = std::make_unique<XmlAttribute>("x2");
|
||||
x2->setValue(PointParser::toString(endPoint.getX(), mPrecision));
|
||||
addAttribute(std::move(x2));
|
||||
|
||||
auto y2 = std::make_unique<XmlAttribute>("y2");
|
||||
y2->setValue(PointParser::toString(endPoint.getY(), mPrecision));
|
||||
addAttribute(std::move(y2));
|
||||
}
|
||||
|
||||
|
||||
SvgPath::SvgPath()
|
||||
: SvgShapeElement("path")
|
||||
|
|
|
@ -60,9 +60,17 @@ class SvgPolyline : public SvgShapeElement
|
|||
public:
|
||||
SvgPolyline();
|
||||
|
||||
void setPoints(const Point& startPoint, const std::vector<Point>& loc);
|
||||
|
||||
void setPoints(const std::vector<Point>& loc);
|
||||
};
|
||||
|
||||
class SvgLine : public SvgShapeElement
|
||||
{
|
||||
public:
|
||||
SvgLine(const Point& startPoint, const Point& endPoint, std::size_t precision = 0);
|
||||
};
|
||||
|
||||
class SvgPath : public SvgShapeElement
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
#include "LineNode.h"
|
||||
#include "PathNode.h"
|
||||
|
||||
void addRect(const Point& loc, std::vector<std::unique_ptr<AbstractVisualNode> >& nodes, double radius = 0.0)
|
||||
void addRect(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, double radius = 0.0)
|
||||
{
|
||||
auto node = std::make_unique<RectangleNode>(loc, 150.0, 100.0);
|
||||
node->setRadius(radius);
|
||||
nodes.push_back(std::move(node));
|
||||
}
|
||||
|
||||
void addCircle(const Point& loc, std::vector<std::unique_ptr<AbstractVisualNode> >& nodes, double minorRadius = 0.0)
|
||||
void addCircle(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, double minorRadius = 0.0)
|
||||
{
|
||||
const auto radius = 50.0;
|
||||
auto centre_loc = loc;
|
||||
|
@ -30,26 +30,25 @@ void addCircle(const Point& loc, std::vector<std::unique_ptr<AbstractVisualNode>
|
|||
nodes.push_back(std::move(node));
|
||||
}
|
||||
|
||||
void addLine(const Point& loc, std::vector<std::unique_ptr<AbstractVisualNode> >& nodes)
|
||||
void addLine(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes)
|
||||
{
|
||||
std::vector<Point> points = { Point(150.0, 100.0) };
|
||||
auto node = std::make_unique<LineNode>(loc, points);
|
||||
nodes.push_back(std::move(node));
|
||||
}
|
||||
|
||||
void addPath(const Point& loc, const std::string& path, std::vector<std::unique_ptr<AbstractVisualNode> >& nodes)
|
||||
void addPath(const Point& loc, const std::string& path, std::vector<std::unique_ptr<MaterialNode> >& nodes)
|
||||
{
|
||||
auto node = std::make_unique<PathNode>(loc, path);
|
||||
nodes.push_back(std::move(node));
|
||||
}
|
||||
|
||||
TEST_CASE(TestD2dOffScreenRendering, "graphics")
|
||||
void addShapes(const Point& start_loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, bool use_fill = false)
|
||||
{
|
||||
TestRenderer renderer(800, 800);
|
||||
auto loc = start_loc;
|
||||
|
||||
std::vector<std::unique_ptr<AbstractVisualNode> > nodes;
|
||||
auto fill_color = Color(200, 0, 200);
|
||||
|
||||
auto loc = Point(10, 10);
|
||||
addRect(loc, nodes);
|
||||
|
||||
loc.move(250, 0);
|
||||
|
@ -67,10 +66,60 @@ TEST_CASE(TestD2dOffScreenRendering, "graphics")
|
|||
loc.move(100, 0);
|
||||
addPath(loc, "M0 0 h150 v100 h-150Z", nodes);
|
||||
|
||||
loc = Point(10, 300);
|
||||
addPath(loc, "M0 0 h150 q50 50 0 100 h-150Z", nodes);
|
||||
|
||||
loc.move(250, 0);
|
||||
addPath(loc, "M0 0 h150 c25 25 25 75 0 100 h-150Z", nodes);
|
||||
|
||||
loc.move(250, 0);
|
||||
addPath(loc, "M0 0 h150 a50 50 0 0 1 0 100 h-150Z", nodes);
|
||||
|
||||
if (use_fill)
|
||||
{
|
||||
for (auto& node : nodes)
|
||||
{
|
||||
node->setFillColor(fill_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(TestD2dOffScreenRendering_Outlines, "graphics")
|
||||
{
|
||||
TestRenderer renderer(800, 800);
|
||||
|
||||
std::vector<std::unique_ptr<MaterialNode> > nodes;
|
||||
|
||||
auto loc = Point(10, 10);
|
||||
|
||||
addShapes(loc, nodes, false);
|
||||
|
||||
auto scene = renderer.getScene();
|
||||
for (const auto& node : nodes)
|
||||
{
|
||||
scene->addNode(node.get());
|
||||
}
|
||||
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "out.png");
|
||||
|
||||
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "outlines.svg");
|
||||
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "outlines.png");
|
||||
};
|
||||
|
||||
TEST_CASE(TestD2dOffScreenRendering_Fill, "graphics")
|
||||
{
|
||||
TestRenderer renderer(800, 800);
|
||||
|
||||
std::vector<std::unique_ptr<MaterialNode> > nodes;
|
||||
|
||||
auto loc = Point(10, 10);
|
||||
|
||||
addShapes(loc, nodes, true);
|
||||
|
||||
auto scene = renderer.getScene();
|
||||
for (const auto& node : nodes)
|
||||
{
|
||||
scene->addNode(node.get());
|
||||
}
|
||||
|
||||
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "fill.svg");
|
||||
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "fill.png");
|
||||
};
|
Loading…
Reference in a new issue