diff --git a/src/base/geometry/AbstractGeometricItem.h b/src/base/geometry/AbstractGeometricItem.h index 2004c25..49f693e 100644 --- a/src/base/geometry/AbstractGeometricItem.h +++ b/src/base/geometry/AbstractGeometricItem.h @@ -20,6 +20,7 @@ public: POINT, PATH, CIRCLE, + POLYGON, UNKNOWN }; diff --git a/src/base/geometry/CMakeLists.txt b/src/base/geometry/CMakeLists.txt index b92f64a..6b0ec53 100644 --- a/src/base/geometry/CMakeLists.txt +++ b/src/base/geometry/CMakeLists.txt @@ -24,7 +24,7 @@ list(APPEND HEADERS points/PointCollection.h points/DiscretePoint.h primitives/Circle.h - primitives/Quad.h + primitives/Polygon.h primitives/Rectangle.h primitives/Triangle.h ) @@ -49,7 +49,7 @@ list(APPEND SOURCES points/PointCollection.cpp points/DiscretePoint.cpp primitives/Circle.cpp - primitives/Quad.cpp + primitives/Polygon.cpp primitives/Rectangle.cpp primitives/Triangle.cpp ) diff --git a/src/base/geometry/Transform.h b/src/base/geometry/Transform.h index 280297d..8a7143a 100644 --- a/src/base/geometry/Transform.h +++ b/src/base/geometry/Transform.h @@ -1,6 +1,36 @@ #pragma once #include "Point.h" +#include "Vector.h" + +class Rotation +{ +public: + enum class Axis + { + X, + Y, + Z, + USER + }; + + + Rotation(double angle = 0.0, Axis axis = Axis::Z, const Point& loc = {}, const Vector& customAxis = {}) + { + + } + +private: + double mAngle{ 0 }; + Axis mAxis{ Axis::Z }; + Point mPoint; + Vector mCustomAxis; +}; + +struct Scale +{ + +}; class Transform { diff --git a/src/base/geometry/primitives/Polygon.cpp b/src/base/geometry/primitives/Polygon.cpp new file mode 100644 index 0000000..839cf22 --- /dev/null +++ b/src/base/geometry/primitives/Polygon.cpp @@ -0,0 +1,38 @@ +#include "Polygon.h" + +namespace ntk { + Polygon::Polygon(const std::vector& points) + : AbstractGeometricItem() + { + if (points.size() > 0) + { + mStartPoint = points[0]; + } + mPoints = PointCollection(points); + } + + const PointCollection& Polygon::getPoints() const + { + return mPoints; + } + + Bounds Polygon::getBounds() const + { + return mPoints.getBounds(); + } + + const Point& Polygon::getLocation() const + { + return mStartPoint; + } + + void Polygon::sample(SparseGrid*) const + { + + } + + Polygon::Type Polygon::getType() const + { + return Polygon::Type::POLYGON; + } +} \ No newline at end of file diff --git a/src/base/geometry/primitives/Polygon.h b/src/base/geometry/primitives/Polygon.h new file mode 100644 index 0000000..b270dbd --- /dev/null +++ b/src/base/geometry/primitives/Polygon.h @@ -0,0 +1,27 @@ +#pragma once + +#include "AbstractGeometricItem.h" + +#include "PointCollection.h" + +namespace ntk{ +class Polygon : public AbstractGeometricItem +{ +public: + Polygon(const std::vector& points); + + const PointCollection& getPoints() const; + + Bounds getBounds() const override; + + const Point& getLocation() const override; + + void sample(SparseGrid*) const override; + + Type getType() const override; + +private: + Point mStartPoint; + PointCollection mPoints; +}; +} \ No newline at end of file diff --git a/src/base/geometry/primitives/Quad.h b/src/base/geometry/primitives/Quad.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/publishing/CMakeLists.txt b/src/publishing/CMakeLists.txt index 7e941a5..774efc8 100644 --- a/src/publishing/CMakeLists.txt +++ b/src/publishing/CMakeLists.txt @@ -11,7 +11,10 @@ list(APPEND publishing_HEADERS pdf/PdfWriter.h plotting/GraphPlotter.h plotting/PlotNode.h + plotting/Plot.h plotting/EquationNode.h + plotting/PlotSeriesNode.h + plotting/PlotCaptionNode.h latex/LatexDocument.h latex/LatexMathExpression.h latex/LatexSymbols.h @@ -34,7 +37,10 @@ list(APPEND publishing_LIB_INCLUDES latex/LatexSymbols.cpp plotting/GraphPlotter.h plotting/PlotNode.cpp + plotting/Plot.cpp plotting/EquationNode.cpp + plotting/PlotSeriesNode.cpp + plotting/PlotCaptionNode.cpp DocumentConverter.cpp ) diff --git a/src/publishing/plotting/EquationNode.cpp b/src/publishing/plotting/EquationNode.cpp index e69de29..7060bbe 100644 --- a/src/publishing/plotting/EquationNode.cpp +++ b/src/publishing/plotting/EquationNode.cpp @@ -0,0 +1,7 @@ +#include "EquationNode.h" + +EquationNode::EquationNode(const Transform& t) + : AbstractVisualNode(t) +{ + +} \ No newline at end of file diff --git a/src/publishing/plotting/EquationNode.h b/src/publishing/plotting/EquationNode.h index e69de29..745526a 100644 --- a/src/publishing/plotting/EquationNode.h +++ b/src/publishing/plotting/EquationNode.h @@ -0,0 +1,9 @@ +#pragma once + +#include "AbstractVisualNode.h" + +class EquationNode : public AbstractVisualNode +{ +public: + EquationNode(const Transform& t = {}); +}; \ No newline at end of file diff --git a/src/publishing/plotting/GraphPlotter.h b/src/publishing/plotting/GraphPlotter.h index e69de29..3f59c93 100644 --- a/src/publishing/plotting/GraphPlotter.h +++ b/src/publishing/plotting/GraphPlotter.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/src/base/geometry/primitives/Quad.cpp b/src/publishing/plotting/Plot.cpp similarity index 100% rename from src/base/geometry/primitives/Quad.cpp rename to src/publishing/plotting/Plot.cpp diff --git a/src/publishing/plotting/Plot.h b/src/publishing/plotting/Plot.h new file mode 100644 index 0000000..5cb1553 --- /dev/null +++ b/src/publishing/plotting/Plot.h @@ -0,0 +1,91 @@ +#pragma once + +#include "Point.h" + +#include +#include + +class TextSpan +{ +public: + enum class Type + { + PLAIN, + EQUATION + }; + + TextSpan(const std::string& content, Type type = Type::PLAIN) + : mType(type), + mContent(content) + { + + } + +private: + Type mType{ Type::PLAIN }; + std::string mContent; +}; + +class PlotCaption +{ +public: + PlotCaption() = default; + + void setContent(const std::string& plainContent) + { + mContent = { plainContent }; + } + + void setContent(const std::vector& content) + { + mContent = content; + } + +private: + std::vector mContent; +}; + +class PlotSeries +{ +public: + PlotSeries(const std::string& label = {}) + : mLabel(label) + { + + } + + void setData(const std::vector& data) + { + mData = data; + } + +private: + std::string mLabel; + std::vector mData; +}; + +class Plot +{ +public: + Plot() = default; + + void setXAxisCaption(const std::string& caption) + { + mXAxisCaption.setContent(caption); + } + + void setYAxisCaption(const std::string& caption) + { + mYAxisCaption.setContent(caption); + } + + void addSeries(const PlotSeries& series) + { + mSeries.push_back(series); + } + +private: + PlotCaption mXAxisCaption; + PlotCaption mYAxisCaption; + std::vector mSeries; +}; \ No newline at end of file diff --git a/src/publishing/plotting/PlotCaptionNode.cpp b/src/publishing/plotting/PlotCaptionNode.cpp new file mode 100644 index 0000000..c48476b --- /dev/null +++ b/src/publishing/plotting/PlotCaptionNode.cpp @@ -0,0 +1,16 @@ +#include "PlotCaptionNode.h" + +#include "TextNode.h" +#include "EquationNode.h" + +PlotCaptionNode::PlotCaptionNode(const Transform& transform) + : AbstractVisualNode(transform) +{ + +} + +void PlotCaptionNode::setContent(const PlotCaption& content) +{ + mContent = content; + mContentDirty = true; +} \ No newline at end of file diff --git a/src/publishing/plotting/PlotCaptionNode.h b/src/publishing/plotting/PlotCaptionNode.h new file mode 100644 index 0000000..3b2bb99 --- /dev/null +++ b/src/publishing/plotting/PlotCaptionNode.h @@ -0,0 +1,23 @@ +#pragma once + +#include "AbstractVisualNode.h" + +#include "Plot.h" + +class TextNode; +class EquationNode; + +class PlotCaptionNode : public AbstractVisualNode +{ +public: + PlotCaptionNode(const Transform& transform = {}); + + void setContent(const PlotCaption& content); + +private: + PlotCaption mContent; + bool mContentDirty{ true }; + + std::vector > mTextContent; + std::vector > mEquationContent; +}; \ No newline at end of file diff --git a/src/publishing/plotting/PlotNode.cpp b/src/publishing/plotting/PlotNode.cpp index e69de29..249f586 100644 --- a/src/publishing/plotting/PlotNode.cpp +++ b/src/publishing/plotting/PlotNode.cpp @@ -0,0 +1,60 @@ +#include "PlotNode.h" + +#include "PlotCaptionNode.h" +#include "PlotSeriesNode.h" + +#include "LineNode.h" + + +PlotNode::PlotNode(const Transform& transform) + : AbstractVisualNode(transform) +{ + +} + +void PlotNode::setContent(Plot* content) +{ + mContent = content; + mContentDirty = true; +} + +void PlotNode::update(SceneInfo* sceneInfo) +{ + if (mContentDirty) + { + createOrUpdateGeometry(sceneInfo); + mContentDirty = false; + } +} + +void PlotNode::setAxisEndStyle(LineEndNode::Style style) +{ + if (mAxisEndStyle != style) + { + mAxisEndStyle = style; + mContentDirty = true; + } +} + +void PlotNode::createOrUpdateGeometry(SceneInfo* sceneInfo) +{ + const double height = 100.0; + const double width = 100.0; + + Point x_axis_start{ 0.0, height }; + std::vector x_axis_points = { Point(width, 0.0) }; + mXAxis = std::make_unique(Transform(x_axis_start), x_axis_points); + mXAxis->setEndEndStyle(mAxisEndStyle); + + addChild(mXAxis.get()); + + Point y_axis_start{ 0.0, height }; + std::vector y_axis_points = { Point(0.0, -height) }; + mYAxis = std::make_unique(Transform(y_axis_start), y_axis_points); + mYAxis->setEndEndStyle(mAxisEndStyle); + + addChild(mYAxis.get()); + +} + + diff --git a/src/publishing/plotting/PlotNode.h b/src/publishing/plotting/PlotNode.h index e69de29..910b4e2 100644 --- a/src/publishing/plotting/PlotNode.h +++ b/src/publishing/plotting/PlotNode.h @@ -0,0 +1,40 @@ +#pragma once + +#include "LineEndNode.h" + +#include + +class Plot; +class LineNode; +class PlotCaptionNode; +class PlotSeriesNode; + + +class PlotNode : public AbstractVisualNode +{ +public: + PlotNode(const Transform& transform = {}); + + void setContent(Plot* content); + + void setAxisEndStyle(LineEndNode::Style style); + + void update(SceneInfo* sceneInfo) override; + +protected: + void createOrUpdateGeometry(SceneInfo* sceneInfo); + + Plot* mContent{ nullptr }; + bool mContentDirty = true; + + std::unique_ptr mXAxis; + std::unique_ptr mYAxis; + LineEndNode::Style mAxisEndStyle{ LineEndNode::Style::NONE }; + + std::unique_ptr mXAxisCaption; + std::unique_ptr mYAxisCaption; + + std::vector > mSeries; + +}; + diff --git a/src/publishing/plotting/PlotSeriesNode.cpp b/src/publishing/plotting/PlotSeriesNode.cpp new file mode 100644 index 0000000..4b3ad05 --- /dev/null +++ b/src/publishing/plotting/PlotSeriesNode.cpp @@ -0,0 +1,13 @@ +#include "PlotSeriesNode.h" + +PlotSeriesNode::PlotSeriesNode(const Transform& transform) + : AbstractVisualNode(transform) +{ + +} + +void PlotSeriesNode::setContent(const PlotSeries& content) +{ + mContent = content; + mContentDirty = true; +} \ No newline at end of file diff --git a/src/publishing/plotting/PlotSeriesNode.h b/src/publishing/plotting/PlotSeriesNode.h new file mode 100644 index 0000000..a7541ac --- /dev/null +++ b/src/publishing/plotting/PlotSeriesNode.h @@ -0,0 +1,17 @@ +#pragma once + +#include "AbstractVisualNode.h" + +#include "Plot.h" + +class PlotSeriesNode : public AbstractVisualNode +{ +public: + PlotSeriesNode(const Transform& transform = {}); + + void setContent(const PlotSeries& content); + +private: + PlotSeries mContent; + bool mContentDirty{ true }; +}; \ No newline at end of file diff --git a/src/rendering/graphics/directx/DirectX2dPainter.cpp b/src/rendering/graphics/directx/DirectX2dPainter.cpp index aff62bd..981cd27 100644 --- a/src/rendering/graphics/directx/DirectX2dPainter.cpp +++ b/src/rendering/graphics/directx/DirectX2dPainter.cpp @@ -5,11 +5,10 @@ #include "AbstractGeometricItem.h" #include "Rectangle.h" #include "Circle.h" -#include "Path.h" - #include "LineSegment.h" #include "Line.h" #include "Path.h" +#include "Polygon.h" #include "Curve.h" #include "Arc.h" @@ -61,6 +60,10 @@ void DirectX2dPainter::paint(SceneModel* model) { paintLine(model); } + else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::POLYGON) + { + paintPolygon(model); + } } void DirectX2dPainter::paintRect(SceneModel* model) @@ -158,6 +161,54 @@ void DirectX2dPainter::paintLine(SceneModel* model) onLine(line, path_sink.Get()); + path_sink->EndFigure(D2D1_FIGURE_END_OPEN); + path_sink->Close(); + + auto rt = mD2dInterface->getRenderTarget(); + + const auto loc = model->getTransform().getLocation(); + D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast(loc.getX()), static_cast(loc.getY())); + rt->SetTransform(translation); + + const auto material = model->getSolidMaterial(); + if (material.hasFillColor()) + { + mSolidBrush->SetColor(toD2dColor(material.getFillColor())); + rt->FillGeometry(path_geom.Get(), mSolidBrush.Get()); + } + if (material.hasStrokeColor()) + { + mSolidBrush->SetColor(toD2dColor(material.getStrokeColor())); + rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f); + } + + rt->SetTransform(D2D1::Matrix3x2F::Identity()); +} + +void DirectX2dPainter::paintPolygon(SceneModel* model) +{ + Microsoft::WRL::ComPtr path_geom; + mD2dInterface->getFactory()->CreatePathGeometry(&path_geom); + + Microsoft::WRL::ComPtr path_sink; + + path_geom->Open(&path_sink); + + auto polygon = dynamic_cast(model->getGeometry()); + + path_sink->BeginFigure(toD2dPoint(polygon->getLocation()), D2D1_FIGURE_BEGIN_FILLED); + + bool first{ true }; + for (const auto& point : polygon->getPoints().getPoints()) + { + if (first) + { + first = false; + continue; + } + path_sink->AddLine(toD2dPoint(point)); + } + path_sink->EndFigure(D2D1_FIGURE_END_CLOSED); path_sink->Close(); diff --git a/src/rendering/graphics/directx/DirectX2dPainter.h b/src/rendering/graphics/directx/DirectX2dPainter.h index f7ebcf1..f4306ff 100644 --- a/src/rendering/graphics/directx/DirectX2dPainter.h +++ b/src/rendering/graphics/directx/DirectX2dPainter.h @@ -52,6 +52,8 @@ private: void paintLine(SceneModel* model); + void paintPolygon(SceneModel* model); + static D2D1::ColorF toD2dColor(const Color& color); static D2D_POINT_2F toD2dPoint(const Point& point); diff --git a/src/rendering/visual_elements/CMakeLists.txt b/src/rendering/visual_elements/CMakeLists.txt index 0561e49..3c595a1 100644 --- a/src/rendering/visual_elements/CMakeLists.txt +++ b/src/rendering/visual_elements/CMakeLists.txt @@ -7,6 +7,8 @@ list(APPEND visual_elements_LIB_INCLUDES basic_shapes/CircleNode.cpp basic_shapes/LineNode.h basic_shapes/LineNode.cpp + basic_shapes/PolygonNode.h + basic_shapes/PolygonNode.cpp scene/Scene.h scene/Scene.cpp scene/SceneInfo.h @@ -40,6 +42,8 @@ list(APPEND visual_elements_LIB_INCLUDES nodes/PathNode.cpp nodes/ImageNode.h nodes/ImageNode.cpp + nodes/LineEndNode.h + nodes/LineEndNode.cpp nodes/MeshNode.h nodes/MeshNode.cpp nodes/TextNode.h diff --git a/src/rendering/visual_elements/basic_shapes/LineNode.cpp b/src/rendering/visual_elements/basic_shapes/LineNode.cpp index 1761bfd..4df5ac8 100644 --- a/src/rendering/visual_elements/basic_shapes/LineNode.cpp +++ b/src/rendering/visual_elements/basic_shapes/LineNode.cpp @@ -20,6 +20,48 @@ void LineNode::createOrUpdateGeometry(SceneInfo* sceneInfo) { auto line = std::make_unique(Point{ 0, 0 }, mPoints); mBackgroundItem = std::make_unique(std::move(line)); + + if (mStartEndStyle != LineEndNode::Style::NONE) + { + if (!mStartNode) + { + mStartNode = std::make_unique(Point{ 0, 0 }); + addChild(mStartNode.get()); + } + mStartNode->setStyle(mStartEndStyle); + mStartNode->setSize(mStartEndSize); + } + + if (mEndEndStyle != LineEndNode::Style::NONE) + { + if (!mEndNode) + { + auto end_loc = mPoints[mPoints.size() - 1]; + + mEndNode = std::make_unique(end_loc); + addChild(mEndNode.get()); + } + mEndNode->setStyle(mEndEndStyle); + mEndNode->setSize(mEndEndSize); + } } mBackgroundItem->setName(mName + "_Model"); +} + +void LineNode::setStartEndStyle(LineEndNode::Style style) +{ + if (mStartEndStyle != style) + { + mStartEndStyle = style; + mGeometryIsDirty = true; + } +} + +void LineNode::setEndEndStyle(LineEndNode::Style style) +{ + if (mStartEndStyle != style) + { + mEndEndStyle = style; + mGeometryIsDirty = true; + } } \ No newline at end of file diff --git a/src/rendering/visual_elements/basic_shapes/LineNode.h b/src/rendering/visual_elements/basic_shapes/LineNode.h index 73e69b9..90d9a9f 100644 --- a/src/rendering/visual_elements/basic_shapes/LineNode.h +++ b/src/rendering/visual_elements/basic_shapes/LineNode.h @@ -4,6 +4,7 @@ #include "SceneInfo.h" #include "Line.h" +#include "LineEndNode.h" #include @@ -14,8 +15,21 @@ public: Type getType() override; + void setStartEndStyle(LineEndNode::Style style); + + void setEndEndStyle(LineEndNode::Style style); + private: void createOrUpdateGeometry(SceneInfo* sceneInfo) override; + double mStartEndSize{ 5.0 }; + double mEndEndSize{ 5.0 }; + + LineEndNode::Style mStartEndStyle{ LineEndNode::Style::NONE }; + LineEndNode::Style mEndEndStyle{ LineEndNode::Style::NONE }; + std::vector mPoints; + + std::unique_ptr mStartNode; + std::unique_ptr mEndNode; }; diff --git a/src/rendering/visual_elements/basic_shapes/PolygonNode.cpp b/src/rendering/visual_elements/basic_shapes/PolygonNode.cpp new file mode 100644 index 0000000..8c3f5f7 --- /dev/null +++ b/src/rendering/visual_elements/basic_shapes/PolygonNode.cpp @@ -0,0 +1,53 @@ +#include "PolygonNode.h" + +#include "Polygon.h" +#include "SceneInfo.h" +#include "SceneModel.h" + +PolygonNode::PolygonNode(const Transform& t) + : GeometryNode(t) +{ + +} + +PolygonNode::~PolygonNode() +{ + +} + +PolygonNode::Type PolygonNode::getType() +{ + return Type::Polygon; +} + +void PolygonNode::setPoints(const std::vector& points) +{ + mPoints = points; + mGeometryIsDirty = true; +} + +void PolygonNode::createOrUpdateGeometry(SceneInfo* sceneInfo) +{ + if (!mBackgroundItem) + { + if (sceneInfo->mSupportsGeometryPrimitives) + { + auto polygon = std::make_unique(mPoints); + mBackgroundItem = std::make_unique(std::move(polygon)); + } + else + { + //auto mesh = MeshPrimitives::buildRectangleAsTriMesh(); + //mBackgroundItem = std::make_unique(std::move(mesh)); + } + mBackgroundItem->setName(mName + "_Model"); + } + else + { + if (sceneInfo->mSupportsGeometryPrimitives) + { + auto polygon = std::make_unique(mPoints); + mBackgroundItem->updateGeometry(std::move(polygon)); + } + } +} \ No newline at end of file diff --git a/src/rendering/visual_elements/basic_shapes/PolygonNode.h b/src/rendering/visual_elements/basic_shapes/PolygonNode.h new file mode 100644 index 0000000..282c6c3 --- /dev/null +++ b/src/rendering/visual_elements/basic_shapes/PolygonNode.h @@ -0,0 +1,19 @@ +#pragma once + +#include "GeometryNode.h" + +class PolygonNode : public GeometryNode +{ +public: + PolygonNode(const Transform& t = {}); + + virtual ~PolygonNode(); + + Type getType() override; + + void setPoints(const std::vector& points); + +private: + void createOrUpdateGeometry(SceneInfo* sceneInfo) override; + std::vector mPoints; +}; \ No newline at end of file diff --git a/src/rendering/visual_elements/nodes/GeometryNode.h b/src/rendering/visual_elements/nodes/GeometryNode.h index 1219e33..4dabe20 100644 --- a/src/rendering/visual_elements/nodes/GeometryNode.h +++ b/src/rendering/visual_elements/nodes/GeometryNode.h @@ -14,7 +14,8 @@ public: Rectangle, Circle, Arc, - Line + Line, + Polygon }; public: diff --git a/src/rendering/visual_elements/nodes/LineEndNode.cpp b/src/rendering/visual_elements/nodes/LineEndNode.cpp new file mode 100644 index 0000000..6a518e4 --- /dev/null +++ b/src/rendering/visual_elements/nodes/LineEndNode.cpp @@ -0,0 +1,63 @@ +#include "LineEndNode.h" + +#include "GeometryNode.h" +#include "PolygonNode.h" + +LineEndNode::LineEndNode(const Transform& t) + : MaterialNode(t) +{ + +} + +void LineEndNode::setStyle(LineEndNode::Style style) +{ + if (mStyle != style) + { + mStyle = style; + mContentDirty = true; + } +} + +void LineEndNode::setSize(double size) +{ + if (mSize != size) + { + mSize = size; + mContentDirty = true; + } +} + +void LineEndNode::createOrUpdateGeometry(SceneInfo* sceneInfo) +{ + if (!mContentNode) + { + if (mStyle == Style::CLOSED_ARROW) + { + auto polygon = std::make_unique(); + auto p0 = Point(0.0, -mSize / 2.0); + auto p1 = Point(mSize, 0.0); + auto p2 = Point(0.0, mSize / 2.0); + polygon->setPoints({ p0, p1, p2 }); + polygon->setFillColor({ 0, 0, 0 }); + + mContentNode = std::move(polygon); + addChild(mContentNode.get()); + } + } + +} + +void LineEndNode::update(SceneInfo* sceneInfo) +{ + if (mContentDirty) + { + createOrUpdateGeometry(sceneInfo); + mContentDirty = false; + } + + if (mMaterialIsDirty) + { + //updateMaterial(); + mMaterialIsDirty = false; + } +} \ No newline at end of file diff --git a/src/rendering/visual_elements/nodes/LineEndNode.h b/src/rendering/visual_elements/nodes/LineEndNode.h new file mode 100644 index 0000000..9973f69 --- /dev/null +++ b/src/rendering/visual_elements/nodes/LineEndNode.h @@ -0,0 +1,38 @@ +#pragma once + +#include "MaterialNode.h" +#include "Vector.h" + +class GeometryNode; + +class LineEndNode : public MaterialNode +{ +public: + enum class Style + { + NONE, + CIRCLE, + CLOSED_ARROW, + OPEN_ARROW, + CURVED_ARROW + }; + + LineEndNode(const Transform& t = {}); + + void setStyle(LineEndNode::Style style); + + void setSize(double size); + + void update(SceneInfo* sceneInfo) override; + +private: + void createOrUpdateGeometry(SceneInfo* sceneInfo); + + std::unique_ptr mContentNode; + + Vector mDirection; + + bool mContentDirty{ true }; + double mSize{ 5.0 }; + Style mStyle{ Style::NONE }; +}; \ No newline at end of file diff --git a/src/rendering/visual_elements/svg/SvgPainter.cpp b/src/rendering/visual_elements/svg/SvgPainter.cpp index 54a552f..f7597e8 100644 --- a/src/rendering/visual_elements/svg/SvgPainter.cpp +++ b/src/rendering/visual_elements/svg/SvgPainter.cpp @@ -17,6 +17,7 @@ #include "Path.h" #include "Line.h" #include "LineSegment.h" +#include "Polygon.h" #include "SvgShapeElements.h" #include "SvgTextElement.h" @@ -149,6 +150,21 @@ void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const { paintLineSegment(document, model); } + else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::POLYGON) + { + paintPolygon(document, model); + } +} + +void SvgPainter::paintPolygon(SvgDocument* document, SceneModel* model) const +{ + auto model_polygon = dynamic_cast(model->getGeometry()); + + auto svg_polygon = std::make_unique(); + svg_polygon->setPoints(model_polygon->getPoints().getPoints()); + + setStyle(model, svg_polygon.get()); + document->getRoot()->addChild(std::move(svg_polygon)); } void SvgPainter::paintRect(SvgDocument* document, SceneModel* model) const diff --git a/src/rendering/visual_elements/svg/SvgPainter.h b/src/rendering/visual_elements/svg/SvgPainter.h index 7daf021..970df18 100644 --- a/src/rendering/visual_elements/svg/SvgPainter.h +++ b/src/rendering/visual_elements/svg/SvgPainter.h @@ -32,6 +32,8 @@ private: void paintPath(SvgDocument* document, SceneModel* model) const; + void paintPolygon(SvgDocument* document, SceneModel* model) const; + void paintText(SvgDocument* document, SceneText* model) const; void setStyle(SceneModel* model, SvgShapeElement* element) const; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bbd19e8..213374d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(test_utils) add_subdirectory(geometry) add_subdirectory(graphics) +add_subdirectory(publishing) add_subdirectory(ui_controls) file(COPY data/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_data) @@ -16,8 +17,7 @@ set(TEST_MODULES image ipc network - mesh - publishing + mesh video web windows) diff --git a/test/graphics/TestD2dOffScreenRendering.cpp b/test/graphics/TestD2dOffScreenRendering.cpp index 6731778..f6309cc 100644 --- a/test/graphics/TestD2dOffScreenRendering.cpp +++ b/test/graphics/TestD2dOffScreenRendering.cpp @@ -6,6 +6,7 @@ #include "CircleNode.h" #include "LineNode.h" #include "PathNode.h" +#include "PolygonNode.h" void addRect(const Point& loc, std::vector >& nodes, double radius = 0.0) { @@ -43,6 +44,17 @@ void addPath(const Point& loc, const std::string& path, std::vector >& nodes) +{ + auto p0 = Point{ 0.0, 0.0 }; + auto p1 = Point{ 150.0, 0.0 }; + auto p2 = Point{ 75.0, 75.0 }; + + auto node = std::make_unique(loc); + node->setPoints({ p0, p1, p2 }); + nodes.push_back(std::move(node)); +} + void addShapes(const Point& start_loc, std::vector >& nodes, bool use_fill = false) { auto loc = start_loc; @@ -57,6 +69,9 @@ void addShapes(const Point& start_loc, std::vector loc.move(100, 0); addLine(loc, nodes); + loc.move(200, 0); + addPolygon(loc, nodes); + loc = Point(10, 150); addRect(loc, nodes, 10.0); diff --git a/test/publishing/CMakeLists.txt b/test/publishing/CMakeLists.txt index d8d3583..2481139 100644 --- a/test/publishing/CMakeLists.txt +++ b/test/publishing/CMakeLists.txt @@ -1,13 +1,16 @@ -set(PUBLISHING_UNIT_TEST_FILES - publishing/TestPdfWriter.cpp - publishing/TestDocumentConverter.cpp - publishing/TestSvgConverter.cpp - publishing/TestSvgToNodeConverter.cpp - publishing/TestLatexConverter.cpp - PARENT_SCOPE - ) - -set(PUBLISHING_UNIT_TEST_DEPENDENCIES - publishing - PARENT_SCOPE - ) \ No newline at end of file +set(MODULE_NAME publishing) + +list(APPEND UNIT_TEST_FILES + TestPdfWriter.cpp + TestDocumentConverter.cpp + TestSvgConverter.cpp + TestSvgToNodeConverter.cpp + TestLatexConverter.cpp + TestPlotting.cpp +) + +set(UNIT_TEST_TARGET_NAME ${MODULE_NAME}_unit_tests) + +add_executable(${UNIT_TEST_TARGET_NAME} ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES}) +target_link_libraries(${UNIT_TEST_TARGET_NAME} PUBLIC test_utils publishing) +set_property(TARGET ${UNIT_TEST_TARGET_NAME} PROPERTY FOLDER test/${MODULE_NAME}) \ No newline at end of file diff --git a/test/publishing/TestPlotting.cpp b/test/publishing/TestPlotting.cpp new file mode 100644 index 0000000..66a3c7a --- /dev/null +++ b/test/publishing/TestPlotting.cpp @@ -0,0 +1,33 @@ +#include "TestFramework.h" +#include "TestUtils.h" +#include "TestRenderUtils.h" + +#include "Plot.h" +#include "PlotNode.h" + +TEST_CASE(TestPlotting, "[publishing]") +{ + auto plot = std::make_unique(); + plot->setXAxisCaption("X Axis"); + plot->setYAxisCaption("Y Axis"); + + PlotSeries series("Series-1"); + + std::vector data{ {0.0, 0.0}, {10.0, 40.0}, {20.0, 80.0} }; + series.setData(data); + plot->addSeries(series); + + Point loc(10, 10); + auto plot_node = std::make_unique(Transform(loc)); + plot_node->setAxisEndStyle(LineEndNode::Style::CLOSED_ARROW); + + plot_node->setContent(plot.get()); + + TestRenderer renderer(800, 800); + + auto scene = renderer.getScene(); + scene->addNode(plot_node.get()); + + renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "plot.svg"); + renderer.write(TestUtils::getTestOutputDir(__FILE__) / "plot.png"); +} \ No newline at end of file