diff --git a/plugins/circuits/src/CMakeLists.txt b/plugins/circuits/src/CMakeLists.txt index e878dd8..8223366 100644 --- a/plugins/circuits/src/CMakeLists.txt +++ b/plugins/circuits/src/CMakeLists.txt @@ -9,6 +9,7 @@ list(APPEND HEADERS gates/LogicGate.h gates/BasicLogicGates.h visuals/ElectronicCircuitNode.h + visuals/CircuitElementNode.h visuals/WireNode.h visuals/TerminalNode.h visuals/LogicGateNode.h @@ -24,6 +25,7 @@ list(APPEND SOURCES gates/BasicLogicGates.cpp gates/LogicGate.cpp visuals/ElectronicCircuitNode.cpp + visuals/CircuitElementNode.cpp visuals/WireNode.cpp visuals/TerminalNode.cpp visuals/LogicGateNode.cpp diff --git a/plugins/circuits/src/ElectronicCircuit.h b/plugins/circuits/src/ElectronicCircuit.h index f2fcd95..b24fe34 100644 --- a/plugins/circuits/src/ElectronicCircuit.h +++ b/plugins/circuits/src/ElectronicCircuit.h @@ -25,11 +25,21 @@ public: return mInputTerminals; } + const std::vector& getOutputTerminals() const + { + return mOutputTerminals; + } + const std::vector& getLogicGates() const { return mLogicGates; } + const std::vector& getWires() const + { + return mWires; + } + private: std::vector mInputTerminals; std::vector mOutputTerminals; diff --git a/plugins/circuits/src/gates/LogicGate.cpp b/plugins/circuits/src/gates/LogicGate.cpp index 97892af..fe1248b 100644 --- a/plugins/circuits/src/gates/LogicGate.cpp +++ b/plugins/circuits/src/gates/LogicGate.cpp @@ -29,7 +29,7 @@ std::size_t NInMOutLogicGate::getNumInputs() const return mNumIn; } -std::size_t NInMOutLogicGate::getNumOutputputs() const +std::size_t NInMOutLogicGate::getNumOutputs() const { return mNumOut; } diff --git a/plugins/circuits/src/gates/LogicGate.h b/plugins/circuits/src/gates/LogicGate.h index 2e242b7..6a6ef9a 100644 --- a/plugins/circuits/src/gates/LogicGate.h +++ b/plugins/circuits/src/gates/LogicGate.h @@ -22,7 +22,7 @@ public: virtual std::size_t getNumInputs() const = 0; - virtual std::size_t getNumOutputputs() const = 0; + virtual std::size_t getNumOutputs() const = 0; virtual Wire* getInput(std::size_t idx) const = 0; @@ -47,7 +47,7 @@ public: std::size_t getNumInputs() const override; - std::size_t getNumOutputputs() const override; + std::size_t getNumOutputs() const override; Wire* getInput(std::size_t idx) const override; diff --git a/plugins/circuits/src/visuals/CircuitElementNode.cpp b/plugins/circuits/src/visuals/CircuitElementNode.cpp new file mode 100644 index 0000000..913ce21 --- /dev/null +++ b/plugins/circuits/src/visuals/CircuitElementNode.cpp @@ -0,0 +1,12 @@ +#include "CircuitElementNode.h" + +CircuitElementNode::CircuitElementNode(const Transform& transform) + : AbstractVisualNode(transform) +{ + +} + +CircuitElementNode::~CircuitElementNode() +{ + +} \ No newline at end of file diff --git a/plugins/circuits/src/visuals/CircuitElementNode.h b/plugins/circuits/src/visuals/CircuitElementNode.h new file mode 100644 index 0000000..a7392f9 --- /dev/null +++ b/plugins/circuits/src/visuals/CircuitElementNode.h @@ -0,0 +1,15 @@ +#pragma once + +#include "AbstractVisualNode.h" + +class Wire; + +class CircuitElementNode : public AbstractVisualNode +{ +public: + CircuitElementNode(const Transform& transform); + + virtual ~CircuitElementNode(); + + virtual Point getConnectionLocation(Wire* wire) const = 0; +}; \ No newline at end of file diff --git a/plugins/circuits/src/visuals/ElectronicCircuitNode.cpp b/plugins/circuits/src/visuals/ElectronicCircuitNode.cpp index c3f78c9..1ef4608 100644 --- a/plugins/circuits/src/visuals/ElectronicCircuitNode.cpp +++ b/plugins/circuits/src/visuals/ElectronicCircuitNode.cpp @@ -4,6 +4,8 @@ #include "WireNode.h" #include "LogicGateNode.h" +#include "FileLogger.h" + ElectronicCircuitNode::ElectronicCircuitNode(const Transform& transform) : AbstractVisualNode(transform) { @@ -21,17 +23,48 @@ void ElectronicCircuitNode::setContent(ElectronicCircuit* content) mContentDirty = true; } +void ElectronicCircuitNode::buildWireConnections() +{ + mWireInputConnections.clear(); + mWireOutputConnections.clear(); + + for (auto terminal : mContent->getInputTerminals()) + { + mWireOutputConnections[terminal->getConnection()] = terminal; + } + + for (auto gate : mContent->getLogicGates()) + { + for (std::size_t idx = 0; idx < gate->getNumInputs(); idx++) + { + mWireInputConnections[gate->getInput(idx)] = gate; + } + + for (std::size_t idx = 0; idx < gate->getNumOutputs(); idx++) + { + mWireOutputConnections[gate->getOutput(idx)] = gate; + } + } + + for (auto terminal : mContent->getOutputTerminals()) + { + mWireInputConnections[terminal->getConnection()] = terminal; + } +} + void ElectronicCircuitNode::createOrUpdateGeometry(SceneInfo*) { mInputTerminalNodes.clear(); mWireNodes.clear(); mLogicGateNodes.clear(); + buildWireConnections(); + // Layout terminals double terminal_vertical_spacing = 100; double terminal_left_margin = 10; - double terminal_y = 0; + double terminal_y = 10; for (auto terminal : mContent->getInputTerminals()) { Point loc{ terminal_left_margin, terminal_y }; @@ -40,6 +73,8 @@ void ElectronicCircuitNode::createOrUpdateGeometry(SceneInfo*) terminal_node->setContent(terminal); addChild(terminal_node.get()); + + mNodesForContent[terminal] = terminal_node.get(); mInputTerminalNodes.push_back(std::move(terminal_node)); terminal_y += terminal_vertical_spacing; @@ -59,12 +94,48 @@ void ElectronicCircuitNode::createOrUpdateGeometry(SceneInfo*) gate_node->setContent(gate); addChild(gate_node.get()); + + mNodesForContent[gate] = gate_node.get(); mLogicGateNodes.push_back(std::move(gate_node)); gate_x += logic_gate_vertical_spacing; gate_y += logic_gate_horizontal_spacing; } + // Layout output terminals + terminal_y = 10; + double terminal_right_margin = 10; + unsigned width = 500; + for (auto terminal : mContent->getOutputTerminals()) + { + Point loc{ width - terminal_right_margin, terminal_y }; + auto node = std::make_unique(Transform(loc)); + + node->setContent(terminal); + + addChild(node.get()); + + mNodesForContent[terminal] = node.get(); + + mOutputTerminalNodes.push_back(std::move(node)); + + terminal_y += terminal_vertical_spacing; + } + + // Add wires + for (auto wire : mContent->getWires()) + { + auto start_node = mNodesForContent[mWireOutputConnections[wire]]; + auto end_node = mNodesForContent[mWireInputConnections[wire]]; + + auto wire_node = std::make_unique(Transform()); + wire_node->setInputLocation(start_node->getConnectionLocation(wire)); + wire_node->setOutputLocation(end_node->getConnectionLocation(wire)); + + addChild(wire_node.get()); + + mWireNodes.push_back(std::move(wire_node)); + } } void ElectronicCircuitNode::update(SceneInfo* sceneInfo) diff --git a/plugins/circuits/src/visuals/ElectronicCircuitNode.h b/plugins/circuits/src/visuals/ElectronicCircuitNode.h index 050359c..e38a4ee 100644 --- a/plugins/circuits/src/visuals/ElectronicCircuitNode.h +++ b/plugins/circuits/src/visuals/ElectronicCircuitNode.h @@ -4,9 +4,13 @@ #include "ElectronicCircuit.h" +#include + class WireNode; class TerminalNode; class LogicGateNode; +class Wire; +class CircuitElementNode; class ElectronicCircuitNode : public AbstractVisualNode { @@ -22,10 +26,18 @@ public: private: void createOrUpdateGeometry(SceneInfo* sceneInfo); + void buildWireConnections(); + ElectronicCircuit* mContent{ nullptr }; bool mContentDirty{ true }; std::vector > mInputTerminalNodes; + std::vector > mOutputTerminalNodes; std::vector > mWireNodes; std::vector > mLogicGateNodes; + + std::unordered_map mWireInputConnections; + std::unordered_map mWireOutputConnections; + + std::unordered_map mNodesForContent; }; diff --git a/plugins/circuits/src/visuals/LogicGateNode.cpp b/plugins/circuits/src/visuals/LogicGateNode.cpp index 245d93d..b234484 100644 --- a/plugins/circuits/src/visuals/LogicGateNode.cpp +++ b/plugins/circuits/src/visuals/LogicGateNode.cpp @@ -8,7 +8,7 @@ #include "LogicGatePrimitiveShapes.h" LogicGateNode::LogicGateNode(const Transform& transform) - : AbstractVisualNode(transform) + : CircuitElementNode(transform) { } @@ -18,6 +18,45 @@ LogicGateNode::~LogicGateNode() } +Point LogicGateNode::getConnectionLocation(Wire* wire) const +{ + bool is_input{ false }; + std::size_t connection_id{ 0 }; + + for (std::size_t idx = 0; idx < mContent->getNumInputs(); idx++) + { + if (mContent->getInput(idx) == wire) + { + is_input = true; + connection_id = idx; + break; + } + } + + for (std::size_t idx = 0; idx < mContent->getNumOutputs(); idx++) + { + if (mContent->getOutput(idx) == wire) + { + connection_id = idx; + break; + } + } + + Point loc; + if (mContent->getGateType() == LogicGate::GateType::AND) + { + loc = LogicGatePrimitiveShapes::getAndGateConnectionLocation(is_input, connection_id); + } + else if (mContent->getGateType() == LogicGate::GateType::OR) + { + loc = LogicGatePrimitiveShapes::getOrGateConnectionLocation(is_input, connection_id); + } + + loc.move(mTransform.getLocation().getX(), mTransform.getLocation().getY()); + return loc; + +} + void LogicGateNode::setContent(LogicGate* content) { mContent = content; diff --git a/plugins/circuits/src/visuals/LogicGateNode.h b/plugins/circuits/src/visuals/LogicGateNode.h index ae0e643..2cf172f 100644 --- a/plugins/circuits/src/visuals/LogicGateNode.h +++ b/plugins/circuits/src/visuals/LogicGateNode.h @@ -1,19 +1,21 @@ #pragma once -#include "AbstractVisualNode.h" +#include "CircuitElementNode.h" #include "CircleNode.h" class LogicGate; class PathNode; -class LogicGateNode : public AbstractVisualNode +class LogicGateNode : public CircuitElementNode { public: LogicGateNode(const Transform& transform); virtual ~LogicGateNode(); + Point getConnectionLocation(Wire* wire) const override; + void setContent(LogicGate* content); void update(SceneInfo* sceneInfo); diff --git a/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp b/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp index e662774..06b6a30 100644 --- a/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp +++ b/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.cpp @@ -5,7 +5,45 @@ std::string LogicGatePrimitiveShapes::getAndGateShape() return "M4 8 h24 a16 16 0 0 1 0 32 h-24Z"; } +Point LogicGatePrimitiveShapes::getAndGateConnectionLocation(bool isInput, std::size_t idx) +{ + if (isInput) + { + if (idx == 0) + { + return { 4.0, 18.66 }; + } + else + { + return { 4.0, 29.33 }; + } + } + else + { + return {44.0, 24.0}; + } +} + std::string LogicGatePrimitiveShapes::getOrGateShape() { return "M4 8 h16 q16 2 24 16 q-12 16 -24 16 h-16 q12 -16 0 -32Z"; +} + +Point LogicGatePrimitiveShapes::getOrGateConnectionLocation(bool isInput, std::size_t idx) +{ + if (isInput) + { + if (idx == 0) + { + return { 8.0, 18.66 }; + } + else + { + return { 8.0, 29.33 }; + } + } + else + { + return { 44.0, 24.0 }; + } } \ No newline at end of file diff --git a/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h b/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h index 88d9e63..64ac11a 100644 --- a/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h +++ b/plugins/circuits/src/visuals/LogicGatePrimitiveShapes.h @@ -1,11 +1,17 @@ #pragma once +#include "Point.h" + #include class LogicGatePrimitiveShapes { public: + static Point getAndGateConnectionLocation(bool isInput, std::size_t idx); + static std::string getAndGateShape(); + static Point getOrGateConnectionLocation(bool isInput, std::size_t idx); + static std::string getOrGateShape(); }; \ No newline at end of file diff --git a/plugins/circuits/src/visuals/TerminalNode.cpp b/plugins/circuits/src/visuals/TerminalNode.cpp index 8265e84..95cb1ac 100644 --- a/plugins/circuits/src/visuals/TerminalNode.cpp +++ b/plugins/circuits/src/visuals/TerminalNode.cpp @@ -3,7 +3,7 @@ #include "CircleNode.h" TerminalNode::TerminalNode(const Transform& transform) - : AbstractVisualNode(transform) + : CircuitElementNode(transform) { } @@ -17,7 +17,7 @@ void TerminalNode::createOrUpdateGeometry(SceneInfo*) { if (!mMarker) { - mMarker = std::make_unique(Transform{}, 5); + mMarker = std::make_unique(Transform{}, 3); mMarker->setFillColor(Color(0, 0, 0)); mMarker->setHasStrokeColor(false); @@ -33,3 +33,8 @@ void TerminalNode::update(SceneInfo* sceneInfo) mContentDirty = false; } } + +Point TerminalNode::getConnectionLocation(Wire*) const +{ + return mTransform.getLocation(); +} diff --git a/plugins/circuits/src/visuals/TerminalNode.h b/plugins/circuits/src/visuals/TerminalNode.h index 57bc652..c505119 100644 --- a/plugins/circuits/src/visuals/TerminalNode.h +++ b/plugins/circuits/src/visuals/TerminalNode.h @@ -1,16 +1,18 @@ #pragma once -#include "AbstractVisualNode.h" +#include "CircuitElementNode.h" #include "Terminal.h" class CircleNode; -class TerminalNode : public AbstractVisualNode +class TerminalNode : public CircuitElementNode { public: TerminalNode(const Transform& transform); + Point getConnectionLocation(Wire* wire) const override; + void setContent(Terminal* terminal); void update(SceneInfo* sceneInfo) override; diff --git a/plugins/circuits/src/visuals/WireNode.cpp b/plugins/circuits/src/visuals/WireNode.cpp index e69de29..b245215 100644 --- a/plugins/circuits/src/visuals/WireNode.cpp +++ b/plugins/circuits/src/visuals/WireNode.cpp @@ -0,0 +1,69 @@ +#include "WireNode.h" + +#include "LineNode.h" + +WireNode::WireNode(const Transform& transform) + : AbstractVisualNode(transform) +{ + +} + +void WireNode::setContent(Wire* wire) +{ + mContent = wire; + mContentDirty = true; +} + +void WireNode::setInputLocation(const Point& point) +{ + if (mInputLocation != point) + { + mContentDirty = true; + mInputLocation = point; + } +} + +void WireNode::setOutputLocation(const Point& point) +{ + if (mOutputLocation != point) + { + mContentDirty = true; + mOutputLocation = point; + } +} + +void WireNode::update(SceneInfo* sceneInfo) +{ + if (mContentDirty) + { + createOrUpdateGeometry(sceneInfo); + mContentDirty = false; + } +} + +void WireNode::createOrUpdateGeometry(SceneInfo*) +{ + if (!mLine) + { + auto loc = mOutputLocation; + loc.move(-mInputLocation.getX(), -mInputLocation.getY(), -mInputLocation.getZ()); + + std::vector points; + + if (loc.getY() == 0.0) + { + points = { loc }; + } + else + { + auto join0 = Point(loc.getX() * 3.0 / 4.0, 0.0); + auto join1 = Point(loc.getX() * 3.0 / 4.0, loc.getY()); + points = { join0, join1 , loc}; + } + + + mLine = std::make_unique(Transform(mInputLocation), points); + + addChild(mLine.get()); + } +} \ No newline at end of file diff --git a/plugins/circuits/src/visuals/WireNode.h b/plugins/circuits/src/visuals/WireNode.h index abed051..c042aa3 100644 --- a/plugins/circuits/src/visuals/WireNode.h +++ b/plugins/circuits/src/visuals/WireNode.h @@ -1,6 +1,30 @@ #pragma once -class WireNode -{ +#include "AbstractVisualNode.h" +#include "Wire.h" + +class LineNode; + +class WireNode : public AbstractVisualNode +{ +public: + WireNode(const Transform& transform); + + void setContent(Wire* wire); + + void setInputLocation(const Point& point); + + void setOutputLocation(const Point& point); + + void update(SceneInfo* sceneInfo); +private: + void createOrUpdateGeometry(SceneInfo* sceneInfo); + Wire* mContent{ nullptr }; + bool mContentDirty{ true }; + + Point mInputLocation; + Point mOutputLocation; + + std::unique_ptr mLine; }; \ No newline at end of file diff --git a/plugins/circuits/test/TestElectronicCircuit.cpp b/plugins/circuits/test/TestElectronicCircuit.cpp index f0fd27c..c01018b 100644 --- a/plugins/circuits/test/TestElectronicCircuit.cpp +++ b/plugins/circuits/test/TestElectronicCircuit.cpp @@ -52,6 +52,7 @@ TEST_CASE(TestElectronicCircuit, "circuits") circuit->addWire(std::move(wire1)); circuit->addWire(std::move(wire2)); circuit->addWire(std::move(wire3)); + circuit->addWire(std::move(wire4)); circuit->addInputTerminal(std::move(input0)); circuit->addInputTerminal(std::move(input1));