Initial circuits plugin work.
This commit is contained in:
parent
b5f21900eb
commit
f8a2ce3c59
50 changed files with 1451 additions and 97 deletions
|
@ -1,15 +1,2 @@
|
||||||
set(PLUGIN_NAME circuits)
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(test)
|
||||||
list(APPEND client_HEADERS
|
|
||||||
ElectronicCircuit.h)
|
|
||||||
|
|
||||||
list(APPEND client_LIB_INCLUDES
|
|
||||||
ElectronicCircuit.cpp)
|
|
||||||
|
|
||||||
add_library(${PLUGIN_NAME} SHARED ${client_LIB_INCLUDES})
|
|
||||||
|
|
||||||
target_include_directories(${PLUGIN_NAME} PUBLIC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
target_link_libraries(${PLUGIN_NAME} PUBLIC core)
|
|
||||||
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class CircuitElement
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class Terminal : public CircuitElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
INPUT,
|
|
||||||
OUTPUT
|
|
||||||
};
|
|
||||||
|
|
||||||
Terminal(Type type)
|
|
||||||
: mType(type)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
double mValue{0};
|
|
||||||
Type mType;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Wire
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Wire(CircuitElement* input, CircuitElement* output)
|
|
||||||
: mInput(input),
|
|
||||||
mOutput(output)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CircuitElement* mInput{nullptr};
|
|
||||||
CircuitElement* mOutput{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
class LogicGate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
NOT,
|
|
||||||
AND,
|
|
||||||
OR,
|
|
||||||
XOR,
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ElectronicCircuit
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
7
plugins/circuits/resources/svg/and_gate.svg
Normal file
7
plugins/circuits/resources/svg/and_gate.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="48">
|
||||||
|
<path d="M4 8 h24 a16 16 0 0 1 0 32 h-24Z" fill="none" stroke="black"></path>
|
||||||
|
|
||||||
|
<path d="M4 8 h16 q16 2 24 16 q-12 16 -24 16 h-16 q12 -16 0 -32Z" fill="none" stroke="black" transform="translate(0, 50)"></path>
|
||||||
|
|
||||||
|
<path d="M4 8 h16 q16 2 24 16 q-12 16 -24 16 h-16 q12 -16 0 -32Z" fill="none" stroke="black" transform="translate(0, 50)"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 416 B |
42
plugins/circuits/src/CMakeLists.txt
Normal file
42
plugins/circuits/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
set(PLUGIN_NAME circuits)
|
||||||
|
|
||||||
|
list(APPEND HEADERS
|
||||||
|
CircuitElement.h
|
||||||
|
Wire.h
|
||||||
|
Terminal.h
|
||||||
|
ElectronicCircuit.h
|
||||||
|
TruthTable.h
|
||||||
|
gates/LogicGate.h
|
||||||
|
gates/BasicLogicGates.h
|
||||||
|
visuals/ElectronicCircuitNode.h
|
||||||
|
visuals/WireNode.h
|
||||||
|
visuals/TerminalNode.h
|
||||||
|
visuals/LogicGateNode.h
|
||||||
|
visuals/LogicGatePrimitiveShapes.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND SOURCES
|
||||||
|
CircuitElement.cpp
|
||||||
|
Wire.cpp
|
||||||
|
Terminal.cpp
|
||||||
|
ElectronicCircuit.cpp
|
||||||
|
TruthTable.cpp
|
||||||
|
gates/BasicLogicGates.cpp
|
||||||
|
gates/LogicGate.cpp
|
||||||
|
visuals/ElectronicCircuitNode.cpp
|
||||||
|
visuals/WireNode.cpp
|
||||||
|
visuals/TerminalNode.cpp
|
||||||
|
visuals/LogicGateNode.cpp
|
||||||
|
visuals/LogicGatePrimitiveShapes.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(${PLUGIN_NAME} SHARED ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(${PLUGIN_NAME} PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/gates
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
||||||
|
)
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements)
|
||||||
|
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
||||||
|
set_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
28
plugins/circuits/src/CircuitElement.h
Normal file
28
plugins/circuits/src/CircuitElement.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
INPUT_TERMINAL,
|
||||||
|
OUTPUT_TERMINAL,
|
||||||
|
WIRE,
|
||||||
|
LOGIC_GATE,
|
||||||
|
FANOUT,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~CircuitElement() = default;
|
||||||
|
|
||||||
|
virtual CircuitElement::Type getType() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
27
plugins/circuits/src/ElectronicCircuit.cpp
Normal file
27
plugins/circuits/src/ElectronicCircuit.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "ElectronicCircuit.h"
|
||||||
|
|
||||||
|
#include "LogicGate.h"
|
||||||
|
|
||||||
|
void ElectronicCircuit::addInputTerminal(TerminalPtr terminal)
|
||||||
|
{
|
||||||
|
mInputTerminals.push_back(terminal.get());
|
||||||
|
mElements.push_back(std::move(terminal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuit::addOutputTerminal(TerminalPtr terminal)
|
||||||
|
{
|
||||||
|
mOutputTerminals.push_back(terminal.get());
|
||||||
|
mElements.push_back(std::move(terminal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuit::addWire(WirePtr wire)
|
||||||
|
{
|
||||||
|
mWires.push_back(wire.get());
|
||||||
|
mElements.push_back(std::move(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuit::addLogicGate(LogicGatePtr gate)
|
||||||
|
{
|
||||||
|
mLogicGates.push_back(gate.get());
|
||||||
|
mElements.push_back(std::move(gate));
|
||||||
|
}
|
42
plugins/circuits/src/ElectronicCircuit.h
Normal file
42
plugins/circuits/src/ElectronicCircuit.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CircuitElement.h"
|
||||||
|
#include "LogicGate.h"
|
||||||
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
using LogicGatePtr = std::unique_ptr<LogicGate>;
|
||||||
|
|
||||||
|
class ElectronicCircuit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addInputTerminal(TerminalPtr terminal);
|
||||||
|
|
||||||
|
void addOutputTerminal(TerminalPtr terminal);
|
||||||
|
|
||||||
|
void addWire(WirePtr wire);
|
||||||
|
|
||||||
|
void addLogicGate(LogicGatePtr gate);
|
||||||
|
|
||||||
|
const std::vector<Terminal*>& getInputTerminals() const
|
||||||
|
{
|
||||||
|
return mInputTerminals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<LogicGate*>& getLogicGates() const
|
||||||
|
{
|
||||||
|
return mLogicGates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Terminal*> mInputTerminals;
|
||||||
|
std::vector<Terminal*> mOutputTerminals;
|
||||||
|
|
||||||
|
std::vector<Wire*> mWires;
|
||||||
|
|
||||||
|
std::vector<LogicGate*> mLogicGates;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<CircuitElement> > mElements;
|
||||||
|
};
|
18
plugins/circuits/src/Terminal.cpp
Normal file
18
plugins/circuits/src/Terminal.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
Terminal::Terminal(TerminalType type, const std::string& label)
|
||||||
|
: mType(type),
|
||||||
|
mLabel(label)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire* Terminal::getConnection() const
|
||||||
|
{
|
||||||
|
return mConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::setConnection(Wire* connection)
|
||||||
|
{
|
||||||
|
mConnection = connection;
|
||||||
|
}
|
35
plugins/circuits/src/Terminal.h
Normal file
35
plugins/circuits/src/Terminal.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CircuitElement.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Wire;
|
||||||
|
|
||||||
|
class Terminal : public CircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class TerminalType
|
||||||
|
{
|
||||||
|
INPUT,
|
||||||
|
OUTPUT
|
||||||
|
};
|
||||||
|
|
||||||
|
Terminal(TerminalType type, const std::string& label = {});
|
||||||
|
|
||||||
|
Wire* getConnection() const;
|
||||||
|
|
||||||
|
Type getType() const override
|
||||||
|
{
|
||||||
|
return mType == TerminalType::INPUT ? Type::INPUT_TERMINAL : Type::OUTPUT_TERMINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setConnection(Wire* connection);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mLabel;
|
||||||
|
bool mValue{ false };
|
||||||
|
TerminalType mType;
|
||||||
|
Wire* mConnection{ nullptr };
|
||||||
|
};
|
||||||
|
using TerminalPtr = std::unique_ptr<Terminal>;
|
11
plugins/circuits/src/TruthTable.cpp
Normal file
11
plugins/circuits/src/TruthTable.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "TruthTable.h"
|
||||||
|
|
||||||
|
const TruthTable::TableData TruthTable::AND_TRUTH_TABLE = { {{0, 0}, {0}} };
|
||||||
|
|
||||||
|
TruthTable TruthTable::getAndTruthTable()
|
||||||
|
{
|
||||||
|
TruthTable table(2, 1);
|
||||||
|
table.setTable(AND_TRUTH_TABLE);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
32
plugins/circuits/src/TruthTable.h
Normal file
32
plugins/circuits/src/TruthTable.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class TruthTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TableData = std::map<std::vector<bool>, std::vector<bool> >;
|
||||||
|
|
||||||
|
TruthTable(std::size_t numInputColumns, std::size_t numOutputColumns)
|
||||||
|
: mNumInputColumns(numInputColumns),
|
||||||
|
mNumOutputColumns(numOutputColumns)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTable(const TableData& data)
|
||||||
|
{
|
||||||
|
mTable = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TruthTable getAndTruthTable();
|
||||||
|
|
||||||
|
static const TruthTable::TableData AND_TRUTH_TABLE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t mNumInputColumns{ 0 };
|
||||||
|
std::size_t mNumOutputColumns{ 0 };
|
||||||
|
|
||||||
|
TableData mTable;
|
||||||
|
};
|
18
plugins/circuits/src/Wire.cpp
Normal file
18
plugins/circuits/src/Wire.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
Wire::Wire(CircuitElement* input, CircuitElement* output)
|
||||||
|
: mInput(input),
|
||||||
|
mOutput(output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitElement* Wire::getInput() const
|
||||||
|
{
|
||||||
|
return mInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitElement* Wire::getOutput() const
|
||||||
|
{
|
||||||
|
return mOutput;
|
||||||
|
}
|
26
plugins/circuits/src/Wire.h
Normal file
26
plugins/circuits/src/Wire.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CircuitElement.h"
|
||||||
|
|
||||||
|
class Wire : public CircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Wire(CircuitElement* input, CircuitElement* output);
|
||||||
|
|
||||||
|
CircuitElement* getInput() const;
|
||||||
|
CircuitElement* getOutput() const;
|
||||||
|
|
||||||
|
Type getType() const override
|
||||||
|
{
|
||||||
|
return Type::WIRE;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CircuitElement* mInput{ nullptr };
|
||||||
|
CircuitElement* mOutput{ nullptr };
|
||||||
|
};
|
||||||
|
using WirePtr = std::unique_ptr<Wire>;
|
||||||
|
|
||||||
|
class Fanout : public CircuitElement
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
13
plugins/circuits/src/gates/BasicLogicGates.cpp
Normal file
13
plugins/circuits/src/gates/BasicLogicGates.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "BasicLogicGates.h"
|
||||||
|
|
||||||
|
AndLogicGate::AndLogicGate(Wire* input0, Wire* input1, Wire* output)
|
||||||
|
: TwoInOneOutLogicGate(input0, input1, output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
OrLogicGate::OrLogicGate(Wire* input0, Wire* input1, Wire* output)
|
||||||
|
: TwoInOneOutLogicGate(input0, input1, output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
45
plugins/circuits/src/gates/BasicLogicGates.h
Normal file
45
plugins/circuits/src/gates/BasicLogicGates.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "LogicGate.h"
|
||||||
|
|
||||||
|
class AndLogicGate : public TwoInOneOutLogicGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndLogicGate(Wire* input0 = nullptr, Wire* input1 = nullptr, Wire* output = nullptr);
|
||||||
|
|
||||||
|
virtual ~AndLogicGate() = default;
|
||||||
|
|
||||||
|
const TruthTable& getTruthTable()
|
||||||
|
{
|
||||||
|
return mTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
GateType getGateType() const
|
||||||
|
{
|
||||||
|
return GateType::AND;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TruthTable mTable{ TruthTable(2, 1) };
|
||||||
|
};
|
||||||
|
|
||||||
|
class OrLogicGate : public TwoInOneOutLogicGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OrLogicGate(Wire* input0 = nullptr, Wire* input1 = nullptr, Wire* output = nullptr);
|
||||||
|
|
||||||
|
virtual ~OrLogicGate() = default;
|
||||||
|
|
||||||
|
const TruthTable& getTruthTable()
|
||||||
|
{
|
||||||
|
return mTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
GateType getGateType() const
|
||||||
|
{
|
||||||
|
return GateType::OR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TruthTable mTable{ TruthTable(2, 1) };
|
||||||
|
};
|
96
plugins/circuits/src/gates/LogicGate.cpp
Normal file
96
plugins/circuits/src/gates/LogicGate.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#include "LogicGate.h"
|
||||||
|
|
||||||
|
NInMOutLogicGate::NInMOutLogicGate(std::size_t numIn, std::size_t numOut, std::vector<Wire*> inputs, std::vector<Wire*> outputs)
|
||||||
|
: LogicGate(),
|
||||||
|
mNumIn(numIn),
|
||||||
|
mNumOut(numOut)
|
||||||
|
{
|
||||||
|
if (inputs.size() == mNumIn)
|
||||||
|
{
|
||||||
|
mInputs = inputs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mInputs = std::vector<Wire*>(numIn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputs.size() == mNumOut)
|
||||||
|
{
|
||||||
|
mOutputs = outputs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mOutputs = std::vector<Wire*>(numOut, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t NInMOutLogicGate::getNumInputs() const
|
||||||
|
{
|
||||||
|
return mNumIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t NInMOutLogicGate::getNumOutputputs() const
|
||||||
|
{
|
||||||
|
return mNumOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire* NInMOutLogicGate::getInput(std::size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx < mNumIn)
|
||||||
|
{
|
||||||
|
return mInputs[idx];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire* NInMOutLogicGate::getOutput(std::size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx < mNumOut)
|
||||||
|
{
|
||||||
|
return mOutputs[idx];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NInMOutLogicGate::setAtInput(std::size_t idx, Wire* value)
|
||||||
|
{
|
||||||
|
if (idx < mInputs.size())
|
||||||
|
{
|
||||||
|
mInputs[idx] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NInMOutLogicGate::setAtOutput(std::size_t idx, Wire* value)
|
||||||
|
{
|
||||||
|
if (idx < mOutputs.size())
|
||||||
|
{
|
||||||
|
mOutputs[idx] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoInOneOutLogicGate::TwoInOneOutLogicGate(Wire* input0, Wire* input1, Wire* output)
|
||||||
|
: NInMOutLogicGate(2, 1, { input0, input1 }, {output})
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutLogicGate::setInput0(Wire* input)
|
||||||
|
{
|
||||||
|
setAtInput(0, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutLogicGate::setInput1(Wire* input)
|
||||||
|
{
|
||||||
|
setAtInput(1, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutLogicGate::setOutput(Wire* output)
|
||||||
|
{
|
||||||
|
setAtOutput(0, output);
|
||||||
|
}
|
78
plugins/circuits/src/gates/LogicGate.h
Normal file
78
plugins/circuits/src/gates/LogicGate.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CircuitElement.h"
|
||||||
|
#include "TruthTable.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class LogicGate : public CircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class GateType
|
||||||
|
{
|
||||||
|
NOT,
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
|
XOR,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
virtual ~LogicGate() = default;
|
||||||
|
|
||||||
|
virtual std::size_t getNumInputs() const = 0;
|
||||||
|
|
||||||
|
virtual std::size_t getNumOutputputs() const = 0;
|
||||||
|
|
||||||
|
virtual Wire* getInput(std::size_t idx) const = 0;
|
||||||
|
|
||||||
|
virtual Wire* getOutput(std::size_t idx) const = 0;
|
||||||
|
|
||||||
|
virtual const TruthTable& getTruthTable() = 0;
|
||||||
|
|
||||||
|
virtual GateType getGateType() const = 0;
|
||||||
|
|
||||||
|
Type getType() const override
|
||||||
|
{
|
||||||
|
return Type::LOGIC_GATE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NInMOutLogicGate : public LogicGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NInMOutLogicGate(std::size_t numIn, std::size_t numOut, std::vector<Wire*> inputs = {}, std::vector<Wire*> outputs = {});
|
||||||
|
|
||||||
|
virtual ~NInMOutLogicGate() = default;
|
||||||
|
|
||||||
|
std::size_t getNumInputs() const override;
|
||||||
|
|
||||||
|
std::size_t getNumOutputputs() const override;
|
||||||
|
|
||||||
|
Wire* getInput(std::size_t idx) const override;
|
||||||
|
|
||||||
|
Wire* getOutput(std::size_t idx) const override;
|
||||||
|
|
||||||
|
void setAtInput(std::size_t idx, Wire* value);
|
||||||
|
|
||||||
|
void setAtOutput(std::size_t idx, Wire* value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t mNumIn{ 1 };
|
||||||
|
std::size_t mNumOut{ 1 };
|
||||||
|
|
||||||
|
std::vector<Wire*> mInputs;
|
||||||
|
std::vector<Wire*> mOutputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TwoInOneOutLogicGate : public NInMOutLogicGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TwoInOneOutLogicGate(Wire* input0 = nullptr, Wire* input1 = nullptr, Wire* output = nullptr);
|
||||||
|
|
||||||
|
void setInput0(Wire* input);
|
||||||
|
|
||||||
|
void setInput1(Wire* input);
|
||||||
|
|
||||||
|
void setOutput(Wire* output);
|
||||||
|
};
|
72
plugins/circuits/src/visuals/ElectronicCircuitNode.cpp
Normal file
72
plugins/circuits/src/visuals/ElectronicCircuitNode.cpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#include "ElectronicCircuitNode.h"
|
||||||
|
|
||||||
|
#include "TerminalNode.h"
|
||||||
|
#include "WireNode.h"
|
||||||
|
#include "LogicGateNode.h"
|
||||||
|
|
||||||
|
ElectronicCircuitNode::ElectronicCircuitNode(const Transform& transform)
|
||||||
|
: AbstractVisualNode(transform)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuitNode::setContent(ElectronicCircuit* content)
|
||||||
|
{
|
||||||
|
mContent = content;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuitNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
mInputTerminalNodes.clear();
|
||||||
|
mWireNodes.clear();
|
||||||
|
mLogicGateNodes.clear();
|
||||||
|
|
||||||
|
// Layout terminals
|
||||||
|
double terminal_vertical_spacing = 100;
|
||||||
|
double terminal_left_margin = 10;
|
||||||
|
|
||||||
|
double terminal_y = 0;
|
||||||
|
for (auto terminal : mContent->getInputTerminals())
|
||||||
|
{
|
||||||
|
Point loc{ terminal_left_margin, terminal_y };
|
||||||
|
auto terminal_node = std::make_unique<TerminalNode>(Transform(loc));
|
||||||
|
|
||||||
|
terminal_node->setContent(terminal);
|
||||||
|
|
||||||
|
addChild(terminal_node.get());
|
||||||
|
mInputTerminalNodes.push_back(std::move(terminal_node));
|
||||||
|
|
||||||
|
terminal_y += terminal_vertical_spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout logic gates
|
||||||
|
double logic_gate_vertical_spacing = 100;
|
||||||
|
double logic_gate_horizontal_spacing = 100;
|
||||||
|
|
||||||
|
double gate_x = logic_gate_vertical_spacing;
|
||||||
|
double gate_y = 0;
|
||||||
|
for (auto gate : mContent->getLogicGates())
|
||||||
|
{
|
||||||
|
Point loc{ gate_x, gate_y };
|
||||||
|
auto gate_node = std::make_unique<LogicGateNode>(Transform(loc));
|
||||||
|
|
||||||
|
gate_node->setContent(gate);
|
||||||
|
|
||||||
|
addChild(gate_node.get());
|
||||||
|
mLogicGateNodes.push_back(std::move(gate_node));
|
||||||
|
|
||||||
|
gate_x += logic_gate_vertical_spacing;
|
||||||
|
gate_y += logic_gate_horizontal_spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElectronicCircuitNode::update(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (mContentDirty)
|
||||||
|
{
|
||||||
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
mContentDirty = false;
|
||||||
|
}
|
||||||
|
}
|
29
plugins/circuits/src/visuals/ElectronicCircuitNode.h
Normal file
29
plugins/circuits/src/visuals/ElectronicCircuitNode.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
#include "ElectronicCircuit.h"
|
||||||
|
|
||||||
|
class WireNode;
|
||||||
|
class TerminalNode;
|
||||||
|
class LogicGateNode;
|
||||||
|
|
||||||
|
class ElectronicCircuitNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ElectronicCircuitNode(const Transform& transform);
|
||||||
|
|
||||||
|
void setContent(ElectronicCircuit* content);
|
||||||
|
|
||||||
|
void update(SceneInfo* sceneInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
|
||||||
|
ElectronicCircuit* mContent{ nullptr };
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<TerminalNode> > mInputTerminalNodes;
|
||||||
|
std::vector<std::unique_ptr<WireNode> > mWireNodes;
|
||||||
|
std::vector<std::unique_ptr<LogicGateNode> > mLogicGateNodes;
|
||||||
|
};
|
49
plugins/circuits/src/visuals/LogicGateNode.cpp
Normal file
49
plugins/circuits/src/visuals/LogicGateNode.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include "LogicGateNode.h"
|
||||||
|
|
||||||
|
#include "Path.h"
|
||||||
|
#include "PathNode.h"
|
||||||
|
#include "CircleNode.h"
|
||||||
|
|
||||||
|
#include "LogicGate.h"
|
||||||
|
#include "LogicGatePrimitiveShapes.h"
|
||||||
|
|
||||||
|
LogicGateNode::LogicGateNode(const Transform& transform)
|
||||||
|
: AbstractVisualNode(transform)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicGateNode::setContent(LogicGate* content)
|
||||||
|
{
|
||||||
|
mContent = content;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicGateNode::update(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (mContentDirty)
|
||||||
|
{
|
||||||
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
mContentDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicGateNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (!mPrimaryPath)
|
||||||
|
{
|
||||||
|
if (mContent->getGateType() == LogicGate::GateType::AND)
|
||||||
|
{
|
||||||
|
mPrimaryPath = std::make_unique<PathNode>(Transform(), LogicGatePrimitiveShapes::getAndGateShape());
|
||||||
|
}
|
||||||
|
else if (mContent->getGateType() == LogicGate::GateType::OR)
|
||||||
|
{
|
||||||
|
mPrimaryPath = std::make_unique<PathNode>(Transform(), LogicGatePrimitiveShapes::getOrGateShape());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPrimaryPath)
|
||||||
|
{
|
||||||
|
addChild(mPrimaryPath.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
plugins/circuits/src/visuals/LogicGateNode.h
Normal file
25
plugins/circuits/src/visuals/LogicGateNode.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
class LogicGate;
|
||||||
|
class PathNode;
|
||||||
|
class CircleNode;
|
||||||
|
|
||||||
|
class LogicGateNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LogicGateNode(const Transform& transform);
|
||||||
|
|
||||||
|
void setContent(LogicGate* content);
|
||||||
|
|
||||||
|
void update(SceneInfo* sceneInfo);
|
||||||
|
private:
|
||||||
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
|
||||||
|
LogicGate* mContent{ nullptr };
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
|
||||||
|
std::unique_ptr<PathNode> mPrimaryPath;
|
||||||
|
std::unique_ptr<CircleNode> mNegationGlyph;
|
||||||
|
};
|
11
plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp
Normal file
11
plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "LogicGatePrimitiveShapes.h"
|
||||||
|
|
||||||
|
std::string LogicGatePrimitiveShapes::getAndGateShape()
|
||||||
|
{
|
||||||
|
return "M4 8 h24 a16 16 0 0 1 0 32 h-24Z";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LogicGatePrimitiveShapes::getOrGateShape()
|
||||||
|
{
|
||||||
|
return "M4 8 h16 q16 2 24 16 q-12 16 -24 16 h-16 q12 -16 0 -32Z";
|
||||||
|
}
|
11
plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h
Normal file
11
plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class LogicGatePrimitiveShapes
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string getAndGateShape();
|
||||||
|
|
||||||
|
static std::string getOrGateShape();
|
||||||
|
};
|
35
plugins/circuits/src/visuals/TerminalNode.cpp
Normal file
35
plugins/circuits/src/visuals/TerminalNode.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "TerminalNode.h"
|
||||||
|
|
||||||
|
#include "CircleNode.h"
|
||||||
|
|
||||||
|
TerminalNode::TerminalNode(const Transform& transform)
|
||||||
|
: AbstractVisualNode(transform)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalNode::setContent(Terminal* terminal)
|
||||||
|
{
|
||||||
|
mContent = terminal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (!mMarker)
|
||||||
|
{
|
||||||
|
mMarker = std::make_unique<CircleNode>(Transform{}, 5);
|
||||||
|
mMarker->setFillColor(Color(0, 0, 0));
|
||||||
|
mMarker->setHasStrokeColor(false);
|
||||||
|
|
||||||
|
addChild(mMarker.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalNode::update(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (mContentDirty)
|
||||||
|
{
|
||||||
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
mContentDirty = false;
|
||||||
|
}
|
||||||
|
}
|
24
plugins/circuits/src/visuals/TerminalNode.h
Normal file
24
plugins/circuits/src/visuals/TerminalNode.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
#include "Terminal.h"
|
||||||
|
|
||||||
|
class CircleNode;
|
||||||
|
|
||||||
|
class TerminalNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TerminalNode(const Transform& transform);
|
||||||
|
|
||||||
|
void setContent(Terminal* terminal);
|
||||||
|
|
||||||
|
void update(SceneInfo* sceneInfo) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
std::unique_ptr<CircleNode> mMarker;
|
||||||
|
|
||||||
|
Terminal* mContent{ nullptr };
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
};
|
0
plugins/circuits/src/visuals/WireNode.cpp
Normal file
0
plugins/circuits/src/visuals/WireNode.cpp
Normal file
6
plugins/circuits/src/visuals/WireNode.h
Normal file
6
plugins/circuits/src/visuals/WireNode.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class WireNode
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
9
plugins/circuits/test/CMakeLists.txt
Normal file
9
plugins/circuits/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
set(PLUGIN_NAME circuits)
|
||||||
|
|
||||||
|
list(APPEND UNIT_TEST_FILES
|
||||||
|
TestElectronicCircuit.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PLUGIN_NAME}_unit_tests ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES})
|
||||||
|
target_link_libraries(${PLUGIN_NAME}_unit_tests PUBLIC test_utils circuits)
|
||||||
|
set_property(TARGET ${PLUGIN_NAME}_unit_tests PROPERTY FOLDER plugins)
|
71
plugins/circuits/test/TestElectronicCircuit.cpp
Normal file
71
plugins/circuits/test/TestElectronicCircuit.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "TestFramework.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
#include "TestRenderUtils.h"
|
||||||
|
|
||||||
|
#include "ElectronicCircuit.h"
|
||||||
|
#include "ElectronicCircuitNode.h"
|
||||||
|
|
||||||
|
#include "BasicLogicGates.h"
|
||||||
|
|
||||||
|
TEST_CASE(TestElectronicCircuit, "circuits")
|
||||||
|
{
|
||||||
|
TestRenderer renderer(100, 100);
|
||||||
|
|
||||||
|
auto circuit = std::make_unique<ElectronicCircuit>();
|
||||||
|
|
||||||
|
// Add three labelled terminals (two in, one out)
|
||||||
|
auto input0 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "p");
|
||||||
|
auto input1 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "q");
|
||||||
|
auto input2 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "r");
|
||||||
|
|
||||||
|
auto output = std::make_unique<Terminal>(Terminal::TerminalType::OUTPUT, "s");
|
||||||
|
|
||||||
|
// Add gates
|
||||||
|
auto and_gate = std::make_unique<AndLogicGate>();
|
||||||
|
auto or_gate = std::make_unique<OrLogicGate>();
|
||||||
|
|
||||||
|
// Add wires
|
||||||
|
auto wire0 = std::make_unique<Wire>(input0.get(), and_gate.get());
|
||||||
|
auto wire1 = std::make_unique<Wire>(input1.get(), and_gate.get());
|
||||||
|
|
||||||
|
auto wire2 = std::make_unique<Wire>(and_gate.get(), or_gate.get());
|
||||||
|
auto wire3 = std::make_unique<Wire>(input2.get(), or_gate.get());
|
||||||
|
|
||||||
|
auto wire4 = std::make_unique<Wire>(or_gate.get(), output.get());
|
||||||
|
|
||||||
|
// Join wires
|
||||||
|
and_gate->setInput0(wire0.get());
|
||||||
|
and_gate->setInput1(wire1.get());
|
||||||
|
and_gate->setOutput(wire2.get());
|
||||||
|
|
||||||
|
or_gate->setInput0(wire2.get());
|
||||||
|
or_gate->setInput1(wire3.get());
|
||||||
|
or_gate->setOutput(wire4.get());
|
||||||
|
|
||||||
|
input0->setConnection(wire0.get());
|
||||||
|
input1->setConnection(wire1.get());
|
||||||
|
input2->setConnection(wire3.get());
|
||||||
|
output->setConnection(wire4.get());
|
||||||
|
|
||||||
|
// Add to circuit
|
||||||
|
circuit->addWire(std::move(wire0));
|
||||||
|
circuit->addWire(std::move(wire1));
|
||||||
|
circuit->addWire(std::move(wire2));
|
||||||
|
circuit->addWire(std::move(wire3));
|
||||||
|
|
||||||
|
circuit->addInputTerminal(std::move(input0));
|
||||||
|
circuit->addInputTerminal(std::move(input1));
|
||||||
|
circuit->addInputTerminal(std::move(input2));
|
||||||
|
|
||||||
|
circuit->addOutputTerminal(std::move(output));
|
||||||
|
|
||||||
|
circuit->addLogicGate(std::move(and_gate));
|
||||||
|
circuit->addLogicGate(std::move(or_gate));
|
||||||
|
|
||||||
|
auto circuit_node = std::make_unique<ElectronicCircuitNode>(Transform());
|
||||||
|
|
||||||
|
circuit_node->setContent(circuit.get());
|
||||||
|
|
||||||
|
renderer.getScene()->addNode(circuit_node.get());
|
||||||
|
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg");
|
||||||
|
}
|
|
@ -16,7 +16,11 @@ list(APPEND HEADERS
|
||||||
path/Path.h
|
path/Path.h
|
||||||
path/PathPostScriptConverter.h
|
path/PathPostScriptConverter.h
|
||||||
path/PathElement.h
|
path/PathElement.h
|
||||||
|
path/Arc.h
|
||||||
|
path/QuadraticBezierCurve.h
|
||||||
|
path/CubicBezierCurve.h
|
||||||
points/Point.h
|
points/Point.h
|
||||||
|
points/PointParser.h
|
||||||
points/PointCollection.h
|
points/PointCollection.h
|
||||||
points/DiscretePoint.h
|
points/DiscretePoint.h
|
||||||
primitives/Circle.h
|
primitives/Circle.h
|
||||||
|
@ -37,7 +41,11 @@ list(APPEND SOURCES
|
||||||
path/Path.cpp
|
path/Path.cpp
|
||||||
path/PathPostScriptConverter.cpp
|
path/PathPostScriptConverter.cpp
|
||||||
path/PathElement.cpp
|
path/PathElement.cpp
|
||||||
|
path/Arc.cpp
|
||||||
|
path/QuadraticBezierCurve.cpp
|
||||||
|
path/CubicBezierCurve.cpp
|
||||||
points/Point.cpp
|
points/Point.cpp
|
||||||
|
points/PointParser.cpp
|
||||||
points/PointCollection.cpp
|
points/PointCollection.cpp
|
||||||
points/DiscretePoint.cpp
|
points/DiscretePoint.cpp
|
||||||
primitives/Circle.cpp
|
primitives/Circle.cpp
|
||||||
|
|
74
src/base/geometry/path/Arc.cpp
Normal file
74
src/base/geometry/path/Arc.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "Arc.h"
|
||||||
|
|
||||||
|
#include "PointParser.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
Arc::Arc(const Point& startPoint, const Point& endPoint, double rX, double rY, double rotation, bool largeArc, bool sweep)
|
||||||
|
: mStartPoint(startPoint),
|
||||||
|
mEndPoint(endPoint),
|
||||||
|
mRx(rX),
|
||||||
|
mRy(rY),
|
||||||
|
mRotation(rotation),
|
||||||
|
mLargeArc(largeArc),
|
||||||
|
mSweep(sweep)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Arc::getFirstPoint() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Arc::getEndPoint() const
|
||||||
|
{
|
||||||
|
return mEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Arc::toPostScriptString(std::size_t precision) const
|
||||||
|
{
|
||||||
|
const auto large = mLargeArc ? "1" : "0";
|
||||||
|
const auto sweep = mSweep ? "1" : "0";
|
||||||
|
std::stringstream sstr;
|
||||||
|
if (precision > 0)
|
||||||
|
{
|
||||||
|
sstr.precision(precision);
|
||||||
|
}
|
||||||
|
sstr << (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO) ? "a" : "A";
|
||||||
|
sstr << mRx << " " << mRy << " " << mRotation << " " << large << " " << sweep << " ";
|
||||||
|
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO)
|
||||||
|
{
|
||||||
|
sstr << PointParser::toStringRelative(mEndPoint, mStartPoint, 2, " ", precision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sstr << PointParser::toString(mEndPoint, 2, " ", precision);
|
||||||
|
}
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bounds Arc::getBounds() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point& Arc::getLocation() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Arc::sample(SparseGrid<bool>* grid) const
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::Type Arc::getType() const
|
||||||
|
{
|
||||||
|
return Type::CURVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::CurveType Arc::getCurveType() const
|
||||||
|
{
|
||||||
|
return CurveType::ARC;
|
||||||
|
}
|
35
src/base/geometry/path/Arc.h
Normal file
35
src/base/geometry/path/Arc.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Curve.h"
|
||||||
|
#include "Point.h"
|
||||||
|
|
||||||
|
class Arc : public Curve
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Arc(const Point& startPoint, const Point& endPoint, double rX, double rY, double rotation = 0, bool largeArc = false, bool sweep = false);
|
||||||
|
|
||||||
|
Point getFirstPoint() const override;
|
||||||
|
|
||||||
|
Point getEndPoint() const override;
|
||||||
|
|
||||||
|
Bounds getBounds() const override;
|
||||||
|
|
||||||
|
const Point& getLocation() const override;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
CurveType getCurveType() const override;
|
||||||
|
|
||||||
|
void sample(SparseGrid<bool>* grid) const override;
|
||||||
|
|
||||||
|
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point mStartPoint;
|
||||||
|
Point mEndPoint;
|
||||||
|
double mRx{ 0.0 };
|
||||||
|
double mRy{ 0.0 };
|
||||||
|
double mRotation{ 0 };
|
||||||
|
bool mLargeArc{ false };
|
||||||
|
bool mSweep{ false };
|
||||||
|
};
|
65
src/base/geometry/path/CubicBezierCurve.cpp
Normal file
65
src/base/geometry/path/CubicBezierCurve.cpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include "CubicBezierCurve.h"
|
||||||
|
|
||||||
|
#include "PointParser.h"
|
||||||
|
|
||||||
|
CubicBezierCurve::CubicBezierCurve(const Point& startPoint, const Point& endPoint, const Point& startControlPoint, const Point& endControlPoint)
|
||||||
|
: mStartPoint(startPoint),
|
||||||
|
mEndPoint(endPoint),
|
||||||
|
mStartControlPoint(startControlPoint),
|
||||||
|
mEndControlPoint(endControlPoint)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Point CubicBezierCurve::getFirstPoint() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point CubicBezierCurve::getEndPoint() const
|
||||||
|
{
|
||||||
|
return mEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CubicBezierCurve::toPostScriptString(std::size_t precision) const
|
||||||
|
{
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO)
|
||||||
|
{
|
||||||
|
const auto start_control = PointParser::toStringRelative(mStartControlPoint, mStartPoint, 2, " ", precision);
|
||||||
|
const auto end_control = PointParser::toStringRelative(mEndControlPoint, mStartPoint, 2, " ", precision);
|
||||||
|
const auto end = PointParser::toStringRelative(mEndPoint, mStartPoint, 2, " ", precision);
|
||||||
|
return "c" + start_control + " " + end_control + " " + end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto start_control = PointParser::toString(mStartControlPoint, 2, " ", precision);
|
||||||
|
const auto end_control = PointParser::toString(mEndControlPoint, 2, " ", precision);
|
||||||
|
const auto end = PointParser::toString(mEndPoint, 2, " ", precision);
|
||||||
|
return "C" + start_control + " " + end_control + " " + end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bounds CubicBezierCurve::getBounds() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point& CubicBezierCurve::getLocation() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicBezierCurve::sample(SparseGrid<bool>* grid) const
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CubicBezierCurve::Type CubicBezierCurve::getType() const
|
||||||
|
{
|
||||||
|
return Type::CURVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CubicBezierCurve::CurveType CubicBezierCurve::getCurveType() const
|
||||||
|
{
|
||||||
|
return CurveType::CUBIC_BEZIER;
|
||||||
|
}
|
32
src/base/geometry/path/CubicBezierCurve.h
Normal file
32
src/base/geometry/path/CubicBezierCurve.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Curve.h"
|
||||||
|
#include "Point.h"
|
||||||
|
|
||||||
|
class CubicBezierCurve : public Curve
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CubicBezierCurve(const Point& startPoint, const Point& endPoint, const Point& startControlPoint, const Point& endControlPoint);
|
||||||
|
|
||||||
|
Point getFirstPoint() const override;
|
||||||
|
|
||||||
|
Point getEndPoint() const override;
|
||||||
|
|
||||||
|
Bounds getBounds() const override;
|
||||||
|
|
||||||
|
const Point& getLocation() const override;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
CurveType getCurveType() const override;
|
||||||
|
|
||||||
|
void sample(SparseGrid<bool>* grid) const override;
|
||||||
|
|
||||||
|
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point mStartPoint;
|
||||||
|
Point mEndPoint;
|
||||||
|
Point mStartControlPoint;
|
||||||
|
Point mEndControlPoint;
|
||||||
|
};
|
|
@ -8,6 +8,10 @@ public:
|
||||||
enum class CurveType
|
enum class CurveType
|
||||||
{
|
{
|
||||||
ARC,
|
ARC,
|
||||||
CUBIC_BEZIER
|
QUADRATIC_BEZIER,
|
||||||
|
CUBIC_BEZIER,
|
||||||
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual CurveType getCurveType() const = 0;
|
||||||
};
|
};
|
|
@ -1,5 +1,7 @@
|
||||||
#include "Line.h"
|
#include "Line.h"
|
||||||
|
|
||||||
|
#include "PointParser.h"
|
||||||
|
|
||||||
Line::Line(const Point& start, const PointCollection& points)
|
Line::Line(const Point& start, const PointCollection& points)
|
||||||
: mStartPoint(start),
|
: mStartPoint(start),
|
||||||
mPoints(points)
|
mPoints(points)
|
||||||
|
@ -62,14 +64,26 @@ Line::Line(const Point& start, InputBufferType bufferType, const std::vector<dou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Line::toPostScriptString() const
|
std::string Line::toPostScriptString(std::size_t precision) const
|
||||||
{
|
{
|
||||||
std::string path = "L ";
|
if (mPostscriptPositioning == PostscriptPositioning::ABSOLUTE_TO)
|
||||||
|
{
|
||||||
|
std::string path = "L";
|
||||||
for (const auto& point : mPoints.getPoints())
|
for (const auto& point : mPoints.getPoints())
|
||||||
{
|
{
|
||||||
path += std::to_string(point.getX()) + " " + std::to_string(point.getY()) + " ";
|
path += PointParser::toString(point, 2, " ", precision) + " ";
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string path = "l";
|
||||||
|
for (const auto& point : mPoints.getPoints())
|
||||||
|
{
|
||||||
|
path += PointParser::toStringRelative(point, mStartPoint, 2, " ", precision) + " ";
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Point Line::getFirstPoint() const
|
Point Line::getFirstPoint() const
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
|
|
||||||
void sample(SparseGrid<bool>* grid) const override {};
|
void sample(SparseGrid<bool>* grid) const override {};
|
||||||
|
|
||||||
std::string toPostScriptString() const override;
|
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Point mStartPoint;
|
Point mStartPoint;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "LineSegment.h"
|
#include "LineSegment.h"
|
||||||
|
|
||||||
|
#include "PointParser.h"
|
||||||
|
|
||||||
LineSegment::LineSegment(const Point& p0, const Point& p1)
|
LineSegment::LineSegment(const Point& p0, const Point& p1)
|
||||||
: mP0(p0),
|
: mP0(p0),
|
||||||
mP1(p1)
|
mP1(p1)
|
||||||
|
@ -32,9 +34,51 @@ void LineSegment::sample(SparseGrid<bool>* grid) const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LineSegment::toPostScriptString() const
|
std::string LineSegment::toPostScriptString(std::size_t precision) const
|
||||||
{
|
{
|
||||||
return "L " + std::to_string(mP1.getX()) + " " + std::to_string(mP1.getY());
|
if (isHorizontal())
|
||||||
|
{
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::ABSOLUTE_TO)
|
||||||
|
{
|
||||||
|
return "H" + PointParser::toString(mP1.getX(), precision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "h" + PointParser::toString(mP0.getDeltaX(mP1), precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isVertical())
|
||||||
|
{
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::ABSOLUTE_TO)
|
||||||
|
{
|
||||||
|
return "V" + PointParser::toString(mP1.getY(), precision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "v" + PointParser::toString(mP0.getDeltaY(mP1), precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::ABSOLUTE_TO)
|
||||||
|
{
|
||||||
|
return "L" + PointParser::toString(mP1, 2, " ", precision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "l" + PointParser::toStringRelative(mP1, mP0, 2, " ", precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LineSegment::isHorizontal() const
|
||||||
|
{
|
||||||
|
return mP0.getDeltaY(mP1) == 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LineSegment::isVertical() const
|
||||||
|
{
|
||||||
|
return mP0.getDeltaX(mP1) == 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bounds LineSegment::getBounds() const
|
Bounds LineSegment::getBounds() const
|
||||||
|
|
|
@ -17,8 +17,6 @@ public:
|
||||||
|
|
||||||
const Point& getPoint1() const;
|
const Point& getPoint1() const;
|
||||||
|
|
||||||
void sample(SparseGrid<bool>* grid) const override;
|
|
||||||
|
|
||||||
Bounds getBounds() const override;
|
Bounds getBounds() const override;
|
||||||
|
|
||||||
const Point& getLocation() const override;
|
const Point& getLocation() const override;
|
||||||
|
@ -27,10 +25,16 @@ public:
|
||||||
|
|
||||||
Point getEndPoint() const override;
|
Point getEndPoint() const override;
|
||||||
|
|
||||||
std::string toPostScriptString() const override;
|
|
||||||
|
|
||||||
Type getType() const override;
|
Type getType() const override;
|
||||||
|
|
||||||
|
bool isHorizontal() const;
|
||||||
|
|
||||||
|
bool isVertical() const;
|
||||||
|
|
||||||
|
void sample(SparseGrid<bool>* grid) const override;
|
||||||
|
|
||||||
|
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Point mP0;
|
Point mP0;
|
||||||
Point mP1;
|
Point mP1;
|
||||||
|
|
|
@ -7,11 +7,25 @@
|
||||||
class PathElement : public AbstractGeometricItem
|
class PathElement : public AbstractGeometricItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class PostscriptPositioning
|
||||||
|
{
|
||||||
|
RELATIVE_TO,
|
||||||
|
ABSOLUTE_TO
|
||||||
|
};
|
||||||
|
|
||||||
~PathElement();
|
~PathElement();
|
||||||
|
|
||||||
virtual Point getFirstPoint() const = 0;
|
virtual Point getFirstPoint() const = 0;
|
||||||
|
|
||||||
virtual Point getEndPoint() const = 0;
|
virtual Point getEndPoint() const = 0;
|
||||||
|
|
||||||
virtual std::string toPostScriptString() const = 0;
|
void setPostscriptPositioning(PostscriptPositioning positioning)
|
||||||
|
{
|
||||||
|
mPostscriptPositioning = positioning;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string toPostScriptString(std::size_t precision = 0) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PostscriptPositioning mPostscriptPositioning{ PostscriptPositioning::RELATIVE_TO};
|
||||||
};
|
};
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
#include "Line.h"
|
#include "Line.h"
|
||||||
#include "LineSegment.h"
|
#include "LineSegment.h"
|
||||||
|
#include "Arc.h"
|
||||||
|
#include "QuadraticBezierCurve.h"
|
||||||
|
#include "CubicBezierCurve.h"
|
||||||
|
|
||||||
void PathPostScriptConverter::fromPostScript(GeometryPath* targetPath, const std::string& postScriptPath)
|
void PathPostScriptConverter::fromPostScript(GeometryPath* targetPath, const std::string& postScriptPath)
|
||||||
{
|
{
|
||||||
|
@ -118,6 +121,18 @@ void PathPostScriptConverter::onElementEnd()
|
||||||
{
|
{
|
||||||
element = onLineTo();
|
element = onLineTo();
|
||||||
}
|
}
|
||||||
|
else if (mLineState == LineState::IN_ARC)
|
||||||
|
{
|
||||||
|
element = onArc();
|
||||||
|
}
|
||||||
|
else if (mLineState == LineState::IN_QUADRATIC_BEZIER)
|
||||||
|
{
|
||||||
|
element = onQuadraticBezier();
|
||||||
|
}
|
||||||
|
else if (mLineState == LineState::IN_CUBIC_BEZIER)
|
||||||
|
{
|
||||||
|
element = onCubicBezier();
|
||||||
|
}
|
||||||
else if (mLineState == LineState::IN_FIRST_POINT)
|
else if (mLineState == LineState::IN_FIRST_POINT)
|
||||||
{
|
{
|
||||||
onMoveTo();
|
onMoveTo();
|
||||||
|
@ -125,6 +140,8 @@ void PathPostScriptConverter::onElementEnd()
|
||||||
|
|
||||||
if (element)
|
if (element)
|
||||||
{
|
{
|
||||||
|
const auto positioning = (mPositionState == PositionState::RELATIVE) ? PathElement::PostscriptPositioning::RELATIVE_TO : PathElement::PostscriptPositioning::ABSOLUTE_TO;
|
||||||
|
element->setPostscriptPositioning(positioning);
|
||||||
mCurrentPoint = element->getEndPoint();
|
mCurrentPoint = element->getEndPoint();
|
||||||
mWorkingFeature->addElement(std::move(element));
|
mWorkingFeature->addElement(std::move(element));
|
||||||
}
|
}
|
||||||
|
@ -216,6 +233,85 @@ PathElementPtr PathPostScriptConverter::onLineTo()
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathElementPtr PathPostScriptConverter::onArc()
|
||||||
|
{
|
||||||
|
PathElementPtr element;
|
||||||
|
if (mPointBuffer.size() == 7)
|
||||||
|
{
|
||||||
|
double rx = mPointBuffer[0];
|
||||||
|
double ry = mPointBuffer[1];
|
||||||
|
double rotation = mPointBuffer[2];
|
||||||
|
bool large_arc = bool(mPointBuffer[3]);
|
||||||
|
bool sweep = bool(mPointBuffer[4]);
|
||||||
|
|
||||||
|
if (mPositionState == PositionState::RELATIVE)
|
||||||
|
{
|
||||||
|
const auto end_point = Point(mCurrentPoint.getX() + mPointBuffer[5], mCurrentPoint.getY() + mPointBuffer[6]);
|
||||||
|
element = std::make_unique<Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto end_point = Point(mPointBuffer[5], mPointBuffer[6]);
|
||||||
|
element = std::make_unique<Arc>(mCurrentPoint, end_point, rx, ry, rotation, large_arc, sweep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathElementPtr PathPostScriptConverter::onQuadraticBezier()
|
||||||
|
{
|
||||||
|
PathElementPtr element;
|
||||||
|
if (mPointBuffer.size() == 4)
|
||||||
|
{
|
||||||
|
double control_x = mPointBuffer[0];
|
||||||
|
double control_y = mPointBuffer[1];
|
||||||
|
double end_x = mPointBuffer[2];
|
||||||
|
bool end_y = mPointBuffer[3];
|
||||||
|
if (mPositionState == PositionState::RELATIVE)
|
||||||
|
{
|
||||||
|
const auto control_point = Point(mCurrentPoint.getX() + control_x, mCurrentPoint.getY() + control_y);
|
||||||
|
const auto end_point = Point(mCurrentPoint.getX() + end_x, mCurrentPoint.getY() + end_y);
|
||||||
|
element = std::make_unique<QuadraticBezierCurve>(mCurrentPoint, end_point, control_point);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto control_point = Point(control_x, control_y);
|
||||||
|
const auto end_point = Point(end_x, end_y);
|
||||||
|
element = std::make_unique<QuadraticBezierCurve>(mCurrentPoint, end_point, control_point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathElementPtr PathPostScriptConverter::onCubicBezier()
|
||||||
|
{
|
||||||
|
PathElementPtr element;
|
||||||
|
if (mPointBuffer.size() == 4)
|
||||||
|
{
|
||||||
|
double control0_x = mPointBuffer[0];
|
||||||
|
double control0_y = mPointBuffer[1];
|
||||||
|
double control1_x = mPointBuffer[0];
|
||||||
|
double control1_y = mPointBuffer[1];
|
||||||
|
double end_x = mPointBuffer[2];
|
||||||
|
bool end_y = mPointBuffer[3];
|
||||||
|
if (mPositionState == PositionState::RELATIVE)
|
||||||
|
{
|
||||||
|
const auto control_point0 = Point(mCurrentPoint.getX() + control0_x, mCurrentPoint.getY() + control0_y);
|
||||||
|
const auto control_point1 = Point(mCurrentPoint.getX() + control1_x, mCurrentPoint.getY() + control1_y);
|
||||||
|
const auto end_point = Point(mCurrentPoint.getX() + end_x, mCurrentPoint.getY() + end_y);
|
||||||
|
element = std::make_unique<CubicBezierCurve>(mCurrentPoint, end_point, control_point0, control_point1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto control_point0 = Point(control0_x, control0_y);
|
||||||
|
const auto control_point1 = Point(control1_x, control1_y);
|
||||||
|
const auto end_point = Point(end_x, end_y);
|
||||||
|
element = std::make_unique<CubicBezierCurve>(mCurrentPoint, end_point, control_point0, control_point1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
std::string PathPostScriptConverter::toPostScript(const GeometryPath* targetPath)
|
std::string PathPostScriptConverter::toPostScript(const GeometryPath* targetPath)
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -226,7 +322,7 @@ std::string PathPostScriptConverter::toPostScript(const GeometryPath* targetPath
|
||||||
|
|
||||||
for (const auto& path_element : feature->getElements())
|
for (const auto& path_element : feature->getElements())
|
||||||
{
|
{
|
||||||
path += " " + path_element->toPostScriptString();
|
path += " " + path_element->toPostScriptString(mPrecision);
|
||||||
}
|
}
|
||||||
path += "Z ";
|
path += "Z ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,10 @@ private:
|
||||||
PathElementPtr onVerticalLineTo();
|
PathElementPtr onVerticalLineTo();
|
||||||
PathElementPtr onLineTo();
|
PathElementPtr onLineTo();
|
||||||
|
|
||||||
|
PathElementPtr onArc();
|
||||||
|
PathElementPtr onQuadraticBezier();
|
||||||
|
PathElementPtr onCubicBezier();
|
||||||
|
|
||||||
LineState mLineState{ LineState::START };
|
LineState mLineState{ LineState::START };
|
||||||
PositionState mPositionState{ PositionState::ABSOLUTE };
|
PositionState mPositionState{ PositionState::ABSOLUTE };
|
||||||
std::string mBuffer;
|
std::string mBuffer;
|
||||||
|
@ -58,4 +62,6 @@ private:
|
||||||
|
|
||||||
GeometryPathFeaturePtr mWorkingFeature;
|
GeometryPathFeaturePtr mWorkingFeature;
|
||||||
Point mCurrentPoint;
|
Point mCurrentPoint;
|
||||||
|
|
||||||
|
std::size_t mPrecision{ 3 };
|
||||||
};
|
};
|
||||||
|
|
58
src/base/geometry/path/QuadraticBezierCurve.cpp
Normal file
58
src/base/geometry/path/QuadraticBezierCurve.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "QuadraticBezierCurve.h"
|
||||||
|
|
||||||
|
#include "PointParser.h"
|
||||||
|
|
||||||
|
QuadraticBezierCurve::QuadraticBezierCurve(const Point& startPoint, const Point& endPoint, const Point& controlPoint)
|
||||||
|
: mStartPoint(startPoint),
|
||||||
|
mEndPoint(endPoint),
|
||||||
|
mControlPoint(controlPoint)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Point QuadraticBezierCurve::getFirstPoint() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point QuadraticBezierCurve::getEndPoint() const
|
||||||
|
{
|
||||||
|
return mEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string QuadraticBezierCurve::toPostScriptString(std::size_t precision) const
|
||||||
|
{
|
||||||
|
if (mPostscriptPositioning == PostscriptPositioning::RELATIVE_TO)
|
||||||
|
{
|
||||||
|
return "q" + PointParser::toStringRelative(mControlPoint, mStartPoint, 2, " ", precision) + " " + PointParser::toStringRelative(mEndPoint, mStartPoint, 2, " ", precision);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "Q" + PointParser::toString(mControlPoint, 2, " ", precision) + " " + PointParser::toString(mEndPoint, 2, " ", precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bounds QuadraticBezierCurve::getBounds() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point& QuadraticBezierCurve::getLocation() const
|
||||||
|
{
|
||||||
|
return mStartPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadraticBezierCurve::sample(SparseGrid<bool>* grid) const
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QuadraticBezierCurve::Type QuadraticBezierCurve::getType() const
|
||||||
|
{
|
||||||
|
return Type::CURVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuadraticBezierCurve::CurveType QuadraticBezierCurve::getCurveType() const
|
||||||
|
{
|
||||||
|
return CurveType::QUADRATIC_BEZIER;
|
||||||
|
}
|
31
src/base/geometry/path/QuadraticBezierCurve.h
Normal file
31
src/base/geometry/path/QuadraticBezierCurve.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Curve.h"
|
||||||
|
#include "Point.h"
|
||||||
|
|
||||||
|
class QuadraticBezierCurve : public Curve
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QuadraticBezierCurve(const Point& startPoint, const Point& endPoint, const Point& controlPoint);
|
||||||
|
|
||||||
|
Point getFirstPoint() const override;
|
||||||
|
|
||||||
|
Point getEndPoint() const override;
|
||||||
|
|
||||||
|
Bounds getBounds() const override;
|
||||||
|
|
||||||
|
const Point& getLocation() const override;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
CurveType getCurveType() const override;
|
||||||
|
|
||||||
|
void sample(SparseGrid<bool>* grid) const override;
|
||||||
|
|
||||||
|
std::string toPostScriptString(std::size_t precision = 0) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point mStartPoint;
|
||||||
|
Point mEndPoint;
|
||||||
|
Point mControlPoint;
|
||||||
|
};
|
|
@ -31,9 +31,9 @@ Point::~Point()
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<Point> Point::Create(double x, double y, double z)
|
std::unique_ptr<Point> Point::Create(double x, double y, double z)
|
||||||
{
|
{
|
||||||
return std::make_shared<Point>(x, y, z);
|
return std::make_unique<Point>(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Point::getX() const
|
double Point::getX() const
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "Vector.h"
|
#include "Vector.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class Transform;
|
class Transform;
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ public:
|
||||||
|
|
||||||
~Point();
|
~Point();
|
||||||
|
|
||||||
static std::shared_ptr<Point> Create(double x, double y, double z = 0);
|
static std::unique_ptr<Point> Create(double x, double y, double z = 0);
|
||||||
|
|
||||||
void apply(const Transform& transform);
|
void apply(const Transform& transform);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
#include "Bounds.h"
|
#include "Bounds.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class PointCollection
|
class PointCollection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
66
src/base/geometry/points/PointParser.cpp
Normal file
66
src/base/geometry/points/PointParser.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "PointParser.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
std::string PointParser::toString(const Point& p, std::size_t dimensions, const std::string& delimiter, std::size_t precision)
|
||||||
|
{
|
||||||
|
return toString(p.getX(), p.getY(), p.getZ(), dimensions, delimiter, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PointParser::toStringRelative(const Point& p, const Point& relativeTo, std::size_t dimensions, const std::string& delimiter, std::size_t precision)
|
||||||
|
{
|
||||||
|
return toString(relativeTo.getDeltaX(p), relativeTo.getDeltaY(p), relativeTo.getDeltaZ(p), dimensions, delimiter, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PointParser::toString(double x, double y, double z, std::size_t dimensions, const std::string& delimiter, std::size_t precision)
|
||||||
|
{
|
||||||
|
if (precision == 0)
|
||||||
|
{
|
||||||
|
if (dimensions == 1)
|
||||||
|
{
|
||||||
|
return std::to_string(x);
|
||||||
|
}
|
||||||
|
else if (dimensions == 2)
|
||||||
|
{
|
||||||
|
return std::to_string(x) + delimiter + std::to_string(y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::to_string(x) + delimiter + std::to_string(y) + delimiter + std::to_string(z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr.precision(precision);
|
||||||
|
if (dimensions == 1)
|
||||||
|
{
|
||||||
|
sstr << x;
|
||||||
|
}
|
||||||
|
else if (dimensions == 2)
|
||||||
|
{
|
||||||
|
sstr << x << delimiter << y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sstr << x << delimiter << y << delimiter << z;
|
||||||
|
}
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PointParser::toString(double x, std::size_t precision)
|
||||||
|
{
|
||||||
|
if (precision == 0)
|
||||||
|
{
|
||||||
|
return std::to_string(x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr.precision(precision);
|
||||||
|
sstr << x;
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
src/base/geometry/points/PointParser.h
Normal file
18
src/base/geometry/points/PointParser.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Point.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PointParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static std::string toString(const Point& p, std::size_t dimensions = 3, const std::string& delimiter = " ", std::size_t precision = 0);
|
||||||
|
|
||||||
|
static std::string toStringRelative(const Point& p, const Point& relativeTo, std::size_t dimensions = 3, const std::string& delimiter = " ", std::size_t precision = 0);
|
||||||
|
|
||||||
|
static std::string toString(double x, double y, double z, std::size_t dimensions = 3, const std::string& delimiter = " ", std::size_t precision = 0);
|
||||||
|
|
||||||
|
static std::string toString(double x, std::size_t precision = 0);
|
||||||
|
};
|
Loading…
Reference in a new issue