/// <summary> /// Adds an index to the specified node's name. The new name will be the first available one of the row NodeName, NodeName 2, NodeName 3, NodeName 4... /// </summary> public void AddNode(Node node) { bool nameIsFree = false; // walk through nodes and look for first free index for (int i = 1; i <= (Nodes.Count + 1) && !nameIsFree; i++) { nameIsFree = true; foreach (Node existingNode in Nodes) { if (i == 1 && node.Name == existingNode.Name) { nameIsFree = false; } else if (i > 1 && (node.Name + " " + i) == existingNode.Name) { nameIsFree = false; } } // special case: "NodeName 1" shall be known as "NodeName" if (nameIsFree && i > 1) { node.Name += " " + i; } } if (node is InputNode) { NotifyOfPropertyChange(() => TickCount); node.PropertyChanged += (sender, e) => { if (e.PropertyName == "TickCount") NotifyOfPropertyChange(() => TickCount); }; } Nodes.Add(node); }
/// <summary> /// Returns true and adds the edge iff the specified directed edge does not lead to a cycle. /// </summary> public bool AddEdge(Node.Output source, Node.Input sink) { IEnumerable<Node> nodeList = DepthFirstSearch(source.Node); // if sink can be reached after starting dfs at the source the new edge would create a cycle if (nodeList.Any(node => node.Inputs.Contains(sink))) { return false; } else { sink.Source = source; return true; } }
public SaveNodeOutputViewModel(Node.Output output, Stream stream, PipelineState model) { this.model = model; IEnumerable<Frame> frames = model.Driver.RenderTicks(new[] { output.Node }, 0, TickCount, cts.Token) .Do(_ => { CurrentTick++; NotifyOfPropertyChange(() => CurrentTick); }) .Select(dic => dic[output]) .ToEnumerable(); Task.Factory.StartNew(() => { using (stream) YuvEncoder.Encode(stream, frames); TryClose(); }); }
public NodeViewModel(Node model, PipelineViewModel parent) { fake = new InOutputViewModel(model: null, parent: this); Model = model; NodeType = new NodeType { Type = model.GetType() }; Parent = parent; ZIndex = 0; inputs = Model.Inputs.Select(i => new InOutputViewModel(i, this)).ToList(); Outputs = Model.Outputs.Select(i => new InOutputViewModel(i, this)).ToList(); if (Model.Outputs is INotifyCollectionChanged) ((INotifyCollectionChanged)Model.Outputs).CollectionChanged += delegate { Outputs = Model.Outputs.Select(i => new InOutputViewModel(i, this)).ToList(); NotifyOfPropertyChange(() => Outputs); NotifyOfPropertyChange(() => HasOutputs); Parent.NotifyOfPropertyChange(() => Parent.Edges); }; }
/// <summary> /// Constructs an output that belongs to the specified node. /// </summary> public Output(Node node) { Node = node; }
/// <summary> /// Renders an output into a user-chosen file. /// </summary> public IEnumerable<IResult> SaveNodeOutput(Node.Output output) { var file = new ChooseFileResult { Filter = "YUV-Video|*.yuv", OpenReadOnly = false }; yield return file; IoC.Get<IWindowManager>().ShowDialog(new SaveNodeOutputViewModel(output, file.Stream(), Parent.Parent.Model)); }
public Node.Input AddInput(Node.Output source) { var input = new Node.Input { Source = source }; Model.Inputs.Add(input); inputs.Add(new InOutputViewModel(input, this)); NotifyOfPropertyChange(() => Inputs); return input; }
/// <summary> /// Opens a new output window for a node output. /// </summary> public void ShowNodeOutput(Node.Output output) { Parent.Parent.OpenWindow(new VideoOutputViewModel(output)); }
/// <summary> /// Returns true iff an edge between the specified nodes does not lead to a cycle. /// </summary> public bool CanAddEdge(Node source, Node sink) { return !DepthFirstSearch(source).Contains(sink); }
// Recursive part of the depth first search. private void Visit(Node node, LinkedList<Node> nodeList, HashSet<Node> visited) { if (node.Inputs != null) { foreach (Node.Input input in node.Inputs) { if (input.Source != null) { Node child = input.Source.Node; if (nodeList.Contains(child) && visited.Contains(child)) { // cancel further search here, since a cycle has been found return; } else if (!nodeList.Contains(child)) { nodeList.AddLast(child); visited.Add(child); if (child.Inputs != null) { Visit(child, nodeList, visited); } } } } } visited.Remove(node); }
// Recursive part of NumberOfFramesToPrecompute. private int NumberOfTicksToPrecompute(Node startNode) { int framesToPrecompute = 0; if (startNode.Inputs != null) { foreach (Node.Input input in startNode.Inputs) { if (input.Source != null) { framesToPrecompute = Math.Max(framesToPrecompute, NumberOfTicksToPrecompute(input.Source.Node)); } } } framesToPrecompute += startNode.NumberOfTicksToPrecompute; return framesToPrecompute; }
/// <summary> /// Returns a list which contains all nodes which can be reached from the start node. /// </summary> public IEnumerable<Node> DepthFirstSearch(Node startNode) { LinkedList<Node> nodeList = new LinkedList<Node>(); HashSet<Node> visited = new HashSet<Node>(); nodeList.AddFirst(startNode); visited.Add(startNode); Visit(startNode, nodeList, visited); return nodeList; }
/// <summary> /// Removes the specified node from the node list and removes all edges connected with the node. /// </summary> public void RemoveNode(Node node) { this.Nodes.Remove(node); foreach (Node checkedNode in Nodes) { foreach (Node.Input potentialDependency in checkedNode.Inputs) { if (potentialDependency.Source != null && potentialDependency.Source.Node == node) { // delete edge to node potentialDependency.Source = null; } } } NotifyOfPropertyChange(() => TickCount); }
/// <summary> /// Gets the frame rendered for the given output or null if the output hasn't been rendered. /// </summary> public Frame this[Node.Output output] { get { return dic.ContainsKey(output) ? dic[output] : null; } }