diff options
author | rtk0c <[email protected]> | 2021-04-17 17:31:47 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-04-17 17:31:47 -0700 |
commit | dca1286661f61e51943863de8ce68849a9578363 (patch) | |
tree | ada6c32fdf9ebf11a2b302398e8de28f57e3de8a /core/src/Model/Workflow.cpp | |
parent | 4e5730e1fcef150ce2f13f52a278890589ca96ad (diff) |
Initial work on one-to-many/many-to-one connections
Diffstat (limited to 'core/src/Model/Workflow.cpp')
-rw-r--r-- | core/src/Model/Workflow.cpp | 238 |
1 files changed, 198 insertions, 40 deletions
diff --git a/core/src/Model/Workflow.cpp b/core/src/Model/Workflow.cpp index 385544e..588081d 100644 --- a/core/src/Model/Workflow.cpp +++ b/core/src/Model/Workflow.cpp @@ -1,31 +1,75 @@ #include "Workflow.hpp" +#include <algorithm> #include <cassert> #include <utility> WorkflowConnection::WorkflowConnection() - : Source{ WorkflowNode::kInvalidId } - , Destination{ WorkflowNode::kInvalidId } - , SourcePin{ -1 } - , DestinationPin{ -1 } { + : MultiConnections{} + , SingleConnection{ WorkflowNode::kInvalidId, -1 } + , ConnectionDirection{ OneToMany } { } bool WorkflowConnection::IsValid() const { - return Source != WorkflowNode::kInvalidId; + return SingleConnection.Node != WorkflowNode::kInvalidId; +} + +std::span<WorkflowConnection::ConnectionPoint> WorkflowConnection::GetSourcePoints() { + switch (ConnectionDirection) { + case ManyToOne: return MultiConnections; + case OneToMany: return { &SingleConnection, 1 }; + } +} + +std::span<const WorkflowConnection::ConnectionPoint> WorkflowConnection::GetSourcePoints() const { + switch (ConnectionDirection) { + case ManyToOne: return MultiConnections; + case OneToMany: return { &SingleConnection, 1 }; + } +} + +std::span<WorkflowConnection::ConnectionPoint> WorkflowConnection::GetDestinationPoints() { + switch (ConnectionDirection) { + case ManyToOne: return { &SingleConnection, 1 }; + case OneToMany: return MultiConnections; + } +} + +std::span<const WorkflowConnection::ConnectionPoint> WorkflowConnection::GetDestinationPoints() const { + switch (ConnectionDirection) { + case ManyToOne: return { &SingleConnection, 1 }; + case OneToMany: return MultiConnections; + } } bool WorkflowNode::InputPin::IsConstantConnection() const { - return ConnectionToConst; + return ConnectionToConst && IsConnected(); } bool WorkflowNode::InputPin::IsConnected() const { return Connection != WorkflowConnection::kInvalidId; } +BaseValue::Kind WorkflowNode::InputPin::GetMatchingType() const { + return MatchingType; +} + +WorkflowConnection::Direction WorkflowNode::InputPin::GetSupportedDirection() const { + return AllowsMultipleConnections ? WorkflowConnection::ManyToOne : WorkflowConnection::OneToMany; +} + bool WorkflowNode::OutputPin::IsConnected() const { return Connection != WorkflowConnection::kInvalidId; } +BaseValue::Kind WorkflowNode::OutputPin::GetMatchingType() const { + return MatchingType; +} + +WorkflowConnection::Direction WorkflowNode::OutputPin::GetSupportedDirection() const { + return AllowsMultipleConnections ? WorkflowConnection::OneToMany : WorkflowConnection::ManyToOne; +} + WorkflowNode::WorkflowNode(Type type, Kind kind) : mType{ type } , mKind{ kind } { @@ -91,14 +135,24 @@ void WorkflowNode::SwapInputPin(int a, int b) { auto& pinB = mInputs[b]; if (mWorkflow) { + // Delay assignment to ConnectionPoint::Pin so that the pinB loop (if it happens to run and looks in the same Connection) doesn't match the point updated in the pinA loop + using Pt = WorkflowConnection::ConnectionPoint; + Pt* pointA = nullptr; + Pt* pointB = nullptr; + if (pinA.IsConnected() && !pinA.IsConstantConnection()) { - auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); - conn.DestinationPin = b; + auto pts = mWorkflow->GetConnectionById(pinA.Connection)->GetDestinationPoints(); + auto it = std::find(pts.begin(), pts.end(), Pt{ mId, a }); + pointA = it == pts.end() ? nullptr : &*it; } if (pinB.IsConnected() && !pinB.IsConstantConnection()) { - auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); - conn.DestinationPin = a; + auto pts = mWorkflow->GetConnectionById(pinB.Connection)->GetDestinationPoints(); + auto it = std::find(pts.begin(), pts.end(), Pt{ mId, b }); + pointB = it == pts.end() ? nullptr : &*it; } + + if (pointA) pointA->Pin = b; + if (pointB) pointB->Pin = a; } std::swap(pinA, pinB); @@ -128,14 +182,23 @@ void WorkflowNode::SwapOutputPin(int a, int b) { auto& pinB = mOutputs[b]; if (mWorkflow) { + using Pt = WorkflowConnection::ConnectionPoint; + Pt* pointA = nullptr; + Pt* pointB = nullptr; + if (pinA.IsConnected()) { - auto& conn = *mWorkflow->GetConnectionById(pinA.Connection); - conn.SourcePin = b; + auto pts = mWorkflow->GetConnectionById(pinA.Connection)->GetSourcePoints(); + auto it = std::find(pts.begin(), pts.end(), Pt{ mId, a }); + pointA = it == pts.end() ? nullptr : &*it; } if (pinB.IsConnected()) { - auto& conn = *mWorkflow->GetConnectionById(pinB.Connection); - conn.SourcePin = a; + auto pts = mWorkflow->GetConnectionById(pinB.Connection)->GetSourcePoints(); + auto it = std::find(pts.begin(), pts.end(), Pt{ mId, b }); + pointB = it == pts.end() ? nullptr : &*it; } + + if (pointA) pointA->Pin = b; + if (pointB) pointB->Pin = a; } std::swap(pinA, pinB); @@ -170,43 +233,138 @@ void Workflow::RemoveStep(size_t id) { step->mId = WorkflowNode::kInvalidId; } -void Workflow::Connect(WorkflowNode& source, int sourceNode, WorkflowNode& destination, int destinationNode) { - if (source.mInputs[sourceNode].IsConnected()) { - DisconnectBySource(source, sourceNode); +bool Workflow::Connect(WorkflowNode& sourceNode, int sourcePin, WorkflowNode& destinationNode, int destinationPin) { + auto& src = sourceNode.mOutputs[sourcePin]; + auto& dst = destinationNode.mInputs[destinationPin]; + + // Equivalent to `if (o.GetSupportedDirection() != i.GetSupportedDirection()) return false;` + // Cannot connect two pins of different type + if (src.AllowsMultipleConnections == dst.AllowsMultipleConnections) return false; + // Would be same as `dst.GetSupportedDirection()` because we validated that they are the same above + auto direction = src.GetSupportedDirection(); + + // TODO check type + + using Pt = WorkflowConnection::ConnectionPoint; + Pt* srcConnPt; + Pt* dstConnPt; + size_t connId; + + switch (direction) { + case WorkflowConnection::ManyToOne: { + if (dst.IsConnected()) return false; + + WorkflowConnection* conn; + if (src.IsConnected()) { + conn = &mConnections[src.Connection]; + connId = src.Connection; + } else { + auto p = AllocWorkflowConnection(); + conn = &p.first; + connId = p.second; + } + + srcConnPt = &conn->MultiConnections.emplace_back(); + dstConnPt = &conn->SingleConnection; + } break; + + case WorkflowConnection::OneToMany: { + if (src.IsConnected()) return false; + + WorkflowConnection* conn; + if (dst.IsConnected()) { + conn = &mConnections[src.Connection]; + connId = src.Connection; + } else { + auto p = AllocWorkflowConnection(); + conn = &p.first; + connId = p.second; + } + + srcConnPt = &conn->SingleConnection; + dstConnPt = &conn->MultiConnections.emplace_back(); + } break; } - auto [conn, id] = AllocWorkflowConnection(); - conn.Source = source.GetId(); - conn.SourcePin = sourceNode; - conn.Destination = destination.GetId(); - conn.DestinationPin = destinationNode; + srcConnPt->Node = sourceNode.GetId(); + srcConnPt->Pin = sourcePin; + dstConnPt->Node = destinationNode.GetId(); + dstConnPt->Pin = destinationPin; - source.mInputs[sourceNode].Connection = id; - destination.mInputs[destinationNode].Connection = id; + src.Connection = connId; + dst.Connection = connId; + return true; } -void Workflow::DisconnectBySource(WorkflowNode& source, int sourceNode) { - auto& sn = source.mOutputs[sourceNode]; - if (!sn.IsConnected()) return; +bool Workflow::DisconnectBySource(WorkflowNode& sourceNode, int sourcePin) { + auto& sp = sourceNode.mOutputs[sourcePin]; + if (!sp.IsConnected()) return false; + + auto& conn = mConnections[sp.Connection]; + + using Pt = WorkflowConnection::ConnectionPoint; + switch (sp.GetSupportedDirection()) { + case WorkflowConnection::ManyToOne: { + // Recessive pin, remove ConnectionPoint associated with this pin only + + auto& vec = conn.MultiConnections; + vec.erase(std::remove(vec.begin(), vec.end(), Pt{ sourceNode.GetId(), sourcePin }), vec.end()); - auto& conn = mConnections[sn.Connection]; - auto& dn = mNodes[conn.Destination]->mInputs[conn.DestinationPin]; + sp.Connection = WorkflowConnection::kInvalidId; + } break; - sn.Connection = WorkflowConnection::kInvalidId; - dn.Connection = WorkflowConnection::kInvalidId; - conn = {}; + case WorkflowConnection::OneToMany: { + // Dominate pin, removes whole connection + + for (auto& pt : conn.MultiConnections) { + auto& node = *mNodes[pt.Node]; + node.mInputs[pt.Pin].Connection = WorkflowConnection::kInvalidId; + } + sp.Connection = WorkflowConnection::kInvalidId; + + conn = {}; + } break; + } + + return true; } -void Workflow::DisconnectByDestination(WorkflowNode& destination, int destinationNode) { - auto& dn = destination.mOutputs[destinationNode]; - if (!dn.IsConnected()) return; +bool Workflow::DisconnectByDestination(WorkflowNode& destinationNode, int destinationPin) { + auto& dp = destinationNode.mInputs[destinationPin]; + if (!dp.IsConnected()) return false; + if (dp.IsConstantConnection()) { + dp.ConnectionToConst = false; + dp.Connection = WorkflowConnection::kInvalidId; + return true; + } + + auto& conn = mConnections[dp.Connection]; - auto& conn = mConnections[dn.Connection]; - auto& sn = mNodes[conn.Source]->mInputs[conn.SourcePin]; + using Pt = WorkflowConnection::ConnectionPoint; + switch (dp.GetSupportedDirection()) { + case WorkflowConnection::ManyToOne: { + // Dominate pin, removes whole connection + + for (auto& pt : conn.MultiConnections) { + auto& node = *mNodes[pt.Node]; + node.mOutputs[pt.Pin].Connection = WorkflowConnection::kInvalidId; + } + dp.Connection = WorkflowConnection::kInvalidId; + + conn = {}; + } break; + + case WorkflowConnection::OneToMany: { + // Recessive pin, remove ConnectionPoint associated with this pin only + + auto& vec = conn.MultiConnections; + vec.erase(std::remove(vec.begin(), vec.end(), Pt{ destinationNode.GetId(), destinationPin }), vec.end()); + + dp.Connection = WorkflowConnection::kInvalidId; + } break; + } - sn.Connection = WorkflowConnection::kInvalidId; - dn.Connection = WorkflowConnection::kInvalidId; - conn = {}; + return true; } std::pair<WorkflowConnection&, size_t> Workflow::AllocWorkflowConnection() { |