Fix linux build.
This commit is contained in:
parent
a6d92e142f
commit
9e1d951520
50 changed files with 1586 additions and 1192 deletions
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -127,4 +130,4 @@ void QuantumCircuitNode::createOrUpdateGeometry(SceneInfo*)
|
||||||
|
|
||||||
mWireNodes.push_back(std::move(wire_node));
|
mWireNodes.push_back(std::move(wire_node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -70,4 +71,4 @@ void QuantumWireNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
|
||||||
addChild(mLine.get());
|
addChild(mLine.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
{
|
{
|
||||||
|
@ -21,4 +27,4 @@ TEST_CASE(TestQuantumCircuitParsing, "quantum_computing")
|
||||||
|
|
||||||
renderer.getScene()->addNode(node.get());
|
renderer.getScene()->addNode(node.get());
|
||||||
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg");
|
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
31
src/base/geometry/Rotation.cpp
Normal file
31
src/base/geometry/Rotation.cpp
Normal 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()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
45
src/base/geometry/Rotation.h
Normal file
45
src/base/geometry/Rotation.h
Normal 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;
|
||||||
|
};
|
|
@ -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)
|
||||||
{
|
{
|
||||||
mScaleX = scaleX;
|
if (mScale != scale)
|
||||||
mScaleY = scaleY;
|
{
|
||||||
mScaleZ = scaleZ;
|
mScale = scale;
|
||||||
|
updateMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transform::setRotation(const Rotation& rotation)
|
||||||
|
{
|
||||||
|
if (mRotation != rotation)
|
||||||
|
{
|
||||||
|
mRotation = rotation;
|
||||||
|
updateMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transform::updateMatrix()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -70,4 +67,4 @@ target_include_directories(${MODULE_NAME} PUBLIC
|
||||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
target_link_libraries( ${MODULE_NAME} PUBLIC core ${platform_LIBS})
|
target_link_libraries( ${MODULE_NAME} PUBLIC core ${platform_LIBS})
|
||||||
|
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/base)
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/base)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 {};
|
||||||
|
}
|
|
@ -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 };
|
||||||
|
};
|
|
@ -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>;
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>;
|
|
|
@ -1,8 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "SocketInterface.h"
|
class WinsockInterface
|
||||||
|
|
||||||
class WinsockInterface : public ISocketInterface
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~WinsockInterface();
|
~WinsockInterface();
|
||||||
|
@ -10,4 +8,4 @@ public:
|
||||||
bool initializeWinsock();
|
bool initializeWinsock();
|
||||||
|
|
||||||
void closeWinsock();
|
void closeWinsock();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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/"};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue