Start cleaning geometry module.

This commit is contained in:
jmsgrogan 2023-01-13 11:47:48 +00:00
parent 26ecae46b3
commit cd688f608f
52 changed files with 493 additions and 277 deletions

View file

@ -36,9 +36,13 @@ void BlochSphereNode::update(SceneInfo* sceneInfo)
auto loc = Point(mSize / 2.0, mSize / 2.0); auto loc = Point(mSize / 2.0, mSize / 2.0);
mInnerCircle = std::make_unique<CircleNode>(loc, mSize / 2.0); mInnerCircle = std::make_unique<CircleNode>(loc, mSize / 2.0);
mInnerCircle->setMinorRadius(mSize / 4.0); mInnerCircle->setMinorRadius(mSize / 4.0);
mInnerCircle->setStrokeThickness(0.5);
mOuterCircle = std::make_unique<CircleNode>(loc, mSize/2.0); mOuterCircle = std::make_unique<CircleNode>(loc, mSize/2.0);
const auto end_point_x = Point(loc.getX() + 1.2 * mSize / 2.0, loc.getY());
mXAxis = std::make_unique<LineNode>(loc, { end_point_x });
mCentreCircle = std::make_unique<CircleNode>(loc, mSize / 50.0); mCentreCircle = std::make_unique<CircleNode>(loc, mSize / 50.0);
mCentreCircle->setFillColor(Color(0, 0, 0)); mCentreCircle->setFillColor(Color(0, 0, 0));
mCentreCircle->setHasStrokeColor(false); mCentreCircle->setHasStrokeColor(false);

View file

@ -0,0 +1,12 @@
#pragma once
#include <string>
class AbstractNamedItem
{
public:
~AbstractNamedItem() = default;
protected:
std::string mName;
std::string mSymbol;
};

View file

@ -2,6 +2,7 @@ set(MODULE_NAME core)
list(APPEND core_HEADERS list(APPEND core_HEADERS
AbstractApp.h AbstractApp.h
AbstractNamedItem.h
AbstractWebApp.h AbstractWebApp.h
Dictionary.h Dictionary.h
Event.h Event.h

View file

@ -1,9 +1,8 @@
#pragma once #pragma once
class Rectangle; #include "Bounds.h"
class Point; #include "Point.h"
template<class T>
class Grid; class Grid;
class AbstractGeometricItem class AbstractGeometricItem
@ -13,6 +12,8 @@ public:
enum class Type enum class Type
{ {
LINE, LINE,
LINE_SEGMENT,
CURVE,
RECTANGLE, RECTANGLE,
TRIANGLE, TRIANGLE,
POINT, POINT,
@ -21,26 +22,13 @@ public:
UNKNOWN UNKNOWN
}; };
struct Bounds
{
Bounds(double width, double height)
: mWidth(width),
mHeight(height)
{
}
double mWidth{0.0};
double mHeight{0.0};
};
virtual ~AbstractGeometricItem() = default; virtual ~AbstractGeometricItem() = default;
virtual Bounds getSize() const = 0; virtual Bounds getBounds() const = 0;
virtual const Point& getLocation() const = 0; virtual const Point& getLocation() const = 0;
virtual void sample(Grid<unsigned char>* grid) const = 0; virtual void sample(Grid* grid) const = 0;
virtual Type getType() const { return Type::UNKNOWN; }; virtual Type getType() const { return Type::UNKNOWN; };
}; };

21
src/geometry/Bounds.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
struct Bounds
{
Bounds(double minX, double maxX, double minY, double maxY, double minZ = 0.0, double maxZ = 0.0)
: mMinX(minX),
mMaxX(maxX),
mMinY(minY),
mMaxY(maxY),
mMinZ(minZ),
mMaxZ(maxZ)
{
}
double mMinX{ 0.0 };
double mMaxX{ 0.0 };
double mMinY{ 0.0 };
double mMaxY{ 0.0 };
double mMinZ{ 0.0 };
double mMaxZ{ 0.0 };
};

View file

@ -1,36 +1,48 @@
set(MODULE_NAME geometry)
list(APPEND geometry_LIB_INCLUDES list(APPEND geometry_LIB_INCLUDES
AbstractGeometricItem.h AbstractGeometricItem.h
Circle.h Bounds.h
Circle.cpp DiscretePoint.h
DiscretePoint.h
DiscretePoint.cpp DiscretePoint.cpp
Grid.h Grid.h
Grid.cpp Grid.cpp
Line.h
Linalg.h
Linalg.cpp
Line.cpp
LineSegment.cpp
Matrix.h
Matrix.cpp
Path.h
Path.cpp
Point.h Point.h
Point.cpp Point.cpp
Quad.cpp
Rectangle.h
Rectangle.cpp
Triangle.h
Triangle.cpp
Transform.cpp Transform.cpp
Vector.h math/Linalg.h
Vector.cpp) math/Linalg.cpp
math/Matrix.h
math/Matrix.cpp
math/Vector.h
math/Vector.cpp
path/Curve.h
path/Curve.cpp
path/Line.h
path/Line.cpp
path/LineSegment.h
path/LineSegment.cpp
path/Path.h
path/Path.cpp
path/PathElement.h
primitives/Circle.h
primitives/Circle.cpp
primitives/Quad.h
primitives/Quad.cpp
primitives/Rectangle.h
primitives/Rectangle.cpp
primitives/Triangle.h
primitives/Triangle.cpp
)
add_library(${MODULE_NAME} SHARED ${geometry_LIB_INCLUDES})
# add the library target_include_directories(${MODULE_NAME} PUBLIC
add_library(geometry SHARED ${geometry_LIB_INCLUDES}) ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/math
${CMAKE_CURRENT_SOURCE_DIR}/path
${CMAKE_CURRENT_SOURCE_DIR}/primitives
)
target_include_directories(geometry PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
set_target_properties( geometry PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
set_property(TARGET geometry PROPERTY FOLDER src)

View file

@ -17,12 +17,12 @@ std::shared_ptr<DiscretePoint> DiscretePoint::Create(unsigned x, unsigned y)
return std::make_shared<DiscretePoint>(x, y); return std::make_shared<DiscretePoint>(x, y);
} }
unsigned DiscretePoint::GetX() const unsigned DiscretePoint::getX() const
{ {
return mX; return mX;
} }
unsigned DiscretePoint::GetY() const unsigned DiscretePoint::getY() const
{ {
return mY; return mY;
} }

View file

@ -4,20 +4,16 @@
class DiscretePoint class DiscretePoint
{ {
unsigned mX;
unsigned mY;
public: public:
DiscretePoint(unsigned x = 0, unsigned y = 0); DiscretePoint(unsigned x = 0, unsigned y = 0);
~DiscretePoint(); ~DiscretePoint();
std::shared_ptr<DiscretePoint> Create(unsigned x, unsigned y); std::shared_ptr<DiscretePoint> Create(unsigned x, unsigned y);
unsigned GetX() const; unsigned getX() const;
unsigned GetY() const; unsigned getY() const;
bool operator==(const DiscretePoint& rhs) const bool operator==(const DiscretePoint& rhs) const
{ {
@ -28,6 +24,10 @@ public:
{ {
return !operator==(rhs); return !operator==(rhs);
} }
private:
unsigned mX{ 0 };
unsigned mY{ 0 };
}; };
using Pixel = DiscretePoint; using Pixel = DiscretePoint;

View file

@ -1,50 +1,43 @@
#include "Grid.h" #include "Grid.h"
template<typename T> Grid::Grid(const Bounds& bounds)
Grid<T>::Grid(const ntk::Rectangle& bounds)
: mBounds(bounds) : mBounds(bounds)
{ {
mValues = std::vector<T>(mNumX*mNumY, T()); mValues = std::vector<double>(mNumX*mNumY, 0.0);
} }
template<typename T> const Bounds& Grid::getBounds() const
const ntk::Rectangle& Grid<T>::getBounds() const
{ {
return mBounds; return mBounds;
} }
template<typename T> double Grid::getXSpacing() const
double Grid<T>::getXSpacing() const
{ {
return mBounds.getWidth()/double(mNumX); const auto width = mBounds.mMaxX - mBounds.mMinX;
return width/double(mNumX);
} }
template<typename T> double Grid::getYSpacing() const
double Grid<T>::getYSpacing() const
{ {
return mBounds.getHeight()/double(mNumY); const auto height = mBounds.mMaxY - mBounds.mMinY;
return height/double(mNumY);
} }
template<typename T> const std::vector<double>& Grid::getValues() const
const std::vector<T>& Grid<T>::getValues() const
{ {
return mValues; return mValues;
} }
template<typename T> void Grid::resetBounds(const Bounds& bounds)
void Grid<T>::resetBounds(const ntk::Rectangle& bounds)
{ {
mBounds = bounds; mBounds = bounds;
mValues = std::vector<T>(mNumX*mNumY, T()); mValues = std::vector<double>(mNumX*mNumY, 0.0);
} }
template<typename T> void Grid::setValues(const std::vector<std::size_t>& indices, double value)
void Grid<T>::setValues(const std::vector<std::size_t>& indices, T value)
{ {
for (auto index : indices) for (auto index : indices)
{ {
mValues[index] = value; mValues[index] = value;
} }
} }
template class Grid<unsigned char>;

View file

@ -1,29 +1,29 @@
#pragma once #pragma once
#include "Rectangle.h" #include "Bounds.h"
#include <vector> #include <vector>
template<typename T>
class Grid class Grid
{ {
public: public:
Grid(const ntk::Rectangle& bounds); Grid(const Bounds& bounds);
const ntk::Rectangle& getBounds() const; const Bounds& getBounds() const;
double getXSpacing() const; double getXSpacing() const;
double getYSpacing() const; double getYSpacing() const;
const std::vector<T>& getValues() const; const std::vector<double>& getValues() const;
void resetBounds(const ntk::Rectangle& bounds); void resetBounds(const Bounds& bounds);
void setValues(const std::vector<std::size_t>& indices, T value); void setValues(const std::vector<std::size_t>& indices, double value);
private: private:
ntk::Rectangle mBounds; Bounds mBounds;
std::vector<T> mValues; std::vector<double> mValues;
unsigned mNumX{5}; unsigned mNumX{5};
unsigned mNumY{5}; unsigned mNumY{5};
}; };

View file

View file

View file

View file

@ -1,5 +1,7 @@
#include "Point.h" #include "Point.h"
#include <cmath>
Point::Point(double x, double y, double z) Point::Point(double x, double y, double z)
: mX(x), : mX(x),
mY(y), mY(y),
@ -8,8 +10,8 @@ Point::Point(double x, double y, double z)
} }
Point::Point(const DiscretePoint& point) Point::Point(const DiscretePoint& point)
: mX(point.GetX()), : mX(static_cast<double>(point.getX())),
mY(point.GetY()), mY(static_cast<double>(point.getY())),
mZ(0) mZ(0)
{ {

View file

@ -4,12 +4,10 @@
#include "Vector.h" #include "Vector.h"
#include <memory> #include <memory>
#include <cmath>
class Point class Point
{ {
public: public:
Point(double x = 0, double y = 0, double z = 0); Point(double x = 0, double y = 0, double z = 0);
Point(const DiscretePoint& point); Point(const DiscretePoint& point);

View file

@ -0,0 +1,14 @@
#pragma once
#include <vector>
class Matrix
{
public:
Matrix(unsigned numRows, unsigned numColumns)
{
mData = std::vector<double>(numRows * numColumns, 0.0);
}
private:
std::vector<double> mData;
};

13
src/geometry/path/Curve.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "PathElement.h"
class Curve : public PathElement
{
public:
enum class CurveType
{
ARC,
CUBIC_BEZIER
};
};

View file

@ -0,0 +1,53 @@
#include "Line.h"
Line::Line(const Point& start, const std::vector<Point>& points)
: mStartPoint(start),
mPoints(points)
{
}
const std::vector<Point>& Line::getPoints() const
{
return mPoints;
}
Line::Type Line::getType() const
{
return Line::Type::LINE;
}
const Point& Line::getLocation() const
{
return mStartPoint;
}
Bounds Line::getBounds() const
{
double minX = mStartPoint.getX();
double maxX = mStartPoint.getX();
double minY = mStartPoint.getY();
double maxY = mStartPoint.getY();
for (const auto& point : mPoints)
{
if (point.getX() > maxX)
{
maxX = point.getX();
}
if (point.getX() < minX)
{
minX = point.getX();
}
if (point.getY() > maxY)
{
maxY = point.getX();
}
if (point.getY() < minY)
{
minY = point.getY();
}
}
return { minX, maxX, minY, maxY };
}

23
src/geometry/path/Line.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include "PathElement.h"
#include <vector>
class Line : public PathElement
{
public:
Line(const Point& start, const std::vector<Point>& points);
const std::vector<Point>& getPoints() const;
Line::Type getType() const override;
const Point& getLocation() const override;
Bounds getBounds() const override;
private:
Point mStartPoint;
std::vector<Point> mPoints;
};

View file

@ -27,14 +27,20 @@ const Point& LineSegment::getPoint1() const
return mP1; return mP1;
} }
void LineSegment::sample(Grid<unsigned char>* grid) const void LineSegment::sample(Grid* grid) const
{ {
} }
LineSegment::Bounds LineSegment::getSize() const Bounds LineSegment::getBounds() const
{ {
return {mP0.getDeltaX(mP1), mP0.getDeltaY(mP1)}; const auto minX = std::min(mP0.getX(), mP1.getX());
const auto maxX = std::max(mP0.getX(), mP1.getX());
const auto minY = std::min(mP0.getY(), mP1.getY());
const auto maxY = std::max(mP0.getY(), mP1.getY());
return {minX, maxX, minY, maxY};
} }
const Point& LineSegment::getLocation() const const Point& LineSegment::getLocation() const

View file

@ -1,12 +1,8 @@
#pragma once #pragma once
#include "AbstractGeometricItem.h" #include "PathElement.h"
#include "Point.h"
template<class T> class LineSegment : public PathElement
class Grid;
class LineSegment : public AbstractGeometricItem
{ {
public: public:
LineSegment(const Point& p0, const Point& p1); LineSegment(const Point& p0, const Point& p1);
@ -19,9 +15,9 @@ public:
const Point& getPoint1() const; const Point& getPoint1() const;
void sample(Grid<unsigned char>* grid) const override; void sample(Grid* grid) const override;
Bounds getSize() const override; Bounds getBounds() const override;
const Point& getLocation() const override; const Point& getLocation() const override;

View file

@ -0,0 +1,6 @@
#include "Path.h"
const std::vector<PathElementPtr> Path::getElements() const
{
return mElements;
}

17
src/geometry/path/Path.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include "PathElement.h"
#include <vector>
#include <memory>
using PathElementPtr = std::unique_ptr<PathElement>;
class Path : public AbstractGeometricItem
{
public:
const std::vector<PathElementPtr> getElements() const;
private:
std::vector<PathElementPtr> mElements;
};

View file

@ -0,0 +1,9 @@
#pragma once
#include "AbstractGeometricItem.h"
class PathElement : public AbstractGeometricItem
{
public:
~PathElement() = default;
};

View file

@ -1,8 +1,8 @@
#include "Circle.h" #include "Circle.h"
Circle::Circle(const Point& centre, double radius) Circle::Circle(const Point& centre, double radius)
: mCentre(centre), : mCentre(centre),
mRadius(radius) mRadius(radius)
{ {
mMinorRadius = mRadius; mMinorRadius = mRadius;
} }
@ -27,14 +27,23 @@ void Circle::setMinorRadius(double radius)
mMinorRadius = radius; mMinorRadius = radius;
} }
void Circle::sample(Grid<unsigned char>* grid) const void Circle::sample(Grid* grid) const
{ {
} }
Circle::Bounds Circle::getSize() const bool Circle::isEllipse() const
{ {
return Bounds{ 2.0 * mRadius, 2.0 * mMinorRadius }; return mRadius != mMinorRadius;
}
Bounds Circle::getBounds() const
{
double minX = mCentre.getX() - mRadius;
double maxX = mCentre.getX() + mRadius;
double minY = mCentre.getY() - mMinorRadius;
double maxY = mCentre.getY() + mMinorRadius;
return { minX, maxX, minY, maxY };
} }
Circle::Type Circle::getType() const Circle::Type Circle::getType() const

View file

@ -14,14 +14,16 @@ public:
double getMinorRadius() const; double getMinorRadius() const;
void setMinorRadius(double radius); Bounds getBounds() const override;
void sample(Grid<unsigned char>* grid) const override;
Bounds getSize() const override;
Type getType() const override; Type getType() const override;
bool isEllipse() const;
void setMinorRadius(double radius);
void sample(Grid* grid) const override;
private: private:
double mMinorRadius{ 0.5 }; double mMinorRadius{ 0.5 };
double mRadius{ 0.5 }; double mRadius{ 0.5 };

View file

@ -10,18 +10,28 @@ namespace ntk {
Rectangle::Rectangle(const Point& bottomLeft, double width, double height) Rectangle::Rectangle(const Point& bottomLeft, double width, double height)
: mBottomLeft(bottomLeft), : mBottomLeft(bottomLeft),
mHeight(height), mHeight(height),
mWidth(width) mWidth(width)
{ {
} }
Rectangle Rectangle::getBounds() const Rectangle::Type Rectangle::getType() const
{ {
return Rectangle(mBottomLeft, Point(mBottomLeft, mWidth, mHeight)); return AbstractGeometricItem::Type::RECTANGLE;
} }
void Rectangle::sample(Grid<unsigned char>* grid) const Bounds Rectangle::getBounds() const
{
const auto minX = mBottomLeft.getX();
const auto maxX = mBottomLeft.getX() + mWidth;
const auto minY = mBottomLeft.getY();
const auto maxY = mBottomLeft.getY() + mHeight;
return { minX , maxX , minY , maxY };
}
void Rectangle::sample(Grid* grid) const
{ {
} }
@ -40,9 +50,4 @@ namespace ntk {
{ {
return mBottomLeft; return mBottomLeft;
} }
Rectangle::Bounds Rectangle::getSize() const
{
return { mWidth, mHeight };
}
} }

View file

@ -1,10 +1,6 @@
#pragma once #pragma once
#include "AbstractGeometricItem.h" #include "AbstractGeometricItem.h"
#include "Point.h"
template<class T>
class Grid;
namespace ntk{ namespace ntk{
class Rectangle : public AbstractGeometricItem class Rectangle : public AbstractGeometricItem
@ -19,16 +15,11 @@ public:
const Point& getLocation() const override; const Point& getLocation() const override;
Bounds getSize() const override; Bounds getBounds() const override;
Rectangle getBounds() const; Type getType() const override;
Type getType() const void sample(Grid* grid) const override;
{
return AbstractGeometricItem::Type::RECTANGLE;
}
void sample(Grid<unsigned char>* grid) const override;
private: private:
Point mBottomLeft; Point mBottomLeft;

View file

@ -0,0 +1,8 @@
#pragma once
#include "AbstractGeometricItem.h"
class Triangle : public AbstractGeometricItem
{
};

View file

@ -102,7 +102,7 @@ void SvgConverter::setStyle(SceneModel* model, SvgShapeElement* element) const
if (model->hasOutlineColor()) if (model->hasOutlineColor())
{ {
element->setStrokeColor(model->getOutlineColor()); element->setStrokeColor(model->getOutlineColor());
element->setStrokeWidth(1.0 / transform.getScaleX()); element->setStrokeWidth(model->getOutlineThickness() / transform.getScaleX());
} }
else else
{ {
@ -126,8 +126,13 @@ void SvgConverter::convertPrimitive(SvgDocument* document, SceneModel* model) co
{ {
auto model_circle = dynamic_cast<Circle*>(model->getGeometry()); auto model_circle = dynamic_cast<Circle*>(model->getGeometry());
auto circle = std::make_unique<SvgCircle>(); 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()); circle->setRadius(model_circle->getRadius());
if (model_circle->isEllipse())
{
circle->setMinorRadius(model_circle->getMinorRadius());
}
setStyle(model, circle.get()); setStyle(model, circle.get());
document->getRoot()->addChild(std::move(circle)); document->getRoot()->addChild(std::move(circle));

View file

@ -1,6 +1,5 @@
#include "CircleNode.h" #include "CircleNode.h"
#include "FontsManager.h"
#include "SceneModel.h" #include "SceneModel.h"
#include "AbstractMesh.h" #include "AbstractMesh.h"
#include "MeshPrimitives.h" #include "MeshPrimitives.h"
@ -11,7 +10,7 @@ CircleNode::CircleNode(const Point& location, double radius)
: GeometryNode(location), : GeometryNode(location),
mRadius(radius) mRadius(radius)
{ {
mMinorRadius = mRadius;
} }
CircleNode::Type CircleNode::getType() CircleNode::Type CircleNode::getType()
@ -24,23 +23,6 @@ double CircleNode::getRadius() const
return mRadius; return mRadius;
} }
SceneItem* CircleNode::getSceneItem(std::size_t idx) const
{
if (idx == 0)
{
return mBackgroundItem.get();
}
else
{
return nullptr;
}
}
std::size_t CircleNode::getNumSceneItems() const
{
return 1;
}
void CircleNode::setRadius(double radius) void CircleNode::setRadius(double radius)
{ {
if (mRadius != radius) if (mRadius != radius)
@ -63,8 +45,9 @@ void CircleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
{ {
if (sceneInfo->mSupportsGeometryPrimitives) if (sceneInfo->mSupportsGeometryPrimitives)
{ {
auto circle = std::make_unique<Circle>(Point{ 0, 0 }, 0.5); double unit_circle_radius = 0.5;
circle->setMinorRadius(mMinorRadius); auto circle = std::make_unique<Circle>(Point{ 0, 0 }, unit_circle_radius);
circle->setMinorRadius(unit_circle_radius*mMinorRadius/mRadius);
mBackgroundItem = std::make_unique<SceneModel>(std::move(circle)); mBackgroundItem = std::make_unique<SceneModel>(std::move(circle));
} }
else else
@ -75,40 +58,7 @@ void CircleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
mBackgroundItem->setName(mName + "_Model"); mBackgroundItem->setName(mName + "_Model");
} }
void CircleNode::updateMaterial() void CircleNode::updateTransform()
{ {
if (!mBackgroundItem) mBackgroundItem->updateTransform({ mLocation, 2 * mRadius, 2 * mRadius });
{
return;
}
if (mHasFillColor)
{
mBackgroundItem->setFillColor(mFillColor);
}
if (mHasStrokeColor)
{
mBackgroundItem->setOutlineColor(mStrokeColor);
}
}
void CircleNode::update(SceneInfo* sceneInfo)
{
if (!mBackgroundItem || mGeometryIsDirty)
{
createOrUpdateGeometry(sceneInfo);
mGeometryIsDirty = false;
}
if (mTransformIsDirty)
{
mBackgroundItem->updateTransform({mLocation, 2*mRadius, 2*mRadius});
mTransformIsDirty = false;
}
if (mMaterialIsDirty)
{
updateMaterial();
mMaterialIsDirty = false;
}
} }

View file

@ -8,22 +8,14 @@ public:
CircleNode(const Point& location, double radius); CircleNode(const Point& location, double radius);
Type getType() override; Type getType() override;
double getRadius() const; double getRadius() const;
SceneItem* getSceneItem(std::size_t idx) const override;
std::size_t getNumSceneItems() const override;
void setMinorRadius(double radius); void setMinorRadius(double radius);
void setRadius(double radius); void setRadius(double radius);
void update(SceneInfo* sceneInfo) override;
private: private:
void createOrUpdateGeometry(SceneInfo* sceneInfo); void createOrUpdateGeometry(SceneInfo* sceneInfo) override;
void updateMaterial(); void updateTransform() override;
double mRadius{1.0}; double mRadius{1.0};
double mMinorRadius{ 1.0 }; double mMinorRadius{ 1.0 };
std::unique_ptr<SceneModel> mBackgroundItem;
std::unique_ptr<SceneModel> mOutlineItem;
}; };

View file

@ -1,12 +1,18 @@
#pragma once #pragma once
#include "GeometryNode.h" #include "GeometryNode.h"
#include "SceneInfo.h"
#include "Line.h"
#include <vector>
class LineNode : public GeometryNode class LineNode : public GeometryNode
{ {
public: public:
LineNode(const Point& location) LineNode(const Point& location, const std::vector<Point>& points)
: GeometryNode(location) : GeometryNode(location),
mPoints(points)
{ {
} }
@ -15,4 +21,22 @@ public:
{ {
return Type::Line; return Type::Line;
} }
void createOrUpdateGeometry(SceneInfo* sceneInfo)
{
if (sceneInfo->mSupportsGeometryPrimitives)
{
auto line = std::make_unique<Line>(Point{ 0, 0 }, 1, 1);
mBackgroundItem = std::make_unique<SceneModel>(std::move(line));
}
mBackgroundItem->setName(mName + "_Model");
}
void updateTransform()
{
mBackgroundItem->updateTransform({ mLocation });
}
private:
std::vector<Point> mPoints;
}; };

View file

@ -5,8 +5,6 @@
#include "MeshPrimitives.h" #include "MeshPrimitives.h"
#include "SceneInfo.h" #include "SceneInfo.h"
#include <iostream>
RectangleNode::RectangleNode(const Point& loc, double width, double height) RectangleNode::RectangleNode(const Point& loc, double width, double height)
: GeometryNode(loc), : GeometryNode(loc),
mWidth(width), mWidth(width),
@ -25,23 +23,6 @@ GeometryNode::Type RectangleNode::getType()
return GeometryNode::Type::Rectangle; return GeometryNode::Type::Rectangle;
} }
SceneItem* RectangleNode::getSceneItem(std::size_t idx) const
{
if (idx == 0)
{
return mBackgroundItem.get();
}
else
{
return nullptr;
}
}
std::size_t RectangleNode::getNumSceneItems() const
{
return 1;
}
double RectangleNode::getWidth() const double RectangleNode::getWidth() const
{ {
return mWidth; return mWidth;
@ -86,40 +67,7 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
mBackgroundItem->setName(mName + "_Model"); mBackgroundItem->setName(mName + "_Model");
} }
void RectangleNode::updateMaterial() void RectangleNode::updateTransform()
{ {
if (!mBackgroundItem) mBackgroundItem->updateTransform({ mLocation, mWidth, mHeight });
{ }
return;
}
if (mHasFillColor)
{
mBackgroundItem->setFillColor(mFillColor);
}
if (mHasStrokeColor)
{
mBackgroundItem->setOutlineColor(mStrokeColor);
}
}
void RectangleNode::update(SceneInfo* sceneInfo)
{
if (!mBackgroundItem || mGeometryIsDirty)
{
createOrUpdateGeometry(sceneInfo);
mGeometryIsDirty = false;
}
if (mTransformIsDirty)
{
mBackgroundItem->updateTransform({mLocation, mWidth, mHeight});
mTransformIsDirty = false;
}
if (mMaterialIsDirty)
{
updateMaterial();
mMaterialIsDirty = false;
}
}

View file

@ -9,27 +9,20 @@ class RectangleNode : public GeometryNode
public: public:
RectangleNode(const Point& loc, double width, double height); RectangleNode(const Point& loc, double width, double height);
static std::unique_ptr<RectangleNode> Create(const Point& loc, double width, double height); static std::unique_ptr<RectangleNode> Create(const Point& loc, double width, double height);
GeometryNode::Type getType() override; GeometryNode::Type getType() override;
double getWidth() const; double getWidth() const;
double getHeight() const; double getHeight() const;
SceneItem* getSceneItem(std::size_t idx) const override;
std::size_t getNumSceneItems() const override;
void setWidth(double width); void setWidth(double width);
void setHeight(double height); void setHeight(double height);
void update(SceneInfo* sceneInfo) override;
private: private:
void createOrUpdateGeometry(SceneInfo* sceneInfo); void createOrUpdateGeometry(SceneInfo* sceneInfo) override;
void updateMaterial(); void updateTransform() override;
double mWidth{1}; double mWidth{1};
double mHeight{1}; double mHeight{1};
std::unique_ptr<SceneModel> mBackgroundItem;
std::unique_ptr<SceneModel> mOutlineItem;
}; };
using RectangleNodePtr = std::unique_ptr<RectangleNode>; using RectangleNodePtr = std::unique_ptr<RectangleNode>;

View file

@ -1,19 +1,45 @@
#include "GeometryNode.h" #include "GeometryNode.h"
#include "SceneInfo.h"
#include "SceneModel.h"
GeometryNode::GeometryNode(const Point& location) GeometryNode::GeometryNode(const Point& location)
: MaterialNode(location), : MaterialNode(location),
mStrokeThickness(1), mStrokeThickness(1.0),
mType(Type::Path) mType(Type::Path)
{ {
} }
unsigned GeometryNode::getStrokeThickness() const GeometryNode::~GeometryNode()
{
}
SceneItem* GeometryNode::getSceneItem(std::size_t idx) const
{
if (idx == 0)
{
return mBackgroundItem.get();
}
else
{
return nullptr;
}
}
std::size_t GeometryNode::getNumSceneItems() const
{
return 1;
}
double GeometryNode::getStrokeThickness() const
{ {
return mStrokeThickness; return mStrokeThickness;
} }
void GeometryNode::setStrokeThickness(unsigned thickness) void GeometryNode::setStrokeThickness(double thickness)
{ {
if (mStrokeThickness != thickness) if (mStrokeThickness != thickness)
{ {
@ -21,3 +47,43 @@ void GeometryNode::setStrokeThickness(unsigned thickness)
mStrokeThickness = thickness; mStrokeThickness = thickness;
} }
} }
void GeometryNode::updateMaterial()
{
if (!mBackgroundItem)
{
return;
}
if (mHasFillColor)
{
mBackgroundItem->setFillColor(mFillColor);
}
if (mHasStrokeColor)
{
mBackgroundItem->setOutlineColor(mStrokeColor);
mBackgroundItem->setOutlineThickness(mStrokeThickness);
}
}
void GeometryNode::update(SceneInfo* sceneInfo)
{
if (!mBackgroundItem || mGeometryIsDirty)
{
createOrUpdateGeometry(sceneInfo);
mGeometryIsDirty = false;
}
if (mTransformIsDirty)
{
updateTransform();
mTransformIsDirty = false;
}
if (mMaterialIsDirty)
{
updateMaterial();
mMaterialIsDirty = false;
}
}

View file

@ -2,6 +2,9 @@
#include "MaterialNode.h" #include "MaterialNode.h"
struct SceneInfo;
class SceneModel;
class GeometryNode : public MaterialNode class GeometryNode : public MaterialNode
{ {
public: public:
@ -11,23 +14,33 @@ public:
Rectangle, Rectangle,
Circle, Circle,
Arc, Arc,
Line, Line
Polyline
}; };
public: public:
GeometryNode(const Point& location); GeometryNode(const Point& location);
virtual ~GeometryNode() = default; virtual ~GeometryNode();
virtual Type getType() = 0; virtual Type getType() = 0;
unsigned getStrokeThickness() const; SceneItem* getSceneItem(std::size_t idx) const override;
void setStrokeThickness(unsigned thickness); std::size_t getNumSceneItems() const override;
double getStrokeThickness() const;
void setStrokeThickness(double thickness);
void update(SceneInfo* sceneInfo) override;
protected: protected:
unsigned mStrokeThickness{0}; virtual void createOrUpdateGeometry(SceneInfo* sceneInfo) = 0;
virtual void updateMaterial();
virtual void updateTransform() = 0;
double mStrokeThickness{0};
Type mType; Type mType;
bool mGeometryIsDirty{true}; bool mGeometryIsDirty{true};
std::unique_ptr<SceneModel> mBackgroundItem;
}; };
using GeometryNodePtr = std::unique_ptr<GeometryNode>; using GeometryNodePtr = std::unique_ptr<GeometryNode>;

View file

@ -20,6 +20,11 @@ const Transform& SceneItem::getTransform() const
return mTransform; return mTransform;
} }
double SceneItem::getOutlineThickness() const
{
return mOutlineThickness;
}
bool SceneItem::isVisible() const bool SceneItem::isVisible() const
{ {
return mIsVisible; return mIsVisible;
@ -40,6 +45,11 @@ void SceneItem::setIsVisible(bool isVisible)
mIsVisible = isVisible; mIsVisible = isVisible;
} }
void SceneItem::setOutlineThickness(double thickness)
{
mOutlineThickness = thickness;
}
void SceneItem::setFillColor(const Color& color) void SceneItem::setFillColor(const Color& color)
{ {
if (!mHasFillColor || mFillColor != color) if (!mHasFillColor || mFillColor != color)

View file

@ -28,6 +28,8 @@ public:
virtual Type getType() const = 0; virtual Type getType() const = 0;
double getOutlineThickness() const;
bool hasFillColor() const; bool hasFillColor() const;
bool hasOutlineColor() const; bool hasOutlineColor() const;
@ -38,6 +40,8 @@ public:
void setOutlineColor(const Color& color); void setOutlineColor(const Color& color);
void setOutlineThickness(double thickness);
void setFillColor(const Color& color); void setFillColor(const Color& color);
void updateTransform(const Transform& transform); void updateTransform(const Transform& transform);
@ -60,6 +64,7 @@ protected:
bool mHasOutlineColor{ false }; bool mHasOutlineColor{ false };
Color mOutlineColor; Color mOutlineColor;
double mOutlineThickness{ 1.0 };
bool mColorIsDirty{true}; bool mColorIsDirty{true};
bool mTransformIsDirty{true}; bool mTransformIsDirty{true};

View file

@ -2,8 +2,9 @@
#include <sstream> #include <sstream>
SvgCircle::SvgCircle() SvgCircle::SvgCircle(Type type)
: SvgShapeElement("circle") : SvgShapeElement(type == Type::REGULAR ? "circle" : "ellipse"),
mType(type)
{ {
} }
@ -22,7 +23,23 @@ void SvgCircle::setLocation(const Point& loc)
void SvgCircle::setRadius(double rad) void SvgCircle::setRadius(double rad)
{ {
auto r = std::make_unique<XmlAttribute>("r"); if (mType == Type::REGULAR)
{
auto r = std::make_unique<XmlAttribute>("r");
r->setValue(std::to_string(rad));
addAttribute(std::move(r));
}
else
{
auto r = std::make_unique<XmlAttribute>("rx");
r->setValue(std::to_string(rad));
addAttribute(std::move(r));
}
}
void SvgCircle::setMinorRadius(double rad)
{
auto r = std::make_unique<XmlAttribute>("ry");
r->setValue(std::to_string(rad)); r->setValue(std::to_string(rad));
addAttribute(std::move(r)); addAttribute(std::move(r));
} }

View file

@ -8,11 +8,21 @@
class SvgCircle : public SvgShapeElement class SvgCircle : public SvgShapeElement
{ {
public: public:
SvgCircle(); enum class Type
{
REGULAR,
ELLIPSE
};
SvgCircle(Type type = Type::REGULAR);
void setLocation(const Point& loc); void setLocation(const Point& loc);
void setRadius(double rad); void setRadius(double rad);
void setMinorRadius(double rad);
private:
Type mType{ Type::REGULAR };
}; };
class SvgRectangle : public SvgShapeElement class SvgRectangle : public SvgShapeElement