Fix linux build.

This commit is contained in:
James Grogan 2023-01-28 16:58:26 +00:00
parent a6d92e142f
commit 9e1d951520
50 changed files with 1586 additions and 1192 deletions

View file

@ -4,6 +4,8 @@
#include "WireNode.h" #include "WireNode.h"
#include "LogicGateNode.h" #include "LogicGateNode.h"
#include "LineNode.h"
#include "FileLogger.h" #include "FileLogger.h"
ElectronicCircuitNode::ElectronicCircuitNode(const Transform& transform) ElectronicCircuitNode::ElectronicCircuitNode(const Transform& transform)

View file

@ -12,194 +12,194 @@
std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const Path& path) std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const Path& path)
{ {
File file(path); File file(path);
return read(file.readText()); return read(file.readText());
} }
std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const std::string& content) std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const std::string& content)
{ {
auto circuit = std::make_unique<QuantumCircuit>(); auto circuit = std::make_unique<QuantumCircuit>();
mWorkingCircuit = circuit.get(); mWorkingCircuit = circuit.get();
std::size_t cursor = 0; std::size_t cursor = 0;
for (const auto& line : StringUtils::toLines(content)) for (const auto& line : StringUtils::toLines(content))
{ {
onLine(line, cursor); onLine(line, cursor);
cursor++; cursor++;
} }
circuit->buildWireConnections(); circuit->buildWireConnections();
return circuit; return circuit;
} }
void QuantumCircuitReader::onLine(const std::string& line, std::size_t jdx) void QuantumCircuitReader::onLine(const std::string& line, std::size_t jdx)
{ {
mWorkingString.clear(); mWorkingString.clear();
std::size_t cursor = 0; std::size_t cursor = 0;
while (cursor < line.size()) while (cursor < line.size())
{ {
const auto c = line[cursor]; const auto c = line[cursor];
MLOG_INFO("Working char: " << std::string(1, c)); MLOG_INFO("Working char: " << std::string(1, c));
if (c == '|') if (c == '|')
{ {
if (cursor + 1 < line.size()) if (cursor + 1 < line.size())
{ {
if (line[cursor + 1] == '-') if (line[cursor + 1] == '-')
{ {
onVertialQuantumWire({ cursor, jdx }); onVertialQuantumWire({ cursor, jdx });
} }
else if (auto ket = checkForKet(line.substr(cursor + 1, line.size() - cursor)); !ket.empty()) else if (auto ket = checkForKet(line.substr(cursor + 1, line.size() - cursor)); !ket.empty())
{ {
onKet({ cursor, jdx }, ket); onKet({ cursor, jdx }, ket);
cursor += ket.size() + 1; cursor += ket.size() + 1;
} }
} }
else else
{ {
mWorkingString += c; mWorkingString += c;
} }
} }
else if (c == '-') else if (c == '-')
{ {
if (cursor + 1 < line.size()) if (cursor + 1 < line.size())
{ {
const auto end_id = getWireEnd(line.substr(cursor, line.size() - cursor)); const auto end_id = getWireEnd(line.substr(cursor, line.size() - cursor));
MLOG_INFO("Wire: " << cursor << " with length " << end_id); MLOG_INFO("Wire: " << cursor << " with length " << end_id);
cursor += end_id - 1; cursor += end_id - 1;
} }
else else
{ {
mWorkingString += c; mWorkingString += c;
} }
} }
else else
{ {
if (cursor + 1 < line.size()) if (cursor + 1 < line.size())
{ {
auto gate = checkForGate(line.substr(cursor, line.size() - cursor)); auto gate = checkForGate(line.substr(cursor, line.size() - cursor));
onGate({ cursor, jdx }, gate); onGate({ cursor, jdx }, gate);
cursor += gate.size() - 1; cursor += gate.size() - 1;
} }
else else
{ {
mWorkingString += c; mWorkingString += c;
} }
} }
cursor++; cursor++;
} }
onLineEnd(); onLineEnd();
} }
void QuantumCircuitReader::onLineEnd() void QuantumCircuitReader::onLineEnd()
{ {
auto output_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::OUTPUT); auto output_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::OUTPUT);
auto wire = std::make_unique<QuantumWire>(mWorkingElement, output_terminal.get()); auto wire = std::make_unique<QuantumWire>(mWorkingElement, output_terminal.get());
mWorkingCircuit->addQuantumWire(std::move(wire)); mWorkingCircuit->addQuantumWire(std::move(wire));
mWorkingCircuit->addOutputTerminal(std::move(output_terminal)); mWorkingCircuit->addOutputTerminal(std::move(output_terminal));
mWorkingElement = nullptr; mWorkingElement = nullptr;
} }
void QuantumCircuitReader::onGate(Location loc, const std::string value) void QuantumCircuitReader::onGate(Location, const std::string value)
{ {
MLOG_INFO("Got gate: " << value); MLOG_INFO("Got gate: " << value);
QuantumGatePtr gate; QuantumGatePtr gate;
if (value == "X") if (value == "X")
{ {
gate = std::make_unique<XQuantumGate>(); gate = std::make_unique<XQuantumGate>();
} }
else if (value == "Z") else if (value == "Z")
{ {
gate = std::make_unique<ZQuantumGate>(); gate = std::make_unique<ZQuantumGate>();
} }
if (gate) if (gate)
{ {
auto wire = std::make_unique<QuantumWire>(mWorkingElement, gate.get()); auto wire = std::make_unique<QuantumWire>(mWorkingElement, gate.get());
mWorkingCircuit->addQuantumWire(std::move(wire)); mWorkingCircuit->addQuantumWire(std::move(wire));
mWorkingElement = gate.get(); mWorkingElement = gate.get();
mWorkingCircuit->addLogicGate(std::move(gate)); mWorkingCircuit->addLogicGate(std::move(gate));
} }
} }
std::string QuantumCircuitReader::checkForGate(const std::string& segment) std::string QuantumCircuitReader::checkForGate(const std::string& segment)
{ {
std::string working_string; std::string working_string;
for (const auto c : segment) for (const auto c : segment)
{ {
if (c == '-') if (c == '-')
{ {
break; break;
} }
working_string += c; working_string += c;
} }
return working_string; return working_string;
} }
void QuantumCircuitReader::onKet(Location loc, const std::string value) void QuantumCircuitReader::onKet(Location, const std::string value)
{ {
MLOG_INFO("Got input state: " << value); MLOG_INFO("Got input state: " << value);
Qubit qubit; Qubit qubit;
if (value == "1") if (value == "1")
{ {
qubit = Qubit({ 0.0, 0.0 }, { 1.0, 0.0 }); qubit = Qubit({ 0.0, 0.0 }, { 1.0, 0.0 });
} }
auto input_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::INPUT); auto input_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::INPUT);
mWorkingElement = input_terminal.get(); mWorkingElement = input_terminal.get();
mWorkingCircuit->addInputTerminal(std::move(input_terminal)); mWorkingCircuit->addInputTerminal(std::move(input_terminal));
} }
std::size_t QuantumCircuitReader::getWireEnd(const std::string& segment) std::size_t QuantumCircuitReader::getWireEnd(const std::string& segment)
{ {
std::size_t idx = 0; std::size_t idx = 0;
for (const auto c : segment) for (const auto c : segment)
{ {
if (c != '-') if (c != '-')
{ {
break; break;
} }
idx++; idx++;
} }
return idx; return idx;
} }
std::string QuantumCircuitReader::checkForKet(const std::string& segment) std::string QuantumCircuitReader::checkForKet(const std::string& segment)
{ {
std::string working_string; std::string working_string;
bool found{ false }; bool found{ false };
for (const auto c : segment) for (const auto c : segment)
{ {
if (c == '>') if (c == '>')
{ {
found = true; found = true;
break; break;
} }
else else
{ {
working_string += c; working_string += c;
} }
} }
if (found) if (found)
{ {
return working_string; return working_string;
} }
else else
{ {
return {}; return {};
} }
} }
void QuantumCircuitReader::onVertialQuantumWire(Location loc) void QuantumCircuitReader::onVertialQuantumWire(Location)
{ {
} }

View file

@ -2,16 +2,15 @@
const std::vector<Qubit>& QuantumState::getData() const const std::vector<Qubit>& QuantumState::getData() const
{ {
return mState; return mState;
} }
std::string QuantumState::toString() const std::string QuantumState::toString() const
{ {
std::string out; std::string out;
std::size_t count{ 0 }; for (const auto& qubit : mState)
for (const auto& qubit : mState) {
{ out += "|" + qubit.toString() + "\n";
out += "|" + qubit.toString() + "\n"; }
} return out;
return out;
} }

View file

@ -8,15 +8,15 @@
class QuantumState class QuantumState
{ {
public: public:
void addValue(const Qubit& data) void addValue(const Qubit& data)
{ {
mState.push_back(data); mState.push_back(data);
} }
const std::vector<Qubit>& getData() const; const std::vector<Qubit>& getData() const;
std::string toString() const; std::string toString() const;
private: private:
std::vector<Qubit> mState; std::vector<Qubit> mState;
}; };

View file

@ -9,6 +9,9 @@
#include "QuantumWireNode.h" #include "QuantumWireNode.h"
#include "QuantumGateNode.h" #include "QuantumGateNode.h"
#include "LatexMathExpression.h"
#include "EquationNode.h"
QuantumCircuitNode::QuantumCircuitNode(const Transform& t) QuantumCircuitNode::QuantumCircuitNode(const Transform& t)
: AbstractVisualNode(t) : AbstractVisualNode(t)
{ {
@ -17,8 +20,8 @@ QuantumCircuitNode::QuantumCircuitNode(const Transform& t)
void QuantumCircuitNode::setContent(QuantumCircuit* circuit) void QuantumCircuitNode::setContent(QuantumCircuit* circuit)
{ {
mContent = circuit; mContent = circuit;
mContentDirty = true; mContentDirty = true;
} }
void QuantumCircuitNode::update(SceneInfo* sceneInfo) void QuantumCircuitNode::update(SceneInfo* sceneInfo)

View file

@ -7,7 +7,7 @@
#include "LatexMathExpression.h" #include "LatexMathExpression.h"
QuantumGateNode::QuantumGateNode(const Transform& t) QuantumGateNode::QuantumGateNode(const Transform& t)
: QuantumCircuitElementNode(t) : QuantumCircuitElementNode(t)
{ {
} }
@ -19,93 +19,93 @@ QuantumGateNode::~QuantumGateNode()
void QuantumGateNode::setContent(QuantumGate* gate) void QuantumGateNode::setContent(QuantumGate* gate)
{ {
mContent = gate; mContent = gate;
mContentDirty = true; mContentDirty = true;
} }
void QuantumGateNode::update(SceneInfo* sceneInfo) void QuantumGateNode::update(SceneInfo* sceneInfo)
{ {
if (mContentDirty) if (mContentDirty)
{ {
createOrUpdateGeometry(sceneInfo); createOrUpdateGeometry(sceneInfo);
mContentDirty = false; mContentDirty = false;
} }
} }
void QuantumGateNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void QuantumGateNode::createOrUpdateGeometry(SceneInfo*)
{ {
if (!mBody) if (!mBody)
{ {
mBody = std::make_unique<RectangleNode>(Point(0, 0), mBodyWidth, mBodyHeight); mBody = std::make_unique<RectangleNode>(Point(0, 0), mBodyWidth, mBodyHeight);
addChild(mBody.get()); addChild(mBody.get());
} }
if (!mLabel) if (!mLabel)
{ {
mLabel = std::make_unique<EquationNode>(Point(mBodyWidth /3.0, mBodyHeight / 3.0)); mLabel = std::make_unique<EquationNode>(Point(mBodyWidth /3.0, mBodyHeight / 3.0));
std::string label_content; std::string label_content;
if (mContent->getGateType() == QuantumGate::GateType::X) if (mContent->getGateType() == QuantumGate::GateType::X)
{ {
label_content = "X"; label_content = "X";
} }
else if (mContent->getGateType() == QuantumGate::GateType::Y) else if (mContent->getGateType() == QuantumGate::GateType::Y)
{ {
label_content = "Y"; label_content = "Y";
} }
else if (mContent->getGateType() == QuantumGate::GateType::Z) else if (mContent->getGateType() == QuantumGate::GateType::Z)
{ {
label_content = "Z"; label_content = "Z";
} }
else if (mContent->getGateType() == QuantumGate::GateType::H) else if (mContent->getGateType() == QuantumGate::GateType::H)
{ {
label_content = "H"; label_content = "H";
} }
else else
{ {
label_content = "U"; label_content = "U";
} }
mLabelExpression = std::make_unique<LatexMathExpression>(label_content); mLabelExpression = std::make_unique<LatexMathExpression>(label_content);
mLabel->setContent(mLabelExpression.get()); mLabel->setContent(mLabelExpression.get());
addChild(mLabel.get()); addChild(mLabel.get());
} }
} }
Point QuantumGateNode::getConnectionLocation(AbstractQuantumWire* wire) const Point QuantumGateNode::getConnectionLocation(AbstractQuantumWire* wire) const
{ {
bool is_input{ false }; bool is_input{ false };
std::size_t connection_id{ 0 }; //std::size_t connection_id{ 0 };
for (std::size_t idx = 0; idx < mContent->getNumInputs(); idx++) for (std::size_t idx = 0; idx < mContent->getNumInputs(); idx++)
{ {
if (mContent->getInput(idx) == wire) if (mContent->getInput(idx) == wire)
{ {
is_input = true; is_input = true;
connection_id = idx; //connection_id = idx;
break; break;
} }
} }
for (std::size_t idx = 0; idx < mContent->getNumOutputs(); idx++) for (std::size_t idx = 0; idx < mContent->getNumOutputs(); idx++)
{ {
if (mContent->getOutput(idx) == wire) if (mContent->getOutput(idx) == wire)
{ {
connection_id = idx; //connection_id = idx;
break; break;
} }
} }
Point loc; Point loc;
if (is_input) if (is_input)
{ {
loc = Point(0.0, mBodyHeight/2.0); loc = Point(0.0, mBodyHeight/2.0);
} }
else else
{ {
loc = Point(mBodyWidth, mBodyHeight / 2.0); loc = Point(mBodyWidth, mBodyHeight / 2.0);
} }
loc.move(mTransform.getLocation().getX(), mTransform.getLocation().getY()); loc.move(mTransform.getLocation().getX(), mTransform.getLocation().getY());
return loc; return loc;
} }

View file

@ -5,56 +5,56 @@
#include "LatexMathExpression.h" #include "LatexMathExpression.h"
QuantumTerminalNode::QuantumTerminalNode(const Transform& transform) QuantumTerminalNode::QuantumTerminalNode(const Transform& transform)
: QuantumCircuitElementNode(transform) : QuantumCircuitElementNode(transform)
{ {
} }
void QuantumTerminalNode::setContent(QuantumTerminal* terminal) void QuantumTerminalNode::setContent(QuantumTerminal* terminal)
{ {
mContent = terminal; mContent = terminal;
mContentDirty = true; mContentDirty = true;
} }
void QuantumTerminalNode::update(SceneInfo* sceneInfo) void QuantumTerminalNode::update(SceneInfo* sceneInfo)
{ {
if (mContentDirty) if (mContentDirty)
{ {
createOrUpdateGeometry(sceneInfo); createOrUpdateGeometry(sceneInfo);
mContentDirty = false; mContentDirty = false;
} }
} }
void QuantumTerminalNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void QuantumTerminalNode::createOrUpdateGeometry(SceneInfo*)
{ {
if (!mLabel && mContent->getTerminalType() != QuantumTerminal::TerminalType::OUTPUT) if (!mLabel && mContent->getTerminalType() != QuantumTerminal::TerminalType::OUTPUT)
{ {
const auto value = mContent->getValue(); const auto value = mContent->getValue();
std::string label; std::string label;
if (value.isIn0State()) if (value.isIn0State())
{ {
label = "\\ket{0}"; label = "\\ket{0}";
} }
else if(value.isIn1State()) else if(value.isIn1State())
{ {
label = "\\ket{1}"; label = "\\ket{1}";
} }
else else
{ {
label = "\\Psi"; label = "\\Psi";
} }
mLabelExpression = std::make_unique<LatexMathExpression>(label); mLabelExpression = std::make_unique<LatexMathExpression>(label);
mLabel = std::make_unique<EquationNode>(); mLabel = std::make_unique<EquationNode>();
mLabel->setContent(mLabelExpression.get()); mLabel->setContent(mLabelExpression.get());
addChild(mLabel.get()); addChild(mLabel.get());
} }
} }
Point QuantumTerminalNode::getConnectionLocation(AbstractQuantumWire*) const Point QuantumTerminalNode::getConnectionLocation(AbstractQuantumWire*) const
{ {
auto left = mTransform.getLocation(); auto left = mTransform.getLocation();
left.move(mWidth, mHeight/2.0); left.move(mWidth, mHeight/2.0);
return left; return left;
} }

View file

@ -4,6 +4,7 @@
#include "LineNode.h" #include "LineNode.h"
QuantumWireNode::QuantumWireNode(const Transform& t) QuantumWireNode::QuantumWireNode(const Transform& t)
: AbstractVisualNode(t)
{ {
} }
@ -46,7 +47,7 @@ void QuantumWireNode::update(SceneInfo* sceneInfo)
} }
} }
void QuantumWireNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void QuantumWireNode::createOrUpdateGeometry(SceneInfo*)
{ {
if (!mLine) if (!mLine)
{ {

View file

@ -6,6 +6,12 @@
#include "QuantumCircuitNode.h" #include "QuantumCircuitNode.h"
#include "QuantumCircuit.h" #include "QuantumCircuit.h"
#include "QuantumWireNode.h"
#include "QuantumGateNode.h"
#include "QuantumTerminalNode.h"
#include "EquationNode.h"
#include "LatexMathExpression.h"
TEST_CASE(TestQuantumCircuitParsing, "quantum_computing") TEST_CASE(TestQuantumCircuitParsing, "quantum_computing")
{ {

View file

@ -3,6 +3,8 @@ set(MODULE_NAME geometry)
list(APPEND HEADERS list(APPEND HEADERS
AbstractGeometricItem.h AbstractGeometricItem.h
Bounds.h Bounds.h
Transform.h
Rotation.h
grid/AbstractGrid.h grid/AbstractGrid.h
grid/TypedGrid.h grid/TypedGrid.h
grid/Grid.h grid/Grid.h
@ -30,6 +32,7 @@ list(APPEND HEADERS
) )
list(APPEND SOURCES list(APPEND SOURCES
Rotation.cpp
Transform.cpp Transform.cpp
grid/AbstractGrid.cpp grid/AbstractGrid.cpp
math/Linalg.cpp math/Linalg.cpp

View file

@ -0,0 +1,31 @@
#include "Rotation.h"
Rotation::Rotation(double angle, Axis axis, const Point& loc, const Vector& customAxis)
: mAngle(angle),
mAxis(axis),
mPoint(loc),
mCustomAxis(customAxis),
mMatrix(3, 3)
{
updateMatrix();
}
const Matrix& Rotation::getMatrix() const
{
return mMatrix;
}
bool Rotation::isIdentity() const
{
return mMatrix.isIdentity();
}
bool Rotation::isEqual(const Rotation& rotation) const
{
return mMatrix == rotation.mMatrix;
}
void Rotation::updateMatrix()
{
}

View file

@ -0,0 +1,45 @@
#pragma once
#include "Point.h"
#include "Vector.h"
#include "Matrix.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 = {});
const Matrix& getMatrix() const;
bool isIdentity() const;
bool isEqual(const Rotation& rotation) const;
bool operator==(const Rotation& rhs) const
{
return isEqual(rhs);
}
bool operator!=(const Rotation& rhs) const
{
return !operator==(rhs);
}
private:
void updateMatrix();
double mAngle{ 0 };
Axis mAxis{ Axis::Z };
Point mPoint;
Vector mCustomAxis;
Matrix mMatrix;
};

View file

@ -1,43 +1,92 @@
#include "Transform.h" #include "Transform.h"
Transform::Transform(const Point& location, double scaleX, double scaleY, double scaleZ) Scale::Scale(double x, double y, double z)
: mLocation(location), : mX(x),
mScaleX(scaleX), mY(y),
mScaleY(scaleY), mZ(z)
mScaleZ(scaleZ)
{ {
} }
bool Scale::isIdentity() const
{
return mX == 1.0 && mY == 1.0 && mZ == 1.0;
}
bool Scale::isEqual(const Scale& scale) const
{
return mX == scale.mX && mY == scale.mY && mZ == scale.mZ;
}
Transform::Transform(const Point& location, const Scale& scale, const Rotation& rotation)
: mLocation(location),
mScale(scale),
mRotation(rotation),
mMatrix(4, 4)
{
}
void Transform::applyPre(const Transform& transform)
{
mLocation.move(transform.getLocation().getX(), transform.getLocation().getY(), transform.getLocation().getZ());
mScale *= transform.getScale();
}
const Point& Transform::getLocation() const const Point& Transform::getLocation() const
{ {
return mLocation; return mLocation;
} }
double Transform::getScaleX() const const Scale& Transform::getScale() const
{ {
return mScaleX; return mScale;
} }
double Transform::getScaleY() const const Rotation& Transform::getRotation() const
{ {
return mScaleY; return mRotation;
} }
double Transform::getScaleZ() const bool Transform::isEqual(const Transform& transform) const
{ {
return mScaleZ; return (mLocation == transform.mLocation) && (mScale == transform.mScale) && (mRotation == transform.mRotation);
}
bool Transform::isIdentityTransform() const
{
return mLocation.isAtOrigin() && mScale.isIdentity();
} }
void Transform::setLocation(const Point& loc) void Transform::setLocation(const Point& loc)
{ {
mLocation = loc; if (mLocation != loc)
{
mLocation = loc;
updateMatrix();
}
} }
void Transform::setScale(double scaleX, double scaleY, double scaleZ) void Transform::setScale(const Scale& scale)
{
if (mScale != scale)
{
mScale = scale;
updateMatrix();
}
}
void Transform::setRotation(const Rotation& rotation)
{
if (mRotation != rotation)
{
mRotation = rotation;
updateMatrix();
}
}
void Transform::updateMatrix()
{ {
mScaleX = scaleX;
mScaleY = scaleY;
mScaleZ = scaleZ;
} }

View file

@ -1,68 +1,65 @@
#pragma once #pragma once
#include "Point.h" #include "Rotation.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 struct Scale
{ {
Scale(double x = 1.0, double y = 1.0, double z = 1.0);
bool isIdentity() const;
bool isEqual(const Scale& scale) const;
void operator*=(const Scale& rhs)
{
mX *= rhs.mX;
mY *= rhs.mY;
mZ *= rhs.mZ;
}
bool operator==(const Scale& rhs) const
{
return isEqual(rhs);
}
bool operator!=(const Scale& rhs) const
{
return !operator==(rhs);
}
double mX{1.0};
double mY{1.0};
double mZ{1.0};
}; };
class Transform class Transform
{ {
public: public:
Transform(const Point& location = {}, double scaleX = 1.0, double scaleY = 1.0, double scaleZ = 1.0); Transform(const Point& location = {}, const Scale& scale = {}, const Rotation& rotation = {});
void applyPre(const Transform& transform) void applyPre(const Transform& transform);
{
mLocation.move(transform.getLocation().getX(), transform.getLocation().getY(), transform.getLocation().getZ());
mScaleX *= transform.getScaleX();
mScaleY *= transform.getScaleY();
mScaleZ *= transform.getScaleZ();
}
void setLocation(const Point& loc);
void setScale(double scaleX, double scaleY = 1.0, double scaleZ = 1.0);
const Point& getLocation() const; const Point& getLocation() const;
double getScaleX() const; const Scale& getScale() const;
double getScaleY() const; const Rotation& getRotation() const;
double getScaleZ() const; const Matrix& getMatrix() const;
bool isEqual(const Transform& transform) const;
bool isIdentityTransform() const;
void setLocation(const Point& loc);
void setScale(const Scale& scale);
void setRotation(const Rotation& rotation);
bool operator==(const Transform& rhs) const bool operator==(const Transform& rhs) const
{ {
return (mLocation == rhs.mLocation) return isEqual(rhs);
&& (mScaleX == rhs.mScaleX)
&& (mScaleY == rhs.mScaleY)
&& (mScaleZ == rhs.mScaleZ);
} }
bool operator!=(const Transform& rhs) const bool operator!=(const Transform& rhs) const
@ -70,24 +67,11 @@ public:
return !operator==(rhs); return !operator==(rhs);
} }
bool hasDefaultLocation() const
{
return mLocation.getX() == 0.0 && mLocation.getY() == 0.0 && mLocation.getZ() == 0.0;
}
bool hasDefaultScale() const
{
return mScaleX == 1.0 && mScaleY == 1.0 && mScaleZ == 1.0;
}
bool isDefaultTransform() const
{
return hasDefaultLocation() && hasDefaultScale();
}
private: private:
void updateMatrix();
Point mLocation; Point mLocation;
double mScaleX{1}; Scale mScale;
double mScaleY{1}; Rotation mRotation;
double mScaleZ{1}; Matrix mMatrix;
}; };

View file

@ -0,0 +1,66 @@
#include "Matrix.h"
#include <string>
#include <stdexcept>
Matrix::Matrix(std::size_t numRows, std::size_t numColumns)
: mNumRows(numRows),
mNumColumns(numColumns)
{
mData = std::vector<double>(numRows * numColumns, 0.0);
}
bool Matrix::isIdentity() const
{
if (!isSquare())
{
return false;
}
for(std::size_t idx=0; idx<mNumRows; idx++)
{
for(std::size_t jdx=0; jdx<mNumColumns; jdx++)
{
if (idx == jdx)
{
if (getItem(idx, jdx) != 1.0)
{
return false;
}
}
else
{
if (getItem(idx, jdx) != 0.0)
{
return false;
}
}
}
}
return true;
}
double Matrix::getItem(std::size_t rowId, std::size_t columnId) const
{
const auto index = getFlatIndex(rowId, columnId);
if (index >= mData.size())
{
throw std::range_error("Out of bounds array access: " + std::to_string(index) + " for size " + std::to_string(mData.size()));
}
return mData[getFlatIndex(rowId, columnId)];
}
bool Matrix::isSquare() const
{
return mNumRows == mNumColumns;
}
bool Matrix::isEqual(const Matrix& matrix) const
{
return mData == matrix.mData;
}
std::size_t Matrix::getFlatIndex(std::size_t rowId, std::size_t columnId) const
{
return columnId + rowId*mNumColumns;
}

View file

@ -5,10 +5,30 @@
class Matrix class Matrix
{ {
public: public:
Matrix(unsigned numRows, unsigned numColumns) Matrix(std::size_t numRows, std::size_t numColumns);
{
mData = std::vector<double>(numRows * numColumns, 0.0); std::size_t getFlatIndex(std::size_t rowId, std::size_t columnId) const;
}
double getItem(std::size_t rowId, std::size_t columnId) const;
bool isIdentity() const;
bool isSquare() const;
bool isEqual(const Matrix& matrix) const;
bool operator==(const Matrix& rhs) const
{
return isEqual(rhs);
}
bool operator!=(const Matrix& rhs) const
{
return !operator==(rhs);
}
private: private:
std::vector<double> mData; std::size_t mNumRows{0};
std::size_t mNumColumns{0};
std::vector<double> mData;
}; };

View file

@ -79,15 +79,20 @@ double Point::getDeltaZ(const Point& point) const
return point.getZ() - mZ; return point.getZ() - mZ;
} }
bool Point::isAtOrigin() const
{
return mX == 0.0 && mY == 0.0 && mZ == 0.0;
}
void Point::apply(const Transform& transform) void Point::apply(const Transform& transform)
{ {
mX -= transform.getLocation().getX(); mX -= transform.getLocation().getX();
mY -= transform.getLocation().getY(); mY -= transform.getLocation().getY();
mZ -= transform.getLocation().getZ(); mZ -= transform.getLocation().getZ();
mX *= transform.getScaleX(); mX *= transform.getScale().mX;
mY *= transform.getScaleY(); mY *= transform.getScale().mY;
mZ *= transform.getScaleZ(); mZ *= transform.getScale().mZ;
} }
void Point::move(double x, double y, double z) void Point::move(double x, double y, double z)

View file

@ -22,6 +22,8 @@ public:
void apply(const Transform& transform); void apply(const Transform& transform);
bool isAtOrigin() const;
void move(double x, double y, double z = 0); void move(double x, double y, double z = 0);
double getX() const; double getX() const;

View file

@ -7,10 +7,8 @@ if(UNIX)
list(APPEND platform_INCLUDES list(APPEND platform_INCLUDES
sockets/BerkeleySocket.h sockets/BerkeleySocket.h
sockets/BerkeleySocket.cpp sockets/BerkeleySocket.cpp
sockets/UnixSocketInterface.h server/UnixSocketServer.h
sockets/UnixSocketInterface.cpp server/UnixSocketServer.cpp
server/UnixSockerServer.h
server/UnixSockerServer.cpp
client/unix/UnixSocketClient.h client/unix/UnixSocketClient.h
client/unix/UnixSocketClient.cpp client/unix/UnixSocketClient.cpp
) )
@ -45,7 +43,6 @@ list(APPEND HEADERS
server/HttpServer.h server/HttpServer.h
server/PlatformSocketServer.h server/PlatformSocketServer.h
sockets/Socket.h sockets/Socket.h
sockets/SocketInterface.h
sockets/IPlatformSocket.h sockets/IPlatformSocket.h
) )

View file

@ -11,38 +11,38 @@
HttpClient::HttpClient() HttpClient::HttpClient()
{ {
#ifdef _WIN32 #ifdef _WIN32
mSocketClient = std::make_unique<WinsockClient>(); mSocketClient = std::make_unique<WinsockClient>();
#else #else
mSocketClient = std::make_unique<UnixSocketClient>(); mSocketClient = std::make_unique<UnixSocketClient>();
#endif #endif
} }
HttpResponse HttpClient::makeRequest(const HttpRequest& request, const Address& address) HttpResponse HttpClient::makeRequest(const HttpRequest& request, const Address& address)
{ {
PlatformSocketClient::Address socket_address; PlatformSocketClient::Address socket_address;
socket_address.mHost = address.mHost; socket_address.mHost = address.mHost;
socket_address.mPort = address.mPort; socket_address.mPort = address.mPort;
socket_address.mPrefix = address.mPrefix; socket_address.mPrefix = address.mPrefix;
const auto message = request.toString(address.mHost); const auto message = request.toString(address.mHost);
MLOG_INFO("Output http request: " << message); MLOG_INFO("Output http request: " << message);
auto socket_response = mSocketClient->request(socket_address, message); auto socket_response = mSocketClient->request(socket_address, message);
HttpResponse response; HttpResponse response;
if (socket_response.mStatus == PlatformSocketClient::Result::Status::OK) if (socket_response.mStatus == PlatformSocketClient::Result::Status::OK)
{ {
response.fromMessage(socket_response.mBody); response.fromMessage(socket_response.mBody);
} }
else else
{ {
MLOG_ERROR("Http request client error: " << socket_response.mErrorMessage << " | with code: " << socket_response.mErrorCode); MLOG_ERROR("Http request client error: " << socket_response.mErrorMessage << " | with code: " << socket_response.mErrorCode);
HttpResponse::ClientError error; HttpResponse::ClientError error;
error.mMessage = socket_response.mErrorMessage; error.mMessage = socket_response.mErrorMessage;
error.mCode = socket_response.mErrorCode; error.mCode = socket_response.mErrorCode;
response.setClientError(error); response.setClientError(error);
} }
return response; return response;
} }

View file

@ -9,16 +9,16 @@
class HttpClient class HttpClient
{ {
public: public:
struct Address struct Address
{ {
std::string mPrefix; std::string mPrefix;
std::string mHost; std::string mHost;
unsigned int mPort{ 8000 }; unsigned int mPort{ 8000 };
}; };
HttpClient(); HttpClient();
HttpResponse makeRequest(const HttpRequest& request, const Address& address); HttpResponse makeRequest(const HttpRequest& request, const Address& address);
private: private:
std::unique_ptr<PlatformSocketClient> mSocketClient; std::unique_ptr<PlatformSocketClient> mSocketClient;
}; };

View file

@ -0,0 +1,32 @@
#include "UnixSocketClient.h"
UnixSocketClient::UnixSocketClient()
{
}
UnixSocketClient::~UnixSocketClient()
{
}
UnixSocketClient::Result UnixSocketClient::request(const Address& address, const std::string& message)
{
UnixSocketClient::Result result;
auto socket = std::make_unique<BerkeleySocket>(address.mHost, address.mPort);
auto response = socket->send(message);
if (socket->getState().mConnectStatus != Socket::State::ConnectStatus::FAILED)
{
result.mStatus = UnixSocketClient::Result::Status::OK;
result.mBody = response;
}
else
{
result.mStatus = UnixSocketClient::Result::Status::FAILED;
result.mErrorCode = socket->getState().mErrorCode;
result.mErrorMessage = socket->getState().mErrorMessage;
}
return result;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "BerkeleySocket.h"
#include "PlatformSocketClient.h"
#include <vector>
class UnixSocketClient : public PlatformSocketClient
{
public:
UnixSocketClient();
virtual ~UnixSocketClient();
Result request(const Address& address, const std::string& message);
};

View file

@ -1,28 +1,28 @@
#include "WinsockClient.h" #include "WinsockClient.h"
WinsockClient::WinsockClient() WinsockClient::WinsockClient()
: mSocketInterface(std::make_unique<WinsockInterface>()) : mSocketInterface(std::make_unique<WinsockInterface>())
{ {
mSocketInterface->initializeWinsock(); mSocketInterface->initializeWinsock();
} }
WinsockClient::Result WinsockClient::request(const Address& address, const std::string& message) WinsockClient::Result WinsockClient::request(const Address& address, const std::string& message)
{ {
WinsockClient::Result result; WinsockClient::Result result;
auto socket = std::make_unique<WinsockSocket>(address.mHost, address.mPort); auto socket = std::make_unique<WinsockSocket>(address.mHost, address.mPort);
auto response = socket->send(message); auto response = socket->send(message);
if (socket->getState().mConnectStatus != Socket::State::ConnectStatus::FAILED) if (socket->getState().mConnectStatus != Socket::State::ConnectStatus::FAILED)
{ {
result.mStatus = WinsockClient::Result::Status::OK; result.mStatus = WinsockClient::Result::Status::OK;
result.mBody = response; result.mBody = response;
} }
else else
{ {
result.mStatus = WinsockClient::Result::Status::FAILED; result.mStatus = WinsockClient::Result::Status::FAILED;
result.mErrorCode = socket->getState().mErrorCode; result.mErrorCode = socket->getState().mErrorCode;
result.mErrorMessage = socket->getState().mErrorMessage; result.mErrorMessage = socket->getState().mErrorMessage;
} }
return result; return result;
} }

View file

@ -10,10 +10,10 @@
class WinsockClient : public PlatformSocketClient class WinsockClient : public PlatformSocketClient
{ {
public: public:
WinsockClient(); WinsockClient();
Result request(const Address& address, const std::string& message); Result request(const Address& address, const std::string& message);
private: private:
std::unique_ptr<WinsockInterface> mSocketInterface; std::unique_ptr<WinsockInterface> mSocketInterface;
}; };

View file

@ -0,0 +1,70 @@
#include "UnixSocketServer.h"
#include "BerkeleySocket.h"
#include "FileLogger.h"
#include <thread>
UnixSocketServer::~UnixSocketServer()
{
}
void UnixSocketServer::listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc)
{
mConnectionCallback = connectionSuccessFunc;
mFailedCallback = connectionFailedFunc;
auto server_socket = std::make_unique<BerkeleySocket>(address.mHost, address.mPort);
auto on_connection = [this](int handle)
{
auto socket = std::make_unique<BerkeleySocket>(handle);
this->onConnection(std::move(socket));
};
server_socket->doListen(on_connection);
if (server_socket->getState().mBindStatus == Socket::State::BindStatus::FAILED)
{
UnixSocketServer::Result result;
result.mStatus = UnixSocketServer::Result::Status::FAILED;
result.mErrorCode = server_socket->getState().mErrorCode;
result.mErrorMessage = server_socket->getState().mErrorMessage;
mFailedCallback(result);
}
}
void UnixSocketServer::shutDown()
{
mThreads.removeMarked();
mThreads.joinAndClearAll();
}
void UnixSocketServer::onConnection(std::unique_ptr<BerkeleySocket> s)
{
// House-keeping first - clean up any finished threads
MLOG_INFO("Before thread cleanup: " << mThreads.size());
mThreads.removeMarked();
MLOG_INFO("After thread cleanup: " << mThreads.size());
auto worker_func = [this](std::unique_ptr<BerkeleySocket> s)
{
MLOG_INFO("Spawned thread for new connection");
mConnectionCallback(s.get());
MLOG_INFO("Finished thread for new connection");
this->onThreadComplete(std::this_thread::get_id());
};
auto worker = std::make_unique<std::thread>(worker_func, std::move(s));
mThreads.add(std::move(worker));
};
void UnixSocketServer::onThreadComplete(std::thread::id id)
{
mThreads.markForRemoval(id);
}

View file

@ -0,0 +1,27 @@
#pragma once
#include "PlatformSocketServer.h"
#include "ThreadCollection.h"
#include <memory>
class BerkeleySocket;
class UnixSocketServer : public PlatformSocketServer
{
public:
virtual ~UnixSocketServer();
void listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc) override;
void shutDown() override;
private:
void onConnection(std::unique_ptr<BerkeleySocket> clientHandle);
void onThreadComplete(std::thread::id id);
ThreadCollection mThreads;
onConnectionSuccessFunc mConnectionCallback;
onConnectionFailedFunc mFailedCallback;
};

View file

@ -14,64 +14,64 @@ WinsockServer::~WinsockServer()
void WinsockServer::listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc) void WinsockServer::listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc)
{ {
if (!mWinsockInterface) if (!mWinsockInterface)
{ {
mWinsockInterface = std::make_unique<WinsockInterface>(); mWinsockInterface = std::make_unique<WinsockInterface>();
mWinsockInterface->initializeWinsock(); mWinsockInterface->initializeWinsock();
} }
mConnectionCallback = connectionSuccessFunc; mConnectionCallback = connectionSuccessFunc;
mFailedCallback = connectionFailedFunc; mFailedCallback = connectionFailedFunc;
auto server_socket = std::make_unique<WinsockSocket>(address.mHost, address.mPort); auto server_socket = std::make_unique<WinsockSocket>(address.mHost, address.mPort);
auto on_connection = [this](SOCKET handle) auto on_connection = [this](SOCKET handle)
{ {
auto socket = std::make_unique<WinsockSocket>(handle); auto socket = std::make_unique<WinsockSocket>(handle);
this->onConnection(std::move(socket)); this->onConnection(std::move(socket));
}; };
server_socket->doListen(on_connection); server_socket->doListen(on_connection);
if (server_socket->getState().mBindStatus == Socket::State::BindStatus::FAILED) if (server_socket->getState().mBindStatus == Socket::State::BindStatus::FAILED)
{ {
WinsockServer::Result result; WinsockServer::Result result;
result.mStatus = WinsockServer::Result::Status::FAILED; result.mStatus = WinsockServer::Result::Status::FAILED;
result.mErrorCode = server_socket->getState().mErrorCode; result.mErrorCode = server_socket->getState().mErrorCode;
result.mErrorMessage = server_socket->getState().mErrorMessage; result.mErrorMessage = server_socket->getState().mErrorMessage;
mFailedCallback(result); mFailedCallback(result);
} }
} }
void WinsockServer::shutDown() void WinsockServer::shutDown()
{ {
mThreads.removeMarked(); mThreads.removeMarked();
mThreads.joinAndClearAll(); mThreads.joinAndClearAll();
} }
void WinsockServer::onConnection(std::unique_ptr<WinsockSocket> s) void WinsockServer::onConnection(std::unique_ptr<WinsockSocket> s)
{ {
// House-keeping first - clean up any finished threads // House-keeping first - clean up any finished threads
MLOG_INFO("Before thread cleanup: " << mThreads.size()); MLOG_INFO("Before thread cleanup: " << mThreads.size());
mThreads.removeMarked(); mThreads.removeMarked();
MLOG_INFO("After thread cleanup: " << mThreads.size()); MLOG_INFO("After thread cleanup: " << mThreads.size());
auto worker_func = [this](std::unique_ptr<WinsockSocket> s) auto worker_func = [this](std::unique_ptr<WinsockSocket> s)
{ {
MLOG_INFO("Spawned thread for new connection"); MLOG_INFO("Spawned thread for new connection");
mConnectionCallback(s.get()); mConnectionCallback(s.get());
MLOG_INFO("Finished thread for new connection"); MLOG_INFO("Finished thread for new connection");
this->onThreadComplete(std::this_thread::get_id()); this->onThreadComplete(std::this_thread::get_id());
}; };
auto worker = std::make_unique<std::thread>(worker_func, std::move(s)); auto worker = std::make_unique<std::thread>(worker_func, std::move(s));
mThreads.add(std::move(worker)); mThreads.add(std::move(worker));
}; };
void WinsockServer::onThreadComplete(std::thread::id id) void WinsockServer::onThreadComplete(std::thread::id id)
{ {
mThreads.markForRemoval(id); mThreads.markForRemoval(id);
} }

View file

@ -12,20 +12,20 @@ class WinsockInterface;
class WinsockServer : public PlatformSocketServer class WinsockServer : public PlatformSocketServer
{ {
public: public:
virtual ~WinsockServer(); virtual ~WinsockServer();
void listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc) override; void listen(const Address& address, onConnectionSuccessFunc connectionSuccessFunc, onConnectionFailedFunc connectionFailedFunc) override;
void shutDown() override; void shutDown() override;
private: private:
void onConnection(std::unique_ptr<WinsockSocket> clientHandle); void onConnection(std::unique_ptr<WinsockSocket> clientHandle);
void onThreadComplete(std::thread::id id); void onThreadComplete(std::thread::id id);
ThreadCollection mThreads; ThreadCollection mThreads;
onConnectionSuccessFunc mConnectionCallback; onConnectionSuccessFunc mConnectionCallback;
onConnectionFailedFunc mFailedCallback; onConnectionFailedFunc mFailedCallback;
std::unique_ptr<WinsockInterface> mWinsockInterface; std::unique_ptr<WinsockInterface> mWinsockInterface;
}; };

View file

@ -0,0 +1,184 @@
#include "BerkeleySocket.h"
#include "FileLogger.h"
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
BerkeleySocket::BerkeleySocket(const std::string& address, unsigned port)
: Socket(address, port)
{
}
BerkeleySocket::BerkeleySocket(int handle)
: Socket("", 0),
mHandle(handle)
{
mState.mConnectStatus = State::ConnectStatus::OK;
}
BerkeleySocket::~BerkeleySocket()
{
MLOG_INFO("Socket being destroyed");
}
void BerkeleySocket::initialize()
{
mHandle = ::socket(AF_INET, SOCK_STREAM, 0);
}
void BerkeleySocket::initializeForBind()
{
}
void BerkeleySocket::doConnect()
{
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
::inet_aton(mAddress.c_str(), &serv_addr.sin_addr);
serv_addr.sin_port = ::htons(mPort);
int result = ::connect(mHandle, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if( result < 0)
{
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
mState.mErrorCode = result;
mState.mErrorMessage = "Socket: Unable to connect to server.";
return;
}
mState.mConnectStatus = Socket::State::ConnectStatus::OK;
}
void BerkeleySocket::doBind()
{
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(mPort);
int result = ::bind(mHandle, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (result< 0)
{
mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = result;
mState.mErrorMessage = "Socket: Unable to bind socket";
return;
}
mState.mBindStatus = Socket::State::BindStatus::OK;
}
void BerkeleySocket::doListen(onIncomingConnectionFunc connectionFunc)
{
initializeForBind();
if (mState.mBindStatus == Socket::State::BindStatus::FAILED)
{
return;
}
doBind();
if (mState.mBindStatus == Socket::State::BindStatus::FAILED)
{
return;
}
::listen(mHandle, 5);
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
while(true)
{
const auto new_socket_handle = ::accept(mHandle, (struct sockaddr *) &cli_addr, &clilen);
if (new_socket_handle < 0)
{
mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = new_socket_handle;
mState.mErrorMessage = "Socket: Accept failed";
::close(mHandle);
return;
}
connectionFunc(new_socket_handle);
}
}
std::string BerkeleySocket::send(const std::string& message)
{
if (mState.mConnectStatus != Socket::State::ConnectStatus::OK)
{
initialize();
if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED)
{
return {};
}
doConnect();
if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED)
{
return {};
}
}
auto n = ::write(mHandle, message.c_str(), message.length());
if (n < 0)
{
onSockerError("Socket: Send failed.");
return{};
}
std::string response;
while (mState.mConnectStatus == Socket::State::ConnectStatus::OK)
{
response += recieve();
}
::close(mHandle);
return response;
}
void BerkeleySocket::respond(const std::string& message)
{
auto result = ::write(mHandle, message.c_str(), static_cast<int>(message.size()));
(void)result;
}
void BerkeleySocket::onSockerError(const std::string& message)
{
mState.mErrorCode = -1;
mState.mErrorMessage = message;
if (mState.mConnectStatus == Socket::State::ConnectStatus::OK)
{
::close(mHandle);
}
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
}
std::string BerkeleySocket::recieve()
{
const int BUFFER_SIZE = 512;
char buffer[BUFFER_SIZE];
auto result = ::read(mHandle, buffer, BUFFER_SIZE);
if (result > 0)
{
return std::string(buffer);
}
else if (result == 0)
{
mState.mConnectStatus = Socket::State::ConnectStatus::UNSET;
}
else
{
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
mState.mErrorCode = result;
mState.mErrorMessage = "Socket: read failed.";
}
return {};
}

View file

@ -0,0 +1,37 @@
#pragma once
#include "Socket.h"
#include <string>
#include <functional>
class BerkeleySocket : public Socket
{
public:
BerkeleySocket(const std::string& address, unsigned port);
BerkeleySocket(int handle);
~BerkeleySocket();
std::string recieve() override;
void respond(const std::string& message) override;
std::string send(const std::string& message) override;
using onIncomingConnectionFunc = std::function<void(int)>;
void doListen(onIncomingConnectionFunc connectionFunc);
private:
void initialize() override;
void initializeForBind() override;
void doConnect() override;
void doBind() override;
void onSockerError(const std::string& message);
int mHandle{ 0 };
};

View file

@ -1,17 +0,0 @@
#pragma once
#include <memory>
#include <string>
class Socket;
using SocketPtr = std::unique_ptr<Socket>;
class ISocketInterface
{
public:
ISocketInterface() = default;
virtual ~ISocketInterface() = default;
};
using ISocketInterfaceUPtr = std::unique_ptr<ISocketInterface>;

View file

@ -1,146 +0,0 @@
#include "UnixSocketInterface.h"
#include "HttpResponse.h"
#include "HttpMessageHandler.h"
#include "FileLogger.h"
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
UnixSocketInterface::UnixSocketInterface()
{
mMessageHandler = std::make_unique<HttpMessageHandler>();
}
std::unique_ptr<UnixSocketInterface> UnixSocketInterface::Create()
{
return std::make_unique<UnixSocketInterface>();
}
UnixSocketInterface::~UnixSocketInterface()
{
}
void UnixSocketInterface::initializeSocket(const SocketPtr& socketPtr, const std::string& address)
{
auto handle = ::socket(AF_INET, SOCK_STREAM, 0);
socketPtr->setHandle(handle);
if (!address.empty())
{
socketPtr->setAddress(address);
}
}
void UnixSocketInterface::socketWrite(const SocketPtr& socket, const std::string& message)
{
if(socket->getHandle() < 0)
{
MLOG_ERROR("Error opening socket" );
return;
}
const auto port = static_cast<int>(socket->getPort());
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
inet_aton(socket->getAddress().c_str(), &serv_addr.sin_addr);
serv_addr.sin_port = htons(port);
int result = connect(socket->getHandle(), (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(result< 0)
{
MLOG_ERROR("Error connecting to socket" );
return;
}
auto n = write(socket->getHandle(), message.c_str(), message.length());
if (n < 0)
{
std::cerr << "Error on write" << std::endl;
return;
}
char buffer[BUFFER_SIZE] = {0};
int res = read(socket->getHandle(), buffer, BUFFER_SIZE);
if (res < 0)
{
std::cerr << "Error on read" << std::endl;
return;
}
socket->setMessage(buffer);
std::cout << "Here is the message: " << buffer << std::endl;
}
void UnixSocketInterface::socketListen(const SocketPtr& socket)
{
if(socket->getHandle() < 0)
{
std::cerr << "Error opening socket" << std::endl;
return;
}
const auto port = static_cast<int>(socket->getPort());
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
int result = bind(socket->getHandle(), (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(result< 0)
{
std::cerr << "Error binding socket" << std::endl;
return;
}
listen(socket->getHandle(), 5);
}
void UnixSocketInterface::run(const SocketPtr& socket)
{
if(socket->getHandle() < 0)
{
std::cerr << "Error opening socket" << std::endl;
return;
}
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
while(true)
{
const auto new_socket_handle = accept(socket->getHandle(), (struct sockaddr *) &cli_addr, &clilen);
if (new_socket_handle < 0)
{
std::cerr << "Error on accept" << std::endl;
return;
}
char buffer[BUFFER_SIZE] = {0};
int n = read(new_socket_handle, buffer, BUFFER_SIZE);
if (n < 0)
{
std::cerr << "Error on read" << std::endl;
return;
}
socket->setMessage(buffer);
std::cout << "Here is the message: " << buffer << std::endl;
const auto response = mMessageHandler->onMessage(buffer);
n = write(new_socket_handle, response.c_str(), response.length());
if (n < 0)
{
std::cerr << "Error on write" << std::endl;
return;
}
close(new_socket_handle);
}
}

View file

@ -1,33 +0,0 @@
#pragma once
#include "Socket.h"
#include "SocketInterface.h"
#include <memory>
#include <map>
class ISocketMessageHandler;
class UnixSocketInterface : public ISocketInterface
{
public:
UnixSocketInterface();
virtual ~UnixSocketInterface();
static std::unique_ptr<UnixSocketInterface> Create();
void initializeSocket(const SocketPtr& socket, const std::string& address = {}) override;
void socketListen(const SocketPtr& socket) override;
void socketWrite(const SocketPtr& socket, const std::string& message) override;
void run(const SocketPtr& socket) override;
private:
static constexpr unsigned BUFFER_SIZE{1024};
std::unique_ptr<ISocketMessageHandler> mMessageHandler;
};
using UnixSocketInterfacePtr = std::unique_ptr<UnixSocketInterface>;

View file

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "SocketInterface.h" class WinsockInterface
class WinsockInterface : public ISocketInterface
{ {
public: public:
~WinsockInterface(); ~WinsockInterface();

View file

@ -6,240 +6,240 @@
#include "FileLogger.h" #include "FileLogger.h"
WinsockSocket::WinsockSocket(const std::string& address, unsigned port) WinsockSocket::WinsockSocket(const std::string& address, unsigned port)
: Socket(address, port) : Socket(address, port)
{ {
} }
WinsockSocket::WinsockSocket(SOCKET handle) WinsockSocket::WinsockSocket(SOCKET handle)
: Socket("", 0), : Socket("", 0),
mHandle(handle) mHandle(handle)
{ {
mState.mConnectStatus = State::ConnectStatus::OK; mState.mConnectStatus = State::ConnectStatus::OK;
} }
WinsockSocket::~WinsockSocket() WinsockSocket::~WinsockSocket()
{ {
MLOG_INFO("Socket being destroyed"); MLOG_INFO("Socket being destroyed");
} }
void WinsockSocket::initialize() void WinsockSocket::initialize()
{ {
addrinfo hints; addrinfo hints;
ZeroMemory(&hints, sizeof(hints)); ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
auto result = ::getaddrinfo(mAddress.c_str(), std::to_string(mPort).c_str(), &hints, &mAddressInfo); auto result = ::getaddrinfo(mAddress.c_str(), std::to_string(mPort).c_str(), &hints, &mAddressInfo);
if (result != 0) if (result != 0)
{ {
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED; mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
mState.mErrorCode = result; mState.mErrorCode = result;
mState.mErrorMessage = "WinsockSocket: getaddrinfo failed for connect"; mState.mErrorMessage = "WinsockSocket: getaddrinfo failed for connect";
return; return;
} }
mHandle = ::socket(mAddressInfo->ai_family, mAddressInfo->ai_socktype, mAddressInfo->ai_protocol); mHandle = ::socket(mAddressInfo->ai_family, mAddressInfo->ai_socktype, mAddressInfo->ai_protocol);
if (mHandle == INVALID_SOCKET) if (mHandle == INVALID_SOCKET)
{ {
onSockerError("WinsockSocket: Error at socket()"); onSockerError("WinsockSocket: Error at socket()");
::freeaddrinfo(mAddressInfo); ::freeaddrinfo(mAddressInfo);
return; return;
} }
} }
void WinsockSocket::initializeForBind() void WinsockSocket::initializeForBind()
{ {
addrinfo hints; addrinfo hints;
ZeroMemory(&hints, sizeof(hints)); ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
// https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2 // https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
auto result = ::getaddrinfo(nullptr, std::to_string(mPort).c_str(), &hints, &mAddressInfo); auto result = ::getaddrinfo(nullptr, std::to_string(mPort).c_str(), &hints, &mAddressInfo);
if (result != 0) if (result != 0)
{ {
mState.mBindStatus = Socket::State::BindStatus::FAILED; mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = result; mState.mErrorCode = result;
mState.mErrorMessage = "WinsockSocket: getaddrinfo failed for bind"; mState.mErrorMessage = "WinsockSocket: getaddrinfo failed for bind";
return; return;
} }
mHandle = ::socket(mAddressInfo->ai_family, mAddressInfo->ai_socktype, mAddressInfo->ai_protocol); mHandle = ::socket(mAddressInfo->ai_family, mAddressInfo->ai_socktype, mAddressInfo->ai_protocol);
if (mHandle == INVALID_SOCKET) if (mHandle == INVALID_SOCKET)
{ {
onSockerError("WinsockSocket: Error at socket()"); onSockerError("WinsockSocket: Error at socket()");
::freeaddrinfo(mAddressInfo); ::freeaddrinfo(mAddressInfo);
return; return;
} }
} }
void WinsockSocket::doConnect() void WinsockSocket::doConnect()
{ {
auto result = ::connect(mHandle, mAddressInfo->ai_addr, (int)mAddressInfo->ai_addrlen); auto result = ::connect(mHandle, mAddressInfo->ai_addr, (int)mAddressInfo->ai_addrlen);
if (result == SOCKET_ERROR) if (result == SOCKET_ERROR)
{ {
::closesocket(mHandle); ::closesocket(mHandle);
mHandle = INVALID_SOCKET; mHandle = INVALID_SOCKET;
} }
::freeaddrinfo(mAddressInfo); ::freeaddrinfo(mAddressInfo);
if (mHandle == INVALID_SOCKET) if (mHandle == INVALID_SOCKET)
{ {
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED; mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
mState.mErrorCode = SOCKET_ERROR; mState.mErrorCode = SOCKET_ERROR;
mState.mErrorMessage = "WinsockSocket: Unable to connect to server."; mState.mErrorMessage = "WinsockSocket: Unable to connect to server.";
return; return;
} }
mState.mConnectStatus = Socket::State::ConnectStatus::OK; mState.mConnectStatus = Socket::State::ConnectStatus::OK;
} }
void WinsockSocket::doBind() void WinsockSocket::doBind()
{ {
auto result = ::bind(mHandle, mAddressInfo->ai_addr, (int)mAddressInfo->ai_addrlen); auto result = ::bind(mHandle, mAddressInfo->ai_addr, (int)mAddressInfo->ai_addrlen);
if (result == SOCKET_ERROR) if (result == SOCKET_ERROR)
{ {
::closesocket(mHandle); ::closesocket(mHandle);
mHandle = INVALID_SOCKET; mHandle = INVALID_SOCKET;
} }
::freeaddrinfo(mAddressInfo); ::freeaddrinfo(mAddressInfo);
if (mHandle == INVALID_SOCKET) if (mHandle == INVALID_SOCKET)
{ {
mState.mBindStatus = Socket::State::BindStatus::FAILED; mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = ::WSAGetLastError(); mState.mErrorCode = ::WSAGetLastError();
mState.mErrorMessage = "WinsockSocket: Unable to bind socket"; mState.mErrorMessage = "WinsockSocket: Unable to bind socket";
return; return;
} }
mState.mBindStatus = Socket::State::BindStatus::OK; mState.mBindStatus = Socket::State::BindStatus::OK;
} }
void WinsockSocket::doListen(onIncomingConnectionFunc connectionFunc) void WinsockSocket::doListen(onIncomingConnectionFunc connectionFunc)
{ {
initializeForBind(); initializeForBind();
if (mState.mBindStatus == Socket::State::BindStatus::FAILED) if (mState.mBindStatus == Socket::State::BindStatus::FAILED)
{ {
return; return;
} }
doBind(); doBind();
if (mState.mBindStatus == Socket::State::BindStatus::FAILED) if (mState.mBindStatus == Socket::State::BindStatus::FAILED)
{ {
return; return;
} }
if (::listen(mHandle, SOMAXCONN) == SOCKET_ERROR) if (::listen(mHandle, SOMAXCONN) == SOCKET_ERROR)
{ {
mState.mBindStatus = Socket::State::BindStatus::FAILED; mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = ::WSAGetLastError(); mState.mErrorCode = ::WSAGetLastError();
mState.mErrorMessage = "WinsockSocket: Listen failed"; mState.mErrorMessage = "WinsockSocket: Listen failed";
::closesocket(mHandle); ::closesocket(mHandle);
return; return;
} }
while (true) while (true)
{ {
auto client_handle = ::accept(mHandle, NULL, NULL); auto client_handle = ::accept(mHandle, NULL, NULL);
if (client_handle == INVALID_SOCKET) if (client_handle == INVALID_SOCKET)
{ {
mState.mBindStatus = Socket::State::BindStatus::FAILED; mState.mBindStatus = Socket::State::BindStatus::FAILED;
mState.mErrorCode = ::WSAGetLastError(); mState.mErrorCode = ::WSAGetLastError();
mState.mErrorMessage = "WinsockSocket: Accept failed"; mState.mErrorMessage = "WinsockSocket: Accept failed";
::closesocket(mHandle); ::closesocket(mHandle);
break; break;
} }
else else
{ {
connectionFunc(client_handle); connectionFunc(client_handle);
} }
} }
} }
std::string WinsockSocket::send(const std::string& message) std::string WinsockSocket::send(const std::string& message)
{ {
if (mState.mConnectStatus != Socket::State::ConnectStatus::OK) if (mState.mConnectStatus != Socket::State::ConnectStatus::OK)
{ {
initialize(); initialize();
if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED) if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED)
{ {
return {}; return {};
} }
doConnect(); doConnect();
if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED) if (mState.mConnectStatus == Socket::State::ConnectStatus::FAILED)
{ {
return {}; return {};
} }
} }
auto result = ::send(mHandle, message.c_str(), static_cast<int>(message.size()), 0); auto result = ::send(mHandle, message.c_str(), static_cast<int>(message.size()), 0);
if (result == SOCKET_ERROR) if (result == SOCKET_ERROR)
{ {
onSockerError("WinsockSocket: Send failed."); onSockerError("WinsockSocket: Send failed.");
return {}; return {};
} }
result = ::shutdown(mHandle, SD_SEND); result = ::shutdown(mHandle, SD_SEND);
if (result == SOCKET_ERROR) if (result == SOCKET_ERROR)
{ {
onSockerError("WinsockSocket: Post send shutdown failed."); onSockerError("WinsockSocket: Post send shutdown failed.");
return {}; return {};
} }
std::string response; std::string response;
while (mState.mConnectStatus == Socket::State::ConnectStatus::OK) while (mState.mConnectStatus == Socket::State::ConnectStatus::OK)
{ {
response += recieve(); response += recieve();
} }
::closesocket(mHandle); ::closesocket(mHandle);
return response; return response;
} }
void WinsockSocket::respond(const std::string& message) void WinsockSocket::respond(const std::string& message)
{ {
auto result = ::send(mHandle, message.c_str(), static_cast<int>(message.size()), 0); auto result = ::send(mHandle, message.c_str(), static_cast<int>(message.size()), 0);
if (result == SOCKET_ERROR) if (result == SOCKET_ERROR)
{ {
onSockerError("WinsockSocket: Respond failed."); onSockerError("WinsockSocket: Respond failed.");
} }
} }
void WinsockSocket::onSockerError(const std::string& message) void WinsockSocket::onSockerError(const std::string& message)
{ {
mState.mErrorCode = ::WSAGetLastError(); mState.mErrorCode = ::WSAGetLastError();
mState.mErrorMessage = message; mState.mErrorMessage = message;
if (mState.mConnectStatus == Socket::State::ConnectStatus::OK) if (mState.mConnectStatus == Socket::State::ConnectStatus::OK)
{ {
::closesocket(mHandle); ::closesocket(mHandle);
} }
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED; mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
} }
std::string WinsockSocket::recieve() std::string WinsockSocket::recieve()
{ {
const int BUFFER_SIZE = 512; const int BUFFER_SIZE = 512;
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
auto result = ::recv(mHandle, buffer, BUFFER_SIZE, 0); auto result = ::recv(mHandle, buffer, BUFFER_SIZE, 0);
if (result > 0) if (result > 0)
{ {
return std::string(buffer); return std::string(buffer);
} }
else if (result == 0) else if (result == 0)
{ {
mState.mConnectStatus = Socket::State::ConnectStatus::UNSET; mState.mConnectStatus = Socket::State::ConnectStatus::UNSET;
} }
else else
{ {
mState.mConnectStatus = Socket::State::ConnectStatus::FAILED; mState.mConnectStatus = Socket::State::ConnectStatus::FAILED;
mState.mErrorCode = ::WSAGetLastError(); mState.mErrorCode = ::WSAGetLastError();
mState.mErrorMessage = "WinsockSocket: recv failed."; mState.mErrorMessage = "WinsockSocket: recv failed.";
} }
return {}; return {};
} }

View file

@ -9,32 +9,32 @@
class WinsockSocket : public Socket class WinsockSocket : public Socket
{ {
public: public:
WinsockSocket(const std::string& address, unsigned port); WinsockSocket(const std::string& address, unsigned port);
WinsockSocket(SOCKET handle); WinsockSocket(SOCKET handle);
~WinsockSocket(); ~WinsockSocket();
std::string recieve() override; std::string recieve() override;
void respond(const std::string& message) override; void respond(const std::string& message) override;
std::string send(const std::string& message) override; std::string send(const std::string& message) override;
using onIncomingConnectionFunc = std::function<void(SOCKET)>; using onIncomingConnectionFunc = std::function<void(SOCKET)>;
void doListen(onIncomingConnectionFunc connectionFunc); void doListen(onIncomingConnectionFunc connectionFunc);
private: private:
void initialize() override; void initialize() override;
void initializeForBind() override; void initializeForBind() override;
void doConnect() override; void doConnect() override;
void doBind() override; void doBind() override;
void onSockerError(const std::string& message); void onSockerError(const std::string& message);
SOCKET mHandle{ INVALID_SOCKET }; SOCKET mHandle{ INVALID_SOCKET };
addrinfo* mAddressInfo{ nullptr }; addrinfo* mAddressInfo{ nullptr };
}; };

View file

@ -3,15 +3,15 @@
#include "FileLogger.h" #include "FileLogger.h"
LatexMathExpression::LatexMathExpression(const std::string& expression) LatexMathExpression::LatexMathExpression(const std::string& expression)
: mRawBody(expression), : mRawBody(expression),
mType(Type::LINEAR) mType(Type::LINEAR)
{ {
MLOG_INFO("Adding expression with content: " << expression); MLOG_INFO("Adding expression with content: " << expression);
parse(); parse();
} }
LatexMathExpression::LatexMathExpression(Type type) LatexMathExpression::LatexMathExpression(Type type)
: mType(type) : mType(type)
{ {
} }
@ -23,150 +23,150 @@ LatexMathExpression::~LatexMathExpression()
const LatexMathSymbol& LatexMathExpression::getLeftSymbol() const const LatexMathSymbol& LatexMathExpression::getLeftSymbol() const
{ {
return mLeftSymbol; return mLeftSymbol;
} }
const LatexMathSymbol& LatexMathExpression::getRightSymbol() const const LatexMathSymbol& LatexMathExpression::getRightSymbol() const
{ {
return mRightSymbol; return mRightSymbol;
} }
void LatexMathExpression::setLeftSymbol(const LatexMathSymbol& symbol) void LatexMathExpression::setLeftSymbol(const LatexMathSymbol& symbol)
{ {
mLeftSymbol = symbol; mLeftSymbol = symbol;
} }
void LatexMathExpression::setRightSymbol(const LatexMathSymbol& symbol) void LatexMathExpression::setRightSymbol(const LatexMathSymbol& symbol)
{ {
mRightSymbol = symbol; mRightSymbol = symbol;
} }
void LatexMathExpression::onTagBodyChar(char c) void LatexMathExpression::onTagBodyChar(char c)
{ {
if (c == '}') if (c == '}')
{ {
onRBrace(); onRBrace();
} }
else else
{ {
mWorkingString += c; mWorkingString += c;
} }
} }
void LatexMathExpression::onFreeChar(char c) void LatexMathExpression::onFreeChar(char c)
{ {
if (c == '\\') if (c == '\\')
{ {
mLineState = LineState::IN_TAG_NAME; mLineState = LineState::IN_TAG_NAME;
} }
else if (c == '{') else if (c == '{')
{ {
onLBrace(); onLBrace();
} }
else if (c == '}') else if (c == '}')
{ {
onRBrace(); onRBrace();
} }
else if (c == '^') else if (c == '^')
{ {
onSuperscript(); onSuperscript();
} }
else if (c == '_') else if (c == '_')
{ {
onSubscript(); onSubscript();
} }
else if (std::isblank(c)) else if (std::isblank(c))
{ {
onSpace(); onSpace();
} }
else else
{ {
mWorkingString += c; mWorkingString += c;
} }
} }
void LatexMathExpression::parse() void LatexMathExpression::parse()
{ {
mLineState = LineState::NONE; mLineState = LineState::NONE;
mWorkingString.clear(); mWorkingString.clear();
for (auto c : mRawBody) for (auto c : mRawBody)
{ {
if (mLineState == LineState::IN_TAG_BODY) if (mLineState == LineState::IN_TAG_BODY)
{ {
onTagBodyChar(c); onTagBodyChar(c);
} }
else else
{ {
onFreeChar(c); onFreeChar(c);
} }
} }
onSpace(); onSpace();
onCloseExpression(); onCloseExpression();
} }
void LatexMathExpression::onSpace() void LatexMathExpression::onSpace()
{ {
if (mLineState == LineState::IN_TAG_NAME) if (mLineState == LineState::IN_TAG_NAME)
{ {
onFinishedTagName(); onFinishedTagName();
} }
else else
{ {
onLiteral(); onLiteral();
} }
mWorkingString.clear(); mWorkingString.clear();
} }
void LatexMathExpression::onLBrace() void LatexMathExpression::onLBrace()
{ {
if (mLineState == LineState::IN_TAG_NAME) if (mLineState == LineState::IN_TAG_NAME)
{ {
onFinishedTagName(); onFinishedTagName();
} }
else if (mLineState == LineState::AWAITING_LBRACE) else if (mLineState == LineState::AWAITING_LBRACE)
{ {
mLineState = LineState::IN_TAG_BODY; mLineState = LineState::IN_TAG_BODY;
} }
else if (mLineState == LineState::IN_TAG_BODY) else if (mLineState == LineState::IN_TAG_BODY)
{ {
mOpenBraceCount++; mOpenBraceCount++;
} }
else else
{ {
mWorkingString += "{"; mWorkingString += "{";
} }
} }
void LatexMathExpression::onRBrace() void LatexMathExpression::onRBrace()
{ {
if (mLineState == LineState::IN_TAG_BODY) if (mLineState == LineState::IN_TAG_BODY)
{ {
if (mOpenBraceCount == 0) if (mOpenBraceCount == 0)
{ {
onTagBody(); onTagBody();
} }
else else
{ {
mOpenBraceCount--; mOpenBraceCount--;
mWorkingString += "}"; mWorkingString += "}";
} }
} }
else else
{ {
mWorkingString += "}"; mWorkingString += "}";
} }
} }
void LatexMathExpression::setRawContent(const std::string& content) void LatexMathExpression::setRawContent(const std::string& content)
{ {
auto expression = std::make_unique<LatexMathExpression>(content); auto expression = std::make_unique<LatexMathExpression>(content);
mExpressions.push_back(std::move(expression)); mExpressions.push_back(std::move(expression));
} }
void LatexMathExpression::onTagBody() void LatexMathExpression::onTagBody()
{ {
onCloseExpression(); onCloseExpression();
} }
void LatexMathExpression::onSuperscript() void LatexMathExpression::onSuperscript()
@ -181,127 +181,127 @@ void LatexMathExpression::onSubscript()
void LatexMathExpression::onLiteral() void LatexMathExpression::onLiteral()
{ {
LatexMathSymbol symbol{ LatexMathSymbol::Type::RAW, mWorkingString, mWorkingString }; LatexMathSymbol symbol{ LatexMathSymbol::Type::RAW, mWorkingString, mWorkingString };
mWorkingSymbols.push_back(symbol); mWorkingSymbols.push_back(symbol);
} }
void LatexMathExpression::onFinishedTagName() void LatexMathExpression::onFinishedTagName()
{ {
if (auto lookup = LatexSymbolLookup::getKnownTag(mWorkingString); lookup) if (auto lookup = LatexSymbolLookup::getKnownTag(mWorkingString); lookup)
{ {
if (mLineState == LineState::AWAITING_LBRACE || mLineState == LineState::IN_TAG_NAME) if (mLineState == LineState::AWAITING_LBRACE || mLineState == LineState::IN_TAG_NAME)
{ {
onCloseExpression(); onCloseExpression();
if (*lookup == LatexMathSymbol::Tag::FRAC) if (*lookup == LatexMathSymbol::Tag::FRAC)
{ {
onFracTag(); onFracTag();
mWorkingString.clear(); mWorkingString.clear();
} }
else if (auto tag_type = LatexSymbolLookup::getTagType(*lookup); tag_type == LatexMathSymbol::Type::ENCLOSING_TAG) else if (auto tag_type = LatexSymbolLookup::getTagType(*lookup); tag_type == LatexMathSymbol::Type::ENCLOSING_TAG)
{ {
onEnclosingTag(*lookup); onEnclosingTag(*lookup);
} }
mLineState = LineState::IN_TAG_BODY; mLineState = LineState::IN_TAG_BODY;
} }
} }
else if (auto lookup = LatexSymbolLookup::getSymbolUtf8(mWorkingString); lookup) else if (auto lookup = LatexSymbolLookup::getSymbolUtf8(mWorkingString); lookup)
{ {
LatexMathSymbol symbol{ LatexMathSymbol::Type::TAG, mWorkingString, *lookup }; LatexMathSymbol symbol{ LatexMathSymbol::Type::TAG, mWorkingString, *lookup };
mWorkingSymbols.push_back(symbol); mWorkingSymbols.push_back(symbol);
mLineState = LineState::NONE; mLineState = LineState::NONE;
} }
} }
void LatexMathExpression::onFracTag() void LatexMathExpression::onFracTag()
{ {
mWorkingType = Type::FRACTION; mWorkingType = Type::FRACTION;
auto expression = std::make_unique<LatexMathExpression>(mWorkingType); auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
mWorkingExpression = expression.get(); mWorkingExpression = expression.get();
mExpressions.push_back(std::move(expression)); mExpressions.push_back(std::move(expression));
} }
void LatexMathExpression::onEnclosingTag(LatexMathSymbol::Tag tag) void LatexMathExpression::onEnclosingTag(LatexMathSymbol::Tag tag)
{ {
mWorkingType = Type::ENCLOSING; mWorkingType = Type::ENCLOSING;
auto expression = std::make_unique<LatexMathExpression>(mWorkingType); auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
auto left_symbol_value = LatexSymbolLookup::getLeftSymbolUtf8(tag); auto left_symbol_value = LatexSymbolLookup::getLeftSymbolUtf8(tag);
auto right_symbol_value = LatexSymbolLookup::getRightSymbolUtf8(tag); auto right_symbol_value = LatexSymbolLookup::getRightSymbolUtf8(tag);
MLOG_INFO("Adding enclosing tag"); MLOG_INFO("Adding enclosing tag");
expression->setLeftSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "left", *left_symbol_value }); expression->setLeftSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "left", *left_symbol_value });
expression->setRightSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "right", *right_symbol_value }); expression->setRightSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "right", *right_symbol_value });
mWorkingExpression = expression.get(); mWorkingExpression = expression.get();
mExpressions.push_back(std::move(expression)); mExpressions.push_back(std::move(expression));
} }
void LatexMathExpression::onCloseExpression() void LatexMathExpression::onCloseExpression()
{ {
if (mWorkingType == Type::LEAF) if (mWorkingType == Type::LEAF)
{ {
MLOG_INFO("onCloseExpression LEAF"); MLOG_INFO("onCloseExpression LEAF");
if (!mWorkingSymbols.empty()) if (!mWorkingSymbols.empty())
{ {
MLOG_INFO("Has working symbols"); MLOG_INFO("Has working symbols");
auto expression = std::make_unique<LatexMathExpression>(mWorkingType); auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
expression->setContent(mWorkingSymbols); expression->setContent(mWorkingSymbols);
mExpressions.push_back(std::move(expression)); mExpressions.push_back(std::move(expression));
} }
} }
else if (mWorkingType == Type::FRACTION) else if (mWorkingType == Type::FRACTION)
{ {
MLOG_INFO("onCloseExpression FRACTION"); MLOG_INFO("onCloseExpression FRACTION");
mWorkingExpression->setRawContent(mWorkingString); mWorkingExpression->setRawContent(mWorkingString);
if (mWorkingExpression->getExpressions().size() == 2) if (mWorkingExpression->getExpressions().size() == 2)
{ {
mWorkingType = Type::LEAF; mWorkingType = Type::LEAF;
mLineState = LineState::NONE; mLineState = LineState::NONE;
} }
else else
{ {
mLineState = LineState::AWAITING_LBRACE; mLineState = LineState::AWAITING_LBRACE;
mOpenBraceCount = 0; mOpenBraceCount = 0;
} }
} }
else if (mWorkingType == Type::ENCLOSING) else if (mWorkingType == Type::ENCLOSING)
{ {
MLOG_INFO("onCloseExpression ENCLOSING"); MLOG_INFO("onCloseExpression ENCLOSING");
if (!mWorkingString.empty()) if (!mWorkingString.empty())
{ {
mWorkingExpression->setRawContent(mWorkingString); mWorkingExpression->setRawContent(mWorkingString);
if (mWorkingExpression->getExpressions().size() == 1) if (mWorkingExpression->getExpressions().size() == 1)
{ {
mWorkingType = Type::LEAF; mWorkingType = Type::LEAF;
mLineState = LineState::NONE; mLineState = LineState::NONE;
} }
} }
} }
mWorkingString.clear(); mWorkingString.clear();
mWorkingSymbols.clear(); mWorkingSymbols.clear();
} }
void LatexMathExpression::setContent(std::vector<LatexMathSymbol>& symbols) void LatexMathExpression::setContent(std::vector<LatexMathSymbol>& symbols)
{ {
mSymbols = symbols; mSymbols = symbols;
} }
const std::vector<LatexMathSymbol>& LatexMathExpression::getSymbols() const const std::vector<LatexMathSymbol>& LatexMathExpression::getSymbols() const
{ {
return mSymbols; return mSymbols;
} }
const LatexMathExpression::Type LatexMathExpression::getType() const LatexMathExpression::Type LatexMathExpression::getType() const
{ {
return mType; return mType;
} }
const std::vector<LatexMathExpressionPtr>& LatexMathExpression::getExpressions() const const std::vector<LatexMathExpressionPtr>& LatexMathExpression::getExpressions() const
{ {
return mExpressions; return mExpressions;
} }

View file

@ -12,91 +12,91 @@ using LatexMathExpressionPtr = std::unique_ptr<LatexMathExpression>;
class LatexMathExpression class LatexMathExpression
{ {
public: public:
enum class Type enum class Type
{ {
LINEAR, LINEAR,
LEAF, LEAF,
FRACTION, FRACTION,
ENCLOSING, ENCLOSING,
SUBSCRIPT, SUBSCRIPT,
SUPERSCRIPT SUPERSCRIPT
}; };
enum class LineState enum class LineState
{ {
NONE, NONE,
IN_TAG_NAME, IN_TAG_NAME,
AWAITING_LBRACE, AWAITING_LBRACE,
IN_TAG_BODY IN_TAG_BODY
}; };
LatexMathExpression(const std::string& expression); LatexMathExpression(const std::string& expression);
LatexMathExpression(Type type); LatexMathExpression(Type type);
~LatexMathExpression(); ~LatexMathExpression();
const std::vector<LatexMathSymbol>& getSymbols() const; const std::vector<LatexMathSymbol>& getSymbols() const;
const std::vector<LatexMathExpressionPtr>& getExpressions() const; const std::vector<LatexMathExpressionPtr>& getExpressions() const;
const LatexMathSymbol& getLeftSymbol() const; const LatexMathSymbol& getLeftSymbol() const;
const LatexMathSymbol& getRightSymbol() const; const LatexMathSymbol& getRightSymbol() const;
const Type getType() const; Type getType() const;
void setLeftSymbol(const LatexMathSymbol& symbol); void setLeftSymbol(const LatexMathSymbol& symbol);
void setRightSymbol(const LatexMathSymbol& symbol); void setRightSymbol(const LatexMathSymbol& symbol);
void setContent(std::vector<LatexMathSymbol>& symbols); void setContent(std::vector<LatexMathSymbol>& symbols);
void setRawContent(const std::string& content); void setRawContent(const std::string& content);
void onTagBodyChar(char c); void onTagBodyChar(char c);
void onFreeChar(char c); void onFreeChar(char c);
void onSpace(); void onSpace();
void onLBrace(); void onLBrace();
void onRBrace(); void onRBrace();
void onSuperscript(); void onSuperscript();
void onSubscript(); void onSubscript();
void onLiteral(); void onLiteral();
void onTagBody(); void onTagBody();
void onFinishedTagName(); void onFinishedTagName();
void onCloseExpression(); void onCloseExpression();
void onFracTag(); void onFracTag();
void onEnclosingTag(LatexMathSymbol::Tag tag); void onEnclosingTag(LatexMathSymbol::Tag tag);
void parse(); void parse();
private: private:
std::size_t mOpenBraceCount{ 0 }; std::size_t mOpenBraceCount{ 0 };
LineState mLineState{ LineState::NONE }; LineState mLineState{ LineState::NONE };
std::string mWorkingString; std::string mWorkingString;
std::string mRawBody; std::string mRawBody;
Type mWorkingType{ Type::LEAF }; Type mWorkingType{ Type::LEAF };
LatexMathExpression* mWorkingExpression{ nullptr }; LatexMathExpression* mWorkingExpression{ nullptr };
Type mType{ Type::LEAF }; Type mType{ Type::LEAF };
std::vector<LatexMathSymbol> mWorkingSymbols; std::vector<LatexMathSymbol> mWorkingSymbols;
LatexMathSymbol mLeftSymbol; LatexMathSymbol mLeftSymbol;
LatexMathSymbol mRightSymbol; LatexMathSymbol mRightSymbol;
std::vector<LatexMathSymbol> mSymbols; std::vector<LatexMathSymbol> mSymbols;
std::vector<LatexMathExpressionPtr> mExpressions; std::vector<LatexMathExpressionPtr> mExpressions;
}; };

View file

@ -4,18 +4,20 @@
#include "PlotSeriesNode.h" #include "PlotSeriesNode.h"
#include "LineNode.h" #include "LineNode.h"
#include "EquationNode.h"
#include "TextNode.h"
PlotNode::PlotNode(const Transform& transform) PlotNode::PlotNode(const Transform& transform)
: AbstractVisualNode(transform) : AbstractVisualNode(transform)
{ {
} }
void PlotNode::setContent(Plot* content) void PlotNode::setContent(Plot* content)
{ {
mContent = content; mContent = content;
mContentDirty = true; mContentDirty = true;
} }
void PlotNode::update(SceneInfo* sceneInfo) void PlotNode::update(SceneInfo* sceneInfo)
@ -36,7 +38,7 @@ void PlotNode::setAxisEndStyle(LineEndNode::Style style)
} }
} }
void PlotNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void PlotNode::createOrUpdateGeometry(SceneInfo*)
{ {
const double height = 100.0; const double height = 100.0;
const double width = 100.0; const double width = 100.0;

View file

@ -9,32 +9,31 @@ class LineNode;
class PlotCaptionNode; class PlotCaptionNode;
class PlotSeriesNode; class PlotSeriesNode;
class PlotNode : public AbstractVisualNode class PlotNode : public AbstractVisualNode
{ {
public: public:
PlotNode(const Transform& transform = {}); PlotNode(const Transform& transform = {});
void setContent(Plot* content); void setContent(Plot* content);
void setAxisEndStyle(LineEndNode::Style style); void setAxisEndStyle(LineEndNode::Style style);
void update(SceneInfo* sceneInfo) override; void update(SceneInfo* sceneInfo) override;
protected: protected:
void createOrUpdateGeometry(SceneInfo* sceneInfo); void createOrUpdateGeometry(SceneInfo* sceneInfo);
Plot* mContent{ nullptr }; Plot* mContent{ nullptr };
bool mContentDirty = true; bool mContentDirty = true;
std::unique_ptr<LineNode> mXAxis; std::unique_ptr<LineNode> mXAxis;
std::unique_ptr<LineNode> mYAxis; std::unique_ptr<LineNode> mYAxis;
LineEndNode::Style mAxisEndStyle{ LineEndNode::Style::NONE }; LineEndNode::Style mAxisEndStyle{ LineEndNode::Style::NONE };
std::unique_ptr<PlotCaptionNode> mXAxisCaption; std::unique_ptr<PlotCaptionNode> mXAxisCaption;
std::unique_ptr<PlotCaptionNode> mYAxisCaption; std::unique_ptr<PlotCaptionNode> mYAxisCaption;
std::vector<std::unique_ptr<PlotSeriesNode> > mSeries; std::vector<std::unique_ptr<PlotSeriesNode> > mSeries;
}; };

View file

@ -20,6 +20,11 @@ public:
std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) override; std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) override;
double getHorizontalAdvance(const FontItem&, const std::string&) override
{
return 0.0;
}
private: private:
std::filesystem::path mSystemFontLocation{"/usr/share/fonts/"}; std::filesystem::path mSystemFontLocation{"/usr/share/fonts/"};

View file

@ -102,12 +102,12 @@ void OpenGlMeshPainter::paint(SceneModel* model, DrawingContext* context)
{ {
if (idx % 3 == 0) if (idx % 3 == 0)
{ {
auto x = vertices[idx]*transform.getScaleX() + transform.getLocation().getX(); auto x = vertices[idx]*transform.getScale().mX + transform.getLocation().getX();
vertices[idx] = 2*x/width - 1.0; vertices[idx] = 2*x/width - 1.0;
} }
else if(idx%3 == 1) else if(idx%3 == 1)
{ {
auto y = vertices[idx]*transform.getScaleY() + transform.getLocation().getY(); auto y = vertices[idx]*transform.getScale().mY + transform.getLocation().getY();
vertices[idx] = 1.0 - 2*y/height; vertices[idx] = 1.0 - 2*y/height;
} }
@ -124,7 +124,7 @@ void OpenGlMeshPainter::paint(SceneModel* model, DrawingContext* context)
indices = dynamic_cast<TriMesh*>(model->getMesh())->getFaceNodeIds(); indices = dynamic_cast<TriMesh*>(model->getMesh())->getFaceNodeIds();
} }
auto model_color = model->getFillColor().getAsVectorDouble(); auto model_color = model->getSolidMaterial().getFillColor().getAsVectorDouble();
std::vector<float> color = {float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3])}; std::vector<float> color = {float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3])};
paint(vertices, indices, color, line_mesh); paint(vertices, indices, color, line_mesh);

View file

@ -4,60 +4,60 @@
#include "PolygonNode.h" #include "PolygonNode.h"
LineEndNode::LineEndNode(const Transform& t) LineEndNode::LineEndNode(const Transform& t)
: MaterialNode(t) : MaterialNode(t)
{ {
} }
void LineEndNode::setStyle(LineEndNode::Style style) void LineEndNode::setStyle(LineEndNode::Style style)
{ {
if (mStyle != style) if (mStyle != style)
{ {
mStyle = style; mStyle = style;
mContentDirty = true; mContentDirty = true;
} }
} }
void LineEndNode::setSize(double size) void LineEndNode::setSize(double size)
{ {
if (mSize != size) if (mSize != size)
{ {
mSize = size; mSize = size;
mContentDirty = true; mContentDirty = true;
} }
} }
void LineEndNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void LineEndNode::createOrUpdateGeometry(SceneInfo*)
{ {
if (!mContentNode) if (!mContentNode)
{ {
if (mStyle == Style::CLOSED_ARROW) if (mStyle == Style::CLOSED_ARROW)
{ {
auto polygon = std::make_unique<PolygonNode>(); auto polygon = std::make_unique<PolygonNode>();
auto p0 = Point(0.0, -mSize / 2.0); auto p0 = Point(0.0, -mSize / 2.0);
auto p1 = Point(mSize, 0.0); auto p1 = Point(mSize, 0.0);
auto p2 = Point(0.0, mSize / 2.0); auto p2 = Point(0.0, mSize / 2.0);
polygon->setPoints({ p0, p1, p2 }); polygon->setPoints({ p0, p1, p2 });
polygon->setFillColor({ 0, 0, 0 }); polygon->setFillColor({ 0, 0, 0 });
mContentNode = std::move(polygon); mContentNode = std::move(polygon);
addChild(mContentNode.get()); addChild(mContentNode.get());
} }
} }
} }
void LineEndNode::update(SceneInfo* sceneInfo) void LineEndNode::update(SceneInfo* sceneInfo)
{ {
if (mContentDirty) if (mContentDirty)
{ {
createOrUpdateGeometry(sceneInfo); createOrUpdateGeometry(sceneInfo);
mContentDirty = false; mContentDirty = false;
} }
if (mMaterialIsDirty) if (mMaterialIsDirty)
{ {
//updateMaterial(); //updateMaterial();
mMaterialIsDirty = false; mMaterialIsDirty = false;
} }
} }

View file

@ -63,7 +63,7 @@ double TextNode::getContentWidth(SceneInfo* sceneInfo)
return mContentWidth; return mContentWidth;
} }
double TextNode::getContentHeight(SceneInfo* sceneInfo) double TextNode::getContentHeight(SceneInfo*)
{ {
if (mContentHeight == 1.0) if (mContentHeight == 1.0)
{ {

View file

@ -126,8 +126,8 @@ void SvgNode::onCircle(XmlElement* element, std::unique_ptr<GeometryNode>& node)
{ {
const auto transform = svg_circle->getTransform(); const auto transform = svg_circle->getTransform();
loc.move(transform.getLocation().getX(), transform.getLocation().getY()); loc.move(transform.getLocation().getX(), transform.getLocation().getY());
radius *= transform.getScaleX(); radius *= transform.getScale().mX;
minor_radius *= transform.getScaleY(); minor_radius *= transform.getScale().mY;
} }
auto circle_node = std::make_unique<CircleNode>(loc, radius); auto circle_node = std::make_unique<CircleNode>(loc, radius);

View file

@ -71,8 +71,8 @@ void SvgPainter::paintMesh(SvgDocument* document, SceneModel* model, bool showOu
auto face_locs = face->getNodeLocations(); auto face_locs = face->getNodeLocations();
for (const auto& loc : face_locs) for (const auto& loc : face_locs)
{ {
const auto x = loc.getX() * transform.getScaleX() + transform.getLocation().getX(); const auto x = loc.getX() * transform.getScale().mX + transform.getLocation().getX();
const auto y = loc.getY() * transform.getScaleY() + transform.getLocation().getY(); const auto y = loc.getY() * transform.getScale().mY + transform.getLocation().getY();
points[count] = { x, y }; points[count] = { x, y };
count++; count++;
} }
@ -122,7 +122,7 @@ void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
element->setNoStroke(); element->setNoStroke();
} }
if (!transform.isDefaultTransform()) if (!transform.isIdentityTransform())
{ {
element->addAttribute(toTransform(transform)); element->addAttribute(toTransform(transform));
} }
@ -249,7 +249,7 @@ void SvgPainter::paintText(SvgDocument* document, SceneText* text) const
svg_text->setFontSize(text->getTextData().mFont.getSize()); svg_text->setFontSize(text->getTextData().mFont.getSize());
const auto transform = text->getTransform(); const auto transform = text->getTransform();
if (!transform.isDefaultTransform()) if (!transform.isIdentityTransform())
{ {
svg_text->addAttribute(toTransform(transform)); svg_text->addAttribute(toTransform(transform));
} }
@ -262,13 +262,13 @@ std::unique_ptr<XmlAttribute> SvgPainter::toTransform(const Transform& transform
auto svg_transform = std::make_unique<XmlAttribute>("transform"); auto svg_transform = std::make_unique<XmlAttribute>("transform");
std::string ops; std::string ops;
if (!transform.hasDefaultLocation()) if (!transform.isIdentityTransform())
{ {
ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") "; ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") ";
} }
if (!transform.hasDefaultScale()) if (!transform.getScale().isIdentity())
{ {
ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") "; ops += "scale(" + std::to_string(transform.getScale().mX) + " " + std::to_string(transform.getScale().mY) + ") ";
} }
svg_transform->setValue(ops); svg_transform->setValue(ops);

View file

@ -53,7 +53,8 @@ Transform SvgShapeElement::getTransform() const
else if (in_scale) else if (in_scale)
{ {
const auto loc = parsePoint(working_string, 1.0); const auto loc = parsePoint(working_string, 1.0);
transform.setScale(loc.getX(), loc.getY(), loc.getZ()); Scale scale(loc.getX(), loc.getY(), loc.getZ());
transform.setScale(scale);
in_scale = false; in_scale = false;
} }
working_string.clear(); working_string.clear();

View file

@ -14,7 +14,7 @@ xcb_gcontext_t XcbTextInterface::GetFontGC(xcb_connection_t *connection,
/* create graphics context */ /* create graphics context */
xcb_gcontext_t gc = xcb_generate_id(connection); xcb_gcontext_t gc = xcb_generate_id(connection);
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
auto fillColor = textElement->getFillColor().getAsUInt32(); auto fillColor = textElement->getMaterial()->getFillColor().getAsUInt32();
uint32_t value_list[3] = {screen->black_pixel, fillColor, font }; uint32_t value_list[3] = {screen->black_pixel, fillColor, font };
xcb_create_gc(connection, gc, window, mask, value_list); xcb_create_gc(connection, gc, window, mask, value_list);

View file

@ -4,30 +4,35 @@
#include "Plot.h" #include "Plot.h"
#include "PlotNode.h" #include "PlotNode.h"
#include "PlotSeriesNode.h"
#include "PlotCaptionNode.h"
#include "EquationNode.h"
#include "TextNode.h"
#include "LineNode.h"
TEST_CASE(TestPlotting, "[publishing]") TEST_CASE(TestPlotting, "[publishing]")
{ {
auto plot = std::make_unique<Plot>(); auto plot = std::make_unique<Plot>();
plot->setXAxisCaption("X Axis"); plot->setXAxisCaption("X Axis");
plot->setYAxisCaption("Y Axis"); plot->setYAxisCaption("Y Axis");
PlotSeries series("Series-1"); PlotSeries series("Series-1");
std::vector<Point> data{ {0.0, 0.0}, {10.0, 40.0}, {20.0, 80.0} }; std::vector<Point> data{ {0.0, 0.0}, {10.0, 40.0}, {20.0, 80.0} };
series.setData(data); series.setData(data);
plot->addSeries(series); plot->addSeries(series);
Point loc(10, 10); Point loc(10, 10);
auto plot_node = std::make_unique<PlotNode>(Transform(loc)); auto plot_node = std::make_unique<PlotNode>(Transform(loc));
plot_node->setAxisEndStyle(LineEndNode::Style::CLOSED_ARROW); plot_node->setAxisEndStyle(LineEndNode::Style::CLOSED_ARROW);
plot_node->setContent(plot.get()); plot_node->setContent(plot.get());
TestRenderer renderer(800, 800); TestRenderer renderer(800, 800);
auto scene = renderer.getScene(); auto scene = renderer.getScene();
scene->addNode(plot_node.get()); scene->addNode(plot_node.get());
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "plot.svg"); renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "plot.svg");
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "plot.png"); renderer.write(TestUtils::getTestOutputDir(__FILE__) / "plot.png");
} }