protected override void BuildAstForPartialMultiOutput( NodeModel model, AssociativeNode rhs, List<AssociativeNode> resultAst) { base.BuildAstForPartialMultiOutput(model, rhs, resultAst); var emptyList = AstFactory.BuildExprList(new List<AssociativeNode>()); var previewIdInit = AstFactory.BuildAssignment(model.AstIdentifierForPreview, emptyList); resultAst.Add(previewIdInit); resultAst.AddRange( Definition.ReturnKeys.Select( (rtnKey, idx) => AstFactory.BuildAssignment( AstFactory.BuildIdentifier( model.AstIdentifierForPreview.Name, AstFactory.BuildStringNode(rtnKey)), model.GetAstIdentifierForOutputIndex(idx)))); }
/// <summary> /// Returns the names of all the variables defined in this code block. /// </summary> /// <returns>List containing all the names</returns> public List<string> GetDefinedVariableNames() { var defVarNames = new List<string>(); // For unbound identifier, ideally if there is an input connect // to it, it is defined variable. But here we have to be more // aggresive. For copy/paste, the connectors haven't been // created yet, so if a variable is defined in other CBN, even // that variable is defined in this CBN, it is not included in // the return value. defVarNames.AddRange(inputIdentifiers); // Then get all variabled on the LHS of the statements foreach (Statement stmnt in codeStatements) { defVarNames.AddRange(Statement.GetDefinedVariableNames(stmnt, true)); } return defVarNames; }
void DeleteModelImpl(DeleteModelCommand command) { var modelsToDelete = new List<ModelBase>(); if (command.ModelGuid == Guid.Empty) { // When nothing is specified then it means all selected models. modelsToDelete.AddRange(DynamoSelection.Instance.Selection.OfType<ModelBase>()); } else { modelsToDelete.AddRange(command.ModelGuids.Select(guid => CurrentWorkspace.GetModelInternal(guid))); } DeleteModelInternal(modelsToDelete); }
/// <summary> /// Paste ISelectable objects from the clipboard to the workspace. /// </summary> public void Paste() { //clear the selection so we can put the //paste contents in DynamoSelection.Instance.ClearSelection(); //make a lookup table to store the guids of the //old models and the guids of their pasted versions var modelLookup = new Dictionary<Guid, ModelBase>(); //make a list of all newly created models so that their //creations can be recorded in the undo recorder. var createdModels = new List<ModelBase>(); var nodes = ClipBoard.OfType<NodeModel>(); var connectors = ClipBoard.OfType<ConnectorModel>(); var notes = ClipBoard.OfType<NoteModel>(); var annotations = ClipBoard.OfType<AnnotationModel>(); var minX = Double.MaxValue; var minY = Double.MaxValue; // Create the new NoteModel's var newNoteModels = new List<NoteModel>(); foreach (var note in notes) { var noteModel = new NoteModel(note.X, note.Y, note.Text, Guid.NewGuid()); //Store the old note as Key and newnote as value. modelLookup.Add(note.GUID,noteModel); newNoteModels.Add(noteModel); minX = Math.Min(note.X, minX); minY = Math.Min(note.Y, minY); } var xmlDoc = new XmlDocument(); // Create the new NodeModel's var newNodeModels = new List<NodeModel>(); foreach (var node in nodes) { NodeModel newNode; if (CurrentWorkspace is HomeWorkspaceModel && (node is Symbol || node is Output)) { var symbol = (node is Symbol ? (node as Symbol).InputSymbol : (node as Output).Symbol); var code = (string.IsNullOrEmpty(symbol) ? "x" : symbol) + ";"; newNode = new CodeBlockNodeModel(code, node.X, node.Y, LibraryServices, CurrentWorkspace.ElementResolver); } else { var dynEl = node.Serialize(xmlDoc, SaveContext.Copy); newNode = NodeFactory.CreateNodeFromXml(dynEl, SaveContext.Copy, CurrentWorkspace.ElementResolver); } var lacing = node.ArgumentLacing.ToString(); newNode.UpdateValue(new UpdateValueParams("ArgumentLacing", lacing)); if (!string.IsNullOrEmpty(node.NickName)) newNode.NickName = node.NickName; modelLookup.Add(node.GUID, newNode); newNodeModels.Add( newNode ); minX = Math.Min(node.X, minX); minY = Math.Min(node.Y, minY); } // Move all of the notes and nodes such that they are aligned with // the top left of the workspace var workspaceX = -CurrentWorkspace.X / CurrentWorkspace.Zoom; var workspaceY = -CurrentWorkspace.Y / CurrentWorkspace.Zoom; // Provide a small offset when pasting so duplicate pastes aren't directly on top of each other CurrentWorkspace.IncrementPasteOffset(); var shiftX = workspaceX - minX + CurrentWorkspace.CurrentPasteOffset; var shiftY = workspaceY - minY + CurrentWorkspace.CurrentPasteOffset; foreach (var model in newNodeModels.Concat<ModelBase>(newNoteModels)) { model.X = model.X + shiftX; model.Y = model.Y + shiftY; } // Add the new NodeModel's to the Workspace foreach (var newNode in newNodeModels) { CurrentWorkspace.AddAndRegisterNode(newNode, false); createdModels.Add(newNode); AddToSelection(newNode); } // TODO: is this required? OnRequestLayoutUpdate(this, EventArgs.Empty); // Add the new NoteModel's to the Workspace foreach (var newNote in newNoteModels) { CurrentWorkspace.AddNote(newNote, false); createdModels.Add(newNote); AddToSelection(newNote); } ModelBase start; ModelBase end; var newConnectors = from c in connectors // If the guid is in nodeLookup, then we connect to the new pasted node. Otherwise we // re-connect to the original. let startNode = modelLookup.TryGetValue(c.Start.Owner.GUID, out start) ? start as NodeModel : CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == c.Start.Owner.GUID) let endNode = modelLookup.TryGetValue(c.End.Owner.GUID, out end) ? end as NodeModel : CurrentWorkspace.Nodes.FirstOrDefault(x => x.GUID == c.End.Owner.GUID) // Don't make a connector if either end is null. where startNode != null && endNode != null select ConnectorModel.Make(startNode, endNode, c.Start.Index, c.End.Index); createdModels.AddRange(newConnectors); //Grouping depends on the selected node models. //so adding the group after nodes / notes are added to workspace. //select only those nodes that are part of a group. var newAnnotations = new List<AnnotationModel>(); foreach (var annotation in annotations) { var annotationNodeModel = new List<NodeModel>(); var annotationNoteModel = new List<NoteModel>(); //checked condition here that supports pasting of multiple groups foreach (var models in annotation.SelectedModels) { ModelBase mbase; modelLookup.TryGetValue(models.GUID, out mbase); if (mbase is NodeModel) { annotationNodeModel.Add(mbase as NodeModel); } if (mbase is NoteModel) { annotationNoteModel.Add(mbase as NoteModel); } } var annotationModel = new AnnotationModel(annotationNodeModel, annotationNoteModel) { GUID = Guid.NewGuid(), AnnotationText = annotation.AnnotationText, Background = annotation.Background, FontSize = annotation.FontSize }; newAnnotations.Add(annotationModel); } // Add the new Annotation's to the Workspace foreach (var newAnnotation in newAnnotations) { CurrentWorkspace.AddAnnotation(newAnnotation); createdModels.Add(newAnnotation); AddToSelection(newAnnotation); } // Record models that are created as part of the command. CurrentWorkspace.RecordCreatedModels(createdModels); }
internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes) { //Do not build if the node is in error. if (this.State == ElementState.Error) { return null; } var resultNodes = new List<AssociativeNode>(); // Define unbound variables if necessary if (inputIdentifiers != null && inputAstNodes != null && inputIdentifiers.Count == inputAstNodes.Count) { var initStatments = inputIdentifiers.Zip(inputAstNodes, (ident, rhs) => { var identNode = AstFactory.BuildIdentifier(ident); MapIdentifiers(identNode); return AstFactory.BuildAssignment(identNode, rhs); }); resultNodes.AddRange(initStatments); } foreach (var stmnt in codeStatements) { var astNode = ProtoCore.Utils.NodeUtils.Clone(stmnt.AstNode); MapIdentifiers(astNode); resultNodes.Add(astNode as ProtoCore.AST.AssociativeAST.AssociativeNode); } return resultNodes; }
public FScheme.Expression Compile() { IEnumerable<string> inputNames = null; IEnumerable<string> outputNames = null; // Get the internal nodes for the function WorkspaceModel functionWorkspace = this.WorkspaceModel; #region Find outputs // Find output elements for the node List<Output> outputs = functionWorkspace.Nodes.OfType<Output>().ToList(); var topMost = new List<Tuple<int, NodeModel>>(); // if we found output nodes, add select their inputs // these will serve as the function output if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => x.Inputs[0])); outputNames = outputs.Select(x => x.Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable<NodeModel> topMostNodes = functionWorkspace.GetTopMostNodes(); NodeModel infinite = null; var outNames = new List<string>(); foreach (NodeModel topNode in topMostNodes) { if (topNode is Function && (topNode as Function).Definition == this) { infinite = topNode; continue; } foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } if (infinite != null && outNames.Count == 0) { topMost.Add(Tuple.Create(0, infinite)); outNames.Add("∞"); } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.ValidateConnections(); } //Find function entry point, and then compile var variables = functionWorkspace.Nodes.OfType<Symbol>().ToList(); inputNames = variables.Select(x => x.InputSymbol); //Update existing function nodes which point to this function to match its changes dynSettings.Controller.DynamoModel.AllNodes .OfType<Function>() .Where(el => el.Definition != null && el.Definition.FunctionId == this.FunctionId) .ToList() .ForEach(node => { node.SetInputs(inputNames); node.SetOutputs(outputNames); node.RegisterAllPorts(); }); //Call OnSave for all saved elements functionWorkspace.Nodes.ToList().ForEach(x => x.onSave()); INode top; var buildDict = new Dictionary<NodeModel, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode(FScheme.Value.NewList); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(CultureInfo.InvariantCulture); node.AddInput(inputName); node.ConnectInput(inputName, new BeginNode()); try { var exp = topNode.Item2.Build(buildDict, topNode.Item1); node.ConnectInput(inputName, exp); } catch { } i++; } top = node; } else if (topMost.Count == 1) { top = topMost[0].Item2.Build(buildDict, topMost[0].Item1); } else { // if the custom node is empty, it will initially be an empty begin top = new BeginNode(); } // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List<NodeModel> hangingNodes = functionWorkspace.GetHangingNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput( tNode.Index.ToString(CultureInfo.InvariantCulture), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon( variables.Select(x => x.GUID.ToString()), top.Compile()); return expression; }
public List<Type> LoadAllTypesFromDynamoAssemblies() { var nodeTypes = new List<Type>(); var loadedAssemblyNames = new HashSet<string>(); var allLoadedAssembliesByPath = new Dictionary<string, Assembly>(); var allLoadedAssemblies = new Dictionary<string, Assembly>(); // cache the loaded assembly information foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (assembly.IsDynamic) continue; try { allLoadedAssembliesByPath[assembly.Location] = assembly; allLoadedAssemblies[assembly.FullName] = assembly; } catch { } } // find all the dlls registered in all search paths // and concatenate with all dlls in the current directory var allDynamoAssemblyPaths = DynamoPathManager.Instance.Nodes.SelectMany((path) => { return (Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly)); }).ToList(); // add the core assembly to get things like code block nodes and watches. allDynamoAssemblyPaths.Add(Path.Combine(DynamoPathManager.Instance.MainExecPath, "DynamoCore.dll")); var resolver = new ResolveEventHandler(delegate(object sender, ResolveEventArgs args) { Assembly result; allLoadedAssemblies.TryGetValue(args.Name, out result); return result; }); foreach (var assemblyPath in allDynamoAssemblyPaths) { var fn = Path.GetFileName(assemblyPath); if (fn == null) continue; // if the assembly has already been loaded, then // skip it, otherwise cache it. if (loadedAssemblyNames.Contains(fn)) continue; loadedAssemblyNames.Add(fn); if (allLoadedAssembliesByPath.ContainsKey(assemblyPath)) { List<Type> types = LoadNodesFromAssembly(allLoadedAssembliesByPath[assemblyPath]); nodeTypes.AddRange(types); } else { try { var assembly = Assembly.LoadFrom(assemblyPath); allLoadedAssemblies[assembly.GetName().Name] = assembly; List<Type> types = LoadNodesFromAssembly(assembly); nodeTypes.AddRange(types); } catch (Exception e) { DynamoViewModel.Model.Logger.Log(e); } } } return nodeTypes; }
private void OnPreviewControlLoaded(object sender, RoutedEventArgs e) { phaseInStoryboard = this.Resources["phaseInStoryboard"] as Storyboard; phaseOutStoryboard = this.Resources["phaseOutStoryboard"] as Storyboard; expandStoryboard = this.Resources["expandStoryboard"] as Storyboard; condenseStoryboard = this.Resources["condenseStoryboard"] as Storyboard; resizingStoryboard = this.Resources["resizingStoryboard"] as Storyboard; var children = new List<Timeline>(); children.AddRange(phaseInStoryboard.Children); children.AddRange(expandStoryboard.Children); children.AddRange(condenseStoryboard.Children); children.AddRange(resizingStoryboard.Children); this.sizeAnimators = new Dictionary<string, DoubleAnimation>(); foreach (var child in children) { if (string.IsNullOrEmpty(child.Name)) continue; switch (child.Name) { case Element.PhaseInWidthAnimator: case Element.PhaseInHeightAnimator: case Element.ExpandWidthAnimator: case Element.ExpandHeightAnimator: case Element.CondenseWidthAnimator: case Element.CondenseHeightAnimator: case Element.GridWidthAnimator: case Element.GridHeightAnimator: sizeAnimators.Add(child.Name, child as DoubleAnimation); break; } } if (this.sizeAnimators.Count != 8) { var message = "One or more DoubleAnimation timeline not found"; throw new InvalidOperationException(message); } // If there was a request queued before this control is loaded, // then process the request as we now have the right width. BeginNextTransition(); }
private static void ParseSolid(GeometryObject obj, List<XYZ> pts) { var solid = obj as Solid; foreach (Edge gEdge in solid.Edges) { Curve c = gEdge.AsCurve(); if (c is Line) { pts.Add(c.Evaluate(0, true)); pts.Add(c.Evaluate(1,true)); } else { IList<XYZ> xyzArray = gEdge.Tessellate(); pts.AddRange(xyzArray); } } }
/// <summary> /// Gathers the Ids of the upstream drawable nodes. /// </summary> /// <param name="inputs">A dictionary describing the inputs on the node.</param> /// <returns>A collection of strings.</returns> private List<string> GetUpstreamDrawableIds(Dictionary<int, Tuple<int, NodeModel>> inputs) { var drawables = new List<string>(); foreach (KeyValuePair<int, Tuple<int, NodeModel>> pair in inputs) { if (pair.Value == null) continue; NodeModel node = pair.Value.Item2; if(node.OldValue != null) drawables.Add(node.GUID.ToString()); if (node.IsUpstreamVisible) drawables.AddRange(GetUpstreamDrawableIds(node.Inputs)); } return drawables; }
internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes) { var resultAst = new List<AssociativeNode>(); string function = Definition.Name; AssociativeNode rhs; // All inputs are provided, then we should pack all inputs that // belong to variable input parameter into a single array. if (!HasUnconnectedInput()) { var paramCount = Definition.Parameters.Count(); var packId = "__var_arg_pack_" + GUID; resultAst.Add( AstFactory.BuildAssignment( AstFactory.BuildIdentifier(packId), AstFactory.BuildExprList(inputAstNodes.Skip(paramCount - 1).ToList()))); inputAstNodes = inputAstNodes.Take(paramCount - 1) .Concat(new[] { AstFactory.BuildIdentifier(packId) }) .ToList(); } switch (Definition.Type) { case FunctionType.Constructor: case FunctionType.StaticMethod: if (HasUnconnectedInput()) { var functionNode = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { rhs = AstFactory.BuildFunctionCall(Definition.ClassName, Definition.Name, inputAstNodes); } break; case FunctionType.StaticProperty: var staticProp = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = staticProp; break; case FunctionType.InstanceProperty: // Only handle getter here. Setter could be handled in CBN. rhs = new NullNode(); if (inputAstNodes != null && inputAstNodes.Count >= 1) { var thisNode = inputAstNodes[0]; if (thisNode != null && !(thisNode is NullNode)) { var insProp = new IdentifierListNode { LeftNode = inputAstNodes[0], RightNode = new IdentifierNode(Definition.Name) }; rhs = insProp; } } break; case FunctionType.InstanceMethod: rhs = new NullNode(); if (inputAstNodes != null && inputAstNodes.Count >= 1) { var thisNode = inputAstNodes[0]; inputAstNodes.RemoveAt(0); // remove this pointer if (thisNode != null && !(thisNode is NullNode)) { var memberFunc = new IdentifierListNode { LeftNode = thisNode, RightNode = AstFactory.BuildFunctionCall(function, inputAstNodes) }; rhs = memberFunc; } } break; default: if (HasUnconnectedInput()) { var functionNode = new IdentifierNode(function); rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { rhs = AstFactory.BuildFunctionCall(function, inputAstNodes); } break; } resultAst.Add(AstFactory.BuildAssignment(AstIdentifierForPreview, rhs)); if (OutPortData.Count == 1) { var outputIdentiferNode = GetAstIdentifierForOutputIndex(0); string outputIdentifier = outputIdentiferNode.ToString(); string thisIdentifier = AstIdentifierForPreview.ToString(); if (!string.Equals(outputIdentifier, thisIdentifier)) { resultAst.Add( AstFactory.BuildAssignment(outputIdentiferNode, AstIdentifierForPreview)); } } else { var undefinedOutputs = Definition.ReturnKeys == null || !Definition.ReturnKeys.Any(); resultAst.AddRange( Enumerable.Range(0, OutPortData.Count) .Select( outputIdx => undefinedOutputs ? AstIdentifierForPreview : new IdentifierNode(AstIdentifierForPreview) { ArrayDimensions = new ArrayNode { Expr = new StringNode { value = Definition.ReturnKeys.ElementAt( outputIdx) } } })); } return resultAst; }
internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes) { string function = Definition.Name; AssociativeNode rhs; switch (Definition.Type) { case FunctionType.Constructor: case FunctionType.StaticMethod: if (IsPartiallyApplied) { var functionNode = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { AppendReplicationGuides(inputAstNodes); rhs = AstFactory.BuildFunctionCall( Definition.ClassName, Definition.Name, inputAstNodes); } break; case FunctionType.StaticProperty: var staticProp = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = staticProp; break; case FunctionType.InstanceProperty: // Only handle getter here. Setter could be handled in CBN. if (IsPartiallyApplied) { var functionNode = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { rhs = new NullNode(); if (inputAstNodes != null && inputAstNodes.Count >= 1) { var thisNode = inputAstNodes[0]; if (thisNode != null && !(thisNode is NullNode)) { var insProp = new IdentifierListNode { LeftNode = inputAstNodes[0], RightNode = new IdentifierNode(Definition.Name) }; rhs = insProp; } } } break; case FunctionType.InstanceMethod: if (IsPartiallyApplied) { var functionNode = new IdentifierListNode { LeftNode = new IdentifierNode(Definition.ClassName), RightNode = new IdentifierNode(Definition.Name) }; rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { rhs = new NullNode(); AppendReplicationGuides(inputAstNodes); if (inputAstNodes != null && inputAstNodes.Count >= 1) { var thisNode = inputAstNodes[0]; inputAstNodes.RemoveAt(0); // remove this pointer if (thisNode != null && !(thisNode is NullNode)) { var memberFunc = new IdentifierListNode { LeftNode = thisNode, RightNode = AstFactory.BuildFunctionCall(function, inputAstNodes) }; rhs = memberFunc; } } } break; default: if (IsPartiallyApplied) { var functionNode = new IdentifierNode(function); rhs = CreateFunctionObject(functionNode, inputAstNodes); } else { AppendReplicationGuides(inputAstNodes); rhs = AstFactory.BuildFunctionCall(function, inputAstNodes); } break; } var resultAst = new List<AssociativeNode> { AstFactory.BuildAssignment(AstIdentifierForPreview, rhs) }; if (OutPortData.Count == 1) { var outputIdentiferNode = GetAstIdentifierForOutputIndex(0); string outputIdentifier = outputIdentiferNode.ToString(); string thisIdentifier = AstIdentifierForPreview.ToString(); if (!string.Equals(outputIdentifier, thisIdentifier)) { resultAst.Add(AstFactory.BuildAssignment(outputIdentiferNode, AstIdentifierForPreview)); } } else { var undefinedOutputs = Definition.ReturnKeys == null || !Definition.ReturnKeys.Any(); resultAst.AddRange( Enumerable.Range(0, OutPortData.Count) .Select( outputIdx => undefinedOutputs ? AstIdentifierForPreview : new IdentifierNode(AstIdentifierForPreview) { ArrayDimensions = new ArrayNode { Expr = new StringNode { value = Definition.ReturnKeys.ElementAt(outputIdx) } } })); } return resultAst; }
private static List<Color> GetColorsFromMirrorData(RuntimeMirror colorsMirror) { var colors = new List<Color>(); if (colorsMirror == null || colorsMirror.GetData() == null) return colors; var data = colorsMirror.GetData(); if (data != null) { if (data.IsCollection) { colors.AddRange(data.GetElements().Select(e => e.Data).OfType<Color>()); } else { var color = data.Data as Color; if (color != null) colors.Add(color); } } return colors; }
Mesh3D MergeMeshes(List<Mesh3D> meshes) { if (meshes.Count == 0) return null; Mesh3D fullMesh = new Mesh3D(); List<Point3D> positions = new List<Point3D>(); List<int> triangleIndices = new List<int>(); int offset = 0; foreach (Mesh3D m in meshes) { positions.AddRange(m.Vertices); foreach (int[] face in m.Faces) { triangleIndices.Add(face[0] + offset); triangleIndices.Add(face[1] + offset); triangleIndices.Add(face[2] + offset); } offset = positions.Count; } return new Mesh3D(positions, triangleIndices); }
/// <summary> /// Sends workspace and its' dependencies to Flood. /// </summary> internal void Send(IEnumerable<IWorkspaceModel> workspaces) { if (String.IsNullOrWhiteSpace(serverUrl) || String.IsNullOrWhiteSpace(authenticationProvider.Username)) throw new Exception(Resource.ServerErrorMessage); if (authenticationProvider == null) throw new Exception(Resource.AuthenticationErrorMessage); string fullServerAdress = serverUrl + ":" + port; if (reachClient == null) reachClient = new WorkspaceStorageClient(authenticationProvider, fullServerAdress); HomeWorkspace = workspaces.OfType<HomeWorkspaceModel>().First(); var functionNodes = HomeWorkspace.Nodes.OfType<Function>(); List<CustomNodeDefinition> dependencies = new List<CustomNodeDefinition>(); foreach (var node in functionNodes) { dependencies.AddRange(node.Definition.Dependencies); } CustomNodeWorkspaces = new List<CustomNodeWorkspaceModel>(); foreach (var dependency in dependencies) { CustomNodeWorkspaceModel customNodeWs; var isWorkspaceCreated = customNodeManager.TryGetFunctionWorkspace(dependency.FunctionId, false, out customNodeWs); if (isWorkspaceCreated && !CustomNodeWorkspaces.Contains(customNodeWs)) CustomNodeWorkspaces.Add(customNodeWs); } var result = reachClient.Send(HomeWorkspace, CustomNodeWorkspaces); }
/// <summary> /// Get a property value from a member /// </summary> /// <param name="args">The incoming arguments</param> /// <param name="api_base_type">The base type</param> /// <param name="pi">The property info object for which you will return the value.</param> /// <param name="return_type">The expected return type.</param> /// <returns></returns> public static Value GetAPIPropertyValue( FSharpList<Value> args, Type api_base_type, PropertyInfo pi, Type return_type) { //var arg0 = (Autodesk.Revit.DB.HermiteFace)DynamoTypeConverter.ConvertInput(args[0], typeof(Autodesk.Revit.DB.HermiteFace)); //var result = arg0.Points; var results = new List<object>(); //there should only be one argument foreach (var arg in args) { if (arg.IsList) { FSharpList<Value> lst = FSharpList<Value>.Empty; //the values here are the items whose properties //you want to query. nothing fancy, just get the //property for each of the items. results.AddRange(((Value.List) arg).Item. Select(v => DynamoTypeConverter.ConvertInput(v, api_base_type)). Select(invocationTarget => pi.GetValue(invocationTarget, null))); } else { var invocationTarget = DynamoTypeConverter.ConvertInput(args[0], api_base_type); results.Add(pi.GetValue(invocationTarget,null)); } } return ConvertAllResults(results); }
/// <summary> /// Invoke an API method, using the node's lacing strategy to build lists of arguments /// </summary> /// <param name="node">The node.</param> /// <param name="args">The incoming Values on the node.</param> /// <param name="api_base_type">The API's base type whose method we will invoke.</param> /// <param name="pi">An array of parameter info for the method.</param> /// <param name="mi">The method info for the method.</param> /// <param name="return_type">The expected return type from the method.</param> /// <returns></returns> public static Value InvokeAPIMethod(dynRevitTransactionNode node, FSharpList<Value> args, Type api_base_type, ParameterInfo[] pi, MethodBase mi, Type return_type) { //if any argument are a list, honor the lacing strategy //compile a list of parameter lists to be used in our method invocation List<List<object>> parameters = null; switch (node.ArgumentLacing) { case LacingStrategy.Single: parameters = GetSingleArguments(args, pi); break; case LacingStrategy.Shortest: parameters = GetShortestArguments(args, pi); break; case LacingStrategy.Longest: parameters = GetLongestArguments(args, pi); break; default: parameters = GetSingleArguments(args, pi); break; } var invocationTargetList = new List<object>(); if (api_base_type == typeof(Autodesk.Revit.Creation.Document) || api_base_type == typeof(Autodesk.Revit.Creation.FamilyItemFactory) || api_base_type == typeof(Autodesk.Revit.Creation.ItemFactoryBase)) { if (dynRevitSettings.Doc.Document.IsFamilyDocument) { invocationTargetList.Add(dynRevitSettings.Doc.Document.FamilyCreate); } else { invocationTargetList.Add(dynRevitSettings.Doc.Document.Create); } } else if (api_base_type == typeof(Autodesk.Revit.Creation.Application)) { invocationTargetList.Add(dynRevitSettings.Revit.Application.Create); } else { if (!mi.IsStatic && !mi.IsConstructor) { if (args[0].IsList) { invocationTargetList.AddRange(((Value.List)args[0]).Item.Select(x => DynamoTypeConverter.ConvertInput(x, api_base_type))); } else { //the first input will always hold the instance //whose methods you want to invoke invocationTargetList.Add(DynamoTypeConverter.ConvertInput(args[0], api_base_type)); } } } //object result = null; List<object> results = null; //if the method info is for a constructor, then //call the constructor for each set of parameters //if it's an instance method, then invoke the method for //each instance passed in. results = mi.IsConstructor ? parameters.Select(x => ((ConstructorInfo) mi).Invoke(x.ToArray())).ToList() : invocationTargetList.SelectMany(x => parameters.Select(y => mi.Invoke(x, y.ToArray())).ToList()).ToList(); dynRevitUtils.StoreElements(node, results); return ConvertAllResults(results); }
public CustomNodeDefinition( Guid functionId, string displayName="", IList<NodeModel> nodeModels=null) { if (functionId == Guid.Empty) throw new ArgumentException(@"FunctionId invalid.", "functionId"); nodeModels = nodeModels ?? new List<NodeModel>(); #region Find outputs // Find output elements for the node var outputs = nodeModels.OfType<Output>().ToList(); var topMost = new List<Tuple<int, NodeModel>>(); List<string> outNames; // if we found output nodes, add select their inputs // these will serve as the function output if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => Tuple.Create(0, x as NodeModel))); outNames = outputs.Select(x => x.Symbol).ToList(); } else { outNames = new List<string>(); // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable<NodeModel> topMostNodes = nodeModels.Where(node => node.IsTopMostNode); var rtnPorts = //Grab multiple returns from each node topMostNodes.SelectMany( topNode => //If the node is a recursive instance... topNode is Function && (topNode as Function).Definition.FunctionId == functionId // infinity output ? new[] {new {portIndex = 0, node = topNode, name = "∞"}} // otherwise, grab all ports with connected outputs and package necessary info : topNode.OutPortData .Select( (port, i) => new {portIndex = i, node = topNode, name = port.NickName}) .Where(x => !topNode.HasOutput(x.portIndex))); foreach (var rtnAndIndex in rtnPorts.Select((rtn, i) => new {rtn, idx = i})) { topMost.Add(Tuple.Create(rtnAndIndex.rtn.portIndex, rtnAndIndex.rtn.node)); outNames.Add(rtnAndIndex.rtn.name ?? rtnAndIndex.idx.ToString()); } } var nameDict = new Dictionary<string, int>(); foreach (var name in outNames) { if (nameDict.ContainsKey(name)) nameDict[name]++; else nameDict[name] = 0; } nameDict = nameDict.Where(x => x.Value != 0).ToDictionary(x => x.Key, x => x.Value); outNames.Reverse(); var returnKeys = new List<string>(); foreach (var name in outNames) { int amt; if (nameDict.TryGetValue(name, out amt)) { nameDict[name] = amt - 1; returnKeys.Add(name == "" ? amt + ">" : name + amt); } else returnKeys.Add(name); } returnKeys.Reverse(); #endregion #region Find inputs //Find function entry point, and then compile var inputNodes = nodeModels.OfType<Symbol>().ToList(); var parameters = inputNodes.Select(x => new TypedParameter( x.GetAstIdentifierForOutputIndex(0).Value, x.Parameter.Type, x.Parameter.DefaultValue)); var displayParameters = inputNodes.Select(x => x.Parameter.Name); #endregion FunctionBody = nodeModels.Where(node => !(node is Symbol)); DisplayName = displayName; FunctionId = functionId; Parameters = parameters; ReturnKeys = returnKeys; DisplayParameters = displayParameters; OutputNodes = topMost.Select(x => x.Item2.GetAstIdentifierForOutputIndex(x.Item1)); DirectDependencies = nodeModels .OfType<Function>() .Select(node => node.Definition) .Where(def => def.FunctionId != functionId) .Distinct(); }
private static FScheme.Expression CompileFunction( FunctionDefinition definition ) { if (definition == null) return null; // Get the internal nodes for the function dynWorkspace functionWorkspace = definition.Workspace; #region Find outputs // Find output elements for the node IEnumerable<dynNode> outputs = functionWorkspace.Nodes.Where(x => x is dynOutput); var topMost = new List<Tuple<int, dynNode>>(); IEnumerable<string> outputNames; // if we found output nodes, add select their inputs // these will serve as the function output if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => x.Inputs[0])); outputNames = outputs.Select(x => (x as dynOutput).Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as tht output IEnumerable<dynNode> topMostNodes = functionWorkspace.GetTopMostNodes(); var outNames = new List<string>(); foreach (dynNode topNode in topMostNodes) { foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.NodeUI.ValidateConnections(); } //Find function entry point, and then compile the function and add it to our environment IEnumerable<dynNode> variables = functionWorkspace.Nodes.Where(x => x is dynSymbol); IEnumerable<string> inputNames = variables.Select(x => (x as dynSymbol).Symbol); INode top; var buildDict = new Dictionary<dynNode, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode( FScheme.Value.NewList, Enumerable.Range(0, topMost.Count).Select(x => x.ToString())); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(); node.ConnectInput(inputName, topNode.Item2.Build(buildDict, topNode.Item1)); i++; } top = node; } else top = topMost[0].Item2.BuildExpression(buildDict); // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List<dynNode> hangingNodes = functionWorkspace.GetTopMostNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString()); beginNode.ConnectInput(tNode.Index.ToString(), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString()); beginNode.ConnectInput(hangingNodes.Count.ToString(), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon(variables.Select(x => x.NodeUI.GUID.ToString()), top.Compile()); return expression; }
/// <summary> /// Sends workspace and its' dependencies to Flood. /// </summary> /// <returns>String which is response from server.</returns> internal string Send(IEnumerable<IWorkspaceModel> workspaces, WorkspaceProperties workspaceProperties = null) { if (String.IsNullOrWhiteSpace(serverUrl)) { Error = UploadErrorType.ServerNotFound; return Resources.FailedMessage; } if (String.IsNullOrWhiteSpace(authenticationProvider.Username)) { Error = UploadErrorType.AuthenticationFailed; return Resources.FailedMessage; } if (authenticationProvider == null) { Error = UploadErrorType.AuthProviderNotFound; return Resources.FailedMessage; } if (reachClient == null) reachClient = new WorkspaceStorageClient(authenticationProvider, serverUrl); HomeWorkspace = workspaces.OfType<HomeWorkspaceModel>().First(); var functionNodes = HomeWorkspace.Nodes.OfType<Function>(); List<CustomNodeDefinition> dependencies = new List<CustomNodeDefinition>(); foreach (var node in functionNodes) { dependencies.AddRange(node.Definition.Dependencies); } CustomNodeWorkspaces = new List<ICustomNodeWorkspaceModel>(); foreach (var dependency in dependencies) { ICustomNodeWorkspaceModel customNodeWs; var isWorkspaceCreated = customNodeManager.TryGetFunctionWorkspace(dependency.FunctionId, false, out customNodeWs); if (isWorkspaceCreated && !CustomNodeWorkspaces.Contains(customNodeWs)) CustomNodeWorkspaces.Add(customNodeWs); } string result; try { result = reachClient.Send( HomeWorkspace, CustomNodeWorkspaces.OfType<CustomNodeWorkspaceModel>(), workspaceProperties); InvalidNodeNames = null; } catch (InvalidNodesException ex) { InvalidNodeNames = ex.InvalidNodeNames; result = Resources.FailedMessage; } catch { result = Resources.FailedMessage; } return result; }
/// <summary> /// Utility method to get the Revit geometry associated with nodes. /// </summary> /// <param name="value"></param> /// <returns></returns> private static List<GeometryObject> RevitGeometryFromNodes(FScheme.Value value) { var geoms = new List<GeometryObject>(); if (value == null) { return geoms; } if (value.IsList) { foreach (var val_inner in ((FScheme.Value.List)value).Item) { geoms.AddRange(RevitGeometryFromNodes(val_inner)); } return geoms; } var container = value as Value.Container; if (container == null) return geoms; var geom = ((FScheme.Value.Container)value).Item as GeometryObject; if (geom != null && !(geom is Face)) geoms.Add(geom); var ps = ((FScheme.Value.Container) value).Item as ParticleSystem; if (ps != null) { geoms.AddRange(ps.Springs.Select(spring => Line.CreateBound(spring.getOneEnd().getPosition(), spring.getTheOtherEnd().getPosition())).Cast<GeometryObject>()); } var cl = ((FScheme.Value.Container) value).Item as Autodesk.Revit.DB.CurveLoop; if (cl != null) { geoms.AddRange(cl); } //draw xyzs as Point objects var pt = ((FScheme.Value.Container)value).Item as XYZ; if (pt != null) { Type pointType = typeof(Point); MethodInfo[] pointTypeMethods = pointType.GetMethods(BindingFlags.Static | BindingFlags.Public); var method = pointTypeMethods.FirstOrDefault(x => x.Name == "CreatePoint"); if (method != null) { var args = new object[3]; args[0] = pt.X; args[1] = pt.Y; args[2] = pt.Z; geoms.Add((Point)method.Invoke(null, args)); } } return geoms; }
/// <summary> /// This method adds relevant models to the undo recorder. /// </summary> /// <param name="isGroupLayout">True if all the selected models are groups.</param> private void RecordUndoGraphLayout(bool isGroupLayout) { List<ModelBase> undoItems = new List<ModelBase>(); if (!isGroupLayout) { // Add all selected items to the undo recorder undoItems.AddRange(Nodes); undoItems.AddRange(Notes); if (DynamoSelection.Instance.Selection.Count > 0) { undoItems = undoItems.Where(x => x.IsSelected).ToList(); } } else { // Add all models inside selected groups foreach (var group in Annotations) { if (group.IsSelected) { group.Deselect(); undoItems.AddRange(group.SelectedModels); } } } WorkspaceModel.RecordModelsForModification(undoItems, UndoRecorder); }
/// <summary> /// Return all nodes that are in the scope of this node. /// nodes are not in the scope. /// </summary> /// <param name="checkEscape"> /// Specifies if need to exclude nodes that one of their downstream /// nodes are not in the scope /// </param> /// <param name="isInclusive"> /// If one of its upstream node is ScopedNodeModel, if need to include /// all upstream nodes of that node. /// </param> /// <returns></returns> public IEnumerable<NodeModel> GetInScopeNodes(bool checkEscape = true, bool isInclusive = true) { var inScopedNodes = new List<NodeModel>(); foreach (int index in Enumerable.Range(0, InPortData.Count)) { if (!IsScopedInport(index)) { continue; } var inScopedNodesForInport = GetInScopeNodesForInport(index, checkEscape, isInclusive); inScopedNodes.AddRange(inScopedNodesForInport); } return inScopedNodes; }
/// <summary> /// This method extracts all models from the workspace and puts them /// into the combined graph object, LayoutSubgraphs.First() /// <param name="isGroupLayout">True if all the selected models are groups.</param> /// </summary> private void GenerateCombinedGraph(bool isGroupLayout) { LayoutSubgraphs = new List<GraphLayout.Graph>(); LayoutSubgraphs.Add(new GraphLayout.Graph()); GraphLayout.Graph combinedGraph = LayoutSubgraphs.First(); SubgraphClusters = new List<List<GraphLayout.Node>>(); if (!isGroupLayout) { foreach (AnnotationModel group in Annotations) { // Treat a group as a graph layout node/vertex combinedGraph.AddNode(group.GUID, group.Width, group.Height, group.X, group.Y, group.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } foreach (NodeModel node in Nodes) { if (!isGroupLayout) { AnnotationModel group = Annotations.Where( g => g.SelectedModels.Contains(node)).ToList().FirstOrDefault(); // Do not process nodes within groups if (group == null) { combinedGraph.AddNode(node.GUID, node.Width, node.Height, node.X, node.Y, node.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } else { // Process all nodes inside the selection combinedGraph.AddNode(node.GUID, node.Width, node.Height, node.X, node.Y, node.IsSelected || DynamoSelection.Instance.Selection.Count == 0); } } foreach (ConnectorModel edge in Connectors) { if (!isGroupLayout) { AnnotationModel startGroup = null, endGroup = null; startGroup = Annotations.Where( g => g.SelectedModels.Contains(edge.Start.Owner)).ToList().FirstOrDefault(); endGroup = Annotations.Where( g => g.SelectedModels.Contains(edge.End.Owner)).ToList().FirstOrDefault(); // Treat a group as a node, but do not process edges within a group if (startGroup == null || endGroup == null || startGroup != endGroup) { combinedGraph.AddEdge( startGroup == null ? edge.Start.Owner.GUID : startGroup.GUID, endGroup == null ? edge.End.Owner.GUID : endGroup.GUID, edge.Start.Center.X, edge.Start.Center.Y, edge.End.Center.X, edge.End.Center.Y); } } else { // Edges within a group are also processed combinedGraph.AddEdge(edge.Start.Owner.GUID, edge.End.Owner.GUID, edge.Start.Center.X, edge.Start.Center.Y, edge.End.Center.X, edge.End.Center.Y); } } foreach (NoteModel note in Notes) { // Link a note to the nearest node GraphLayout.Node nd = combinedGraph.Nodes.OrderBy(node => Math.Pow(node.X + node.Width / 2 - note.X - note.Width / 2, 2) + Math.Pow(node.Y + node.Height / 2 - note.Y - note.Height / 2, 2)).FirstOrDefault(); if (nd != null) { nd.LinkNote(note, note.Width, note.Height); } } if (!isGroupLayout) { // Add all nodes to one big cluster List<GraphLayout.Node> bigcluster = new List<GraphLayout.Node>(); bigcluster.AddRange(combinedGraph.Nodes); SubgraphClusters.Add(bigcluster); } else { // Each group becomes one cluster foreach (AnnotationModel group in DynamoSelection.Instance.Selection.OfType<AnnotationModel>()) { List<GraphLayout.Node> cluster = new List<GraphLayout.Node>(); cluster.AddRange(group.SelectedModels.Select(x => combinedGraph.FindNode(x.GUID))); SubgraphClusters.Add(cluster); } } }
public DynamoView(DynamoViewModel dynamoViewModel) { // The user's choice to enable hardware acceleration is now saved in // the Dynamo preferences. It is set to true by default. // When the view is constructed, we enable or disable hardware acceleration based on that preference. //This preference is not exposed in the UI and can be used to debug hardware issues only // by modifying the preferences xml. RenderOptions.ProcessRenderMode = dynamoViewModel.Model.PreferenceSettings.UseHardwareAcceleration ? RenderMode.Default : RenderMode.SoftwareOnly; this.dynamoViewModel = dynamoViewModel; this.dynamoViewModel.UIDispatcher = Dispatcher; nodeViewCustomizationLibrary = new NodeViewCustomizationLibrary(this.dynamoViewModel.Model.Logger); DataContext = dynamoViewModel; Title = dynamoViewModel.BrandingResourceProvider.GetString(ResourceNames.MainWindow.Title); tabSlidingWindowStart = tabSlidingWindowEnd = 0; _timer = new Stopwatch(); _timer.Start(); InitializeComponent(); ToggleIsUsageReportingApprovedCommand.ToolTip = string.Format( Wpf.Properties.Resources.DynamoViewSettingMenuEnableDataReportingTooltip, dynamoViewModel.BrandingResourceProvider.ProductName); Loaded += DynamoView_Loaded; Unloaded += DynamoView_Unloaded; SizeChanged += DynamoView_SizeChanged; LocationChanged += DynamoView_LocationChanged; // Check that preference bounds are actually within one // of the available monitors. if (CheckVirtualScreenSize()) { Left = dynamoViewModel.Model.PreferenceSettings.WindowX; Top = dynamoViewModel.Model.PreferenceSettings.WindowY; Width = dynamoViewModel.Model.PreferenceSettings.WindowW; Height = dynamoViewModel.Model.PreferenceSettings.WindowH; } else { Left = 0; Top = 0; Width = 1024; Height = 768; } _workspaceResizeTimer.Tick += _resizeTimer_Tick; if (dynamoViewModel.Model.AuthenticationManager.HasAuthProvider) { loginService = new LoginService(this, new System.Windows.Forms.WindowsFormsSynchronizationContext()); dynamoViewModel.Model.AuthenticationManager.AuthProvider.RequestLogin += loginService.ShowLogin; } var viewExtensions = new List<IViewExtension>(); foreach (var dir in dynamoViewModel.Model.PathManager.ViewExtensionsDirectories) { viewExtensions.AddRange(viewExtensionManager.ExtensionLoader.LoadDirectory(dir)); } viewExtensionManager.MessageLogged += Log; var startupParams = new ViewStartupParams(dynamoViewModel); foreach (var ext in viewExtensions) { try { var logSource = ext as ILogSource; if (logSource != null) logSource.MessageLogged += Log; ext.Startup(startupParams); viewExtensionManager.Add(ext); } catch (Exception exc) { Log(ext.Name + ": " + exc.Message); } } this.dynamoViewModel.RequestPaste += OnRequestPaste; this.dynamoViewModel.RequestReturnFocusToView += OnRequestReturnFocusToView; FocusableGrid.InputBindings.Clear(); }
/// <summary> /// Compiles this custom node definition, updating all UI instances to match /// inputs and outputs and registering new definition with the EngineController. /// </summary> public void Compile(DynamoModel dynamoModel, EngineController controller) { // If we are loading dyf file, dont compile it until all nodes are loaded // otherwise some intermediate function defintions will be created. // TODO: This is a hack, in reality we should be preventing this from being called at the Workspace.RequestSync() level --SJE if (IsBeingLoaded || IsProxy) return; #region Outputs and Inputs and UI updating #region Find outputs // Find output elements for the node List<Output> outputs = WorkspaceModel.Nodes.OfType<Output>().ToList(); var topMost = new List<Tuple<int, NodeModel>>(); List<string> outNames; // if we found output nodes, add select their inputs // these will serve as the function output if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => Tuple.Create(0, x as NodeModel))); outNames = outputs.Select(x => x.Symbol).ToList(); } else { outNames = new List<string>(); // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable<NodeModel> topMostNodes = WorkspaceModel.GetTopMostNodes(); var rtnPorts = //Grab multiple returns from each node topMostNodes.SelectMany( topNode => //If the node is a recursive instance... topNode is Function && (topNode as Function).Definition == this // infinity output ? new[] { new { portIndex = 0, node = topNode, name = "∞" } } // otherwise, grab all ports with connected outputs and package necessary info : topNode.OutPortData .Select( (port, i) => new { portIndex = i, node = topNode, name = port.NickName }) .Where(x => !topNode.HasOutput(x.portIndex))); foreach (var rtnAndIndex in rtnPorts.Select((rtn, i) => new { rtn, idx = i })) { topMost.Add(Tuple.Create(rtnAndIndex.rtn.portIndex, rtnAndIndex.rtn.node)); outNames.Add(rtnAndIndex.rtn.name ?? rtnAndIndex.idx.ToString()); } } var nameDict = new Dictionary<string, int>(); foreach (var name in outNames) { if (nameDict.ContainsKey(name)) nameDict[name]++; else nameDict[name] = 0; } nameDict = nameDict.Where(x => x.Value != 0).ToDictionary(x => x.Key, x => x.Value); outNames.Reverse(); var keys = new List<string>(); foreach (var name in outNames) { int amt; if (nameDict.TryGetValue(name, out amt)) { nameDict[name] = amt - 1; keys.Add(name == "" ? amt + ">" : name + amt); } else keys.Add(name); } keys.Reverse(); ReturnKeys = keys; #endregion //Find function entry point, and then compile var inputNodes = WorkspaceModel.Nodes.OfType<Symbol>().ToList(); var parameters = inputNodes.Select(x => x.GetAstIdentifierForOutputIndex(0).Value); Parameters = inputNodes.Select(x => x.InputSymbol); //Update existing function nodes which point to this function to match its changes var customNodeInstances = dynamoModel.AllNodes .OfType<Function>() .Where(el => el.Definition != null && el.Definition == this); foreach (var node in customNodeInstances) node.ResyncWithDefinition(); //Call OnSave for all saved elements foreach (var node in WorkspaceModel.Nodes) node.OnSave(); #endregion var outputNodes = topMost.Select((x) => { var n = x.Item2.GetAstIdentifierForOutputIndex(x.Item1); return n as AssociativeNode; }); controller.GenerateGraphSyncDataForCustomNode( this, WorkspaceModel.Nodes.Where(x => !(x is Symbol)), outputNodes, parameters); // Not update graph until Run // if (success) // controller.UpdateGraph(); }
internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes, AstBuilder.CompilationContext context) { //Do not build if the node is in error. if (State == ElementState.Error) { return Enumerable.Empty<AssociativeNode>(); } var resultNodes = new List<AssociativeNode>(); // Define unbound variables if necessary if (inputIdentifiers != null && inputAstNodes != null && inputIdentifiers.Count == inputAstNodes.Count) { var initStatments = inputIdentifiers.Zip(inputAstNodes, (ident, rhs) => { var identNode = AstFactory.BuildIdentifier(ident); if (context != AstBuilder.CompilationContext.NodeToCode) MapIdentifiers(identNode); return AstFactory.BuildAssignment(identNode, rhs); }); resultNodes.AddRange(initStatments); } foreach (var astNode in codeStatements.Select(stmnt => NodeUtils.Clone(stmnt.AstNode))) { if (context != AstBuilder.CompilationContext.NodeToCode) MapIdentifiers(astNode); resultNodes.Add(astNode as AssociativeNode); } return resultNodes; }
//public override void Evaluate(FSharpList<FScheme.Value> args, Dictionary<PortData, FScheme.Value> outPuts) //{ // if (OutPortData.Count > 1) // { // var query = (Evaluate(args) as FScheme.Value.List).Item.Zip( // OutPortData, // (value, data) => new { value, data }); // foreach (var result in query) // outPuts[result.data] = result.value; // } // else // base.Evaluate(args, outPuts); //} //public override FScheme.Value Evaluate(FSharpList<FScheme.Value> args) //{ // //return ((FScheme.Value.Function)Controller.FSchemeEnvironment.LookupSymbol(Symbol)) // // .Item.Invoke(args); // throw new NotImplementedException("FSchemeEnvironment has been removed."); //} internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes) { var resultAst = new List<AssociativeNode>(); if (OutPortData.Count == 1) { if (IsPartiallyApplied) { var count = Definition.Parameters.Count(); AssociativeNode functionCall = AstFactory.BuildFunctionObject( Definition.FunctionName, count, Enumerable.Range(0, count).Where(HasInput), inputAstNodes); resultAst.Add(AstFactory.BuildAssignment(AstIdentifierForPreview, functionCall)); resultAst.Add( AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstIdentifierForPreview)); } else { AssociativeNode functionCall = AstFactory.BuildFunctionCall( Definition.FunctionName, inputAstNodes); resultAst.Add(AstFactory.BuildAssignment(AstIdentifierForPreview, functionCall)); // assign the entire result to the only output port var outId = GetAstIdentifierForOutputIndex(0); if (AstIdentifierForPreview.Value != outId.Value) resultAst.Add(AstFactory.BuildAssignment(outId, AstIdentifierForPreview)); } } else { AssociativeNode functionCall = AstFactory.BuildFunctionCall( Definition.FunctionName, inputAstNodes); resultAst.Add(AstFactory.BuildAssignment(AstIdentifierForPreview, functionCall)); /* previewId = customNodeFunc(arg0, arg1 ...); * outId0 = previewId[key0]; * outId1 = previewId[key1]; * ... */ // indexers for each output IEnumerable<AssociativeNode> indexers = Definition.ReturnKeys != null ? Definition.ReturnKeys.Select(AstFactory.BuildStringNode) as IEnumerable<AssociativeNode> : Enumerable.Range(0, OutPortData.Count).Select(AstFactory.BuildIntNode); // for each output, pull the output from the result // based on the associated return key and assign to // corresponding output identifier resultAst.AddRange( indexers.Select( (rtnKey, index) => AstFactory.BuildAssignment( GetAstIdentifierForOutputIndex(index), AstFactory.BuildIdentifier(AstIdentifierForPreview.Name, rtnKey)))); } return resultAst; }
/// <summary> /// Collapse a set of nodes in a given workspace. /// </summary> /// <param name="selectedNodes"> The function definition for the user-defined node </param> /// <param name="currentWorkspace"> The workspace where</param> /// <param name="isTestMode"></param> /// <param name="args"></param> public CustomNodeWorkspaceModel Collapse( IEnumerable<NodeModel> selectedNodes, WorkspaceModel currentWorkspace, bool isTestMode, FunctionNamePromptEventArgs args) { var selectedNodeSet = new HashSet<NodeModel>(selectedNodes); // Note that undoable actions are only recorded for the "currentWorkspace", // the nodes which get moved into "newNodeWorkspace" are not recorded for undo, // even in the new workspace. Their creations will simply be treated as part of // the opening of that new workspace (i.e. when a user opens a file, she will // not expect the nodes that show up to be undoable). // // After local nodes are moved into "newNodeWorkspace" as the result of // conversion, if user performs an undo, new set of nodes will be created in // "currentWorkspace" (not moving those nodes in the "newNodeWorkspace" back // into "currentWorkspace"). In another word, undo recording is on a per- // workspace basis, it does not work across different workspaces. // UndoRedoRecorder undoRecorder = currentWorkspace.UndoRecorder; CustomNodeWorkspaceModel newWorkspace; using (undoRecorder.BeginActionGroup()) { #region Determine Inputs and Outputs //Step 1: determine which nodes will be inputs to the new node var inputs = new HashSet<Tuple<NodeModel, int, Tuple<int, NodeModel>>>( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.InPortData.Count) .Where(node.HasConnectedInput) .Select(data => Tuple.Create(node, data, node.InputNodes[data])) .Where(input => !selectedNodeSet.Contains(input.Item3.Item2)))); var outputs = new HashSet<Tuple<NodeModel, int, Tuple<int, NodeModel>>>( selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPortData.Count) .Where(node.HasOutput) .SelectMany( data => node.OutputNodes[data].Where( output => !selectedNodeSet.Contains(output.Item2)) .Select(output => Tuple.Create(node, data, output))))); #endregion #region Detect 1-node holes (higher-order function extraction) Log(Properties.Resources.CouldNotRepairOneNodeHoles, WarningLevel.Mild); // http://adsk-oss.myjetbrains.com/youtrack/issue/MAGN-5603 //var curriedNodeArgs = // new HashSet<NodeModel>( // inputs.Select(x => x.Item3.Item2) // .Intersect(outputs.Select(x => x.Item3.Item2))).Select( // outerNode => // { // //var node = new Apply1(); // var node = newNodeWorkspace.AddNode<Apply1>(); // node.SetNickNameFromAttribute(); // node.DisableReporting(); // node.X = outerNode.X; // node.Y = outerNode.Y; // //Fetch all input ports // // in order // // that have inputs // // and whose input comes from an inner node // List<int> inPortsConnected = // Enumerable.Range(0, outerNode.InPortData.Count) // .Where( // x => // outerNode.HasInput(x) // && selectedNodeSet.Contains( // outerNode.Inputs[x].Item2)) // .ToList(); // var nodeInputs = // outputs.Where(output => output.Item3.Item2 == outerNode) // .Select( // output => // new // { // InnerNodeInputSender = output.Item1, // OuterNodeInPortData = output.Item3.Item1 // }) // .ToList(); // nodeInputs.ForEach(_ => node.AddInput()); // node.RegisterAllPorts(); // return // new // { // OuterNode = outerNode, // InnerNode = node, // Outputs = // inputs.Where( // input => input.Item3.Item2 == outerNode) // .Select(input => input.Item3.Item1), // Inputs = nodeInputs, // OuterNodePortDataList = inPortsConnected // }; // }).ToList(); #endregion #region UI Positioning Calculations double avgX = selectedNodeSet.Average(node => node.X); double avgY = selectedNodeSet.Average(node => node.Y); double leftMost = selectedNodeSet.Min(node => node.X); double topMost = selectedNodeSet.Min(node => node.Y); double rightMost = selectedNodeSet.Max(node => node.X + node.Width); double leftShift = leftMost - 250; #endregion #region Handle full selected connectors // Step 2: Determine all the connectors whose start/end owners are // both in the selection set, and then move them from the current // workspace into the new workspace. var fullySelectedConns = new HashSet<ConnectorModel>( currentWorkspace.Connectors.Where( conn => { bool startSelected = selectedNodeSet.Contains(conn.Start.Owner); bool endSelected = selectedNodeSet.Contains(conn.End.Owner); return startSelected && endSelected; })); foreach (var connector in fullySelectedConns) { undoRecorder.RecordDeletionForUndo(connector); connector.Delete(); } #endregion #region Handle partially selected connectors // Step 3: Partially selected connectors (either one of its start // and end owners is in the selection) are to be destroyed. var partiallySelectedConns = currentWorkspace.Connectors.Where( conn => selectedNodeSet.Contains(conn.Start.Owner) || selectedNodeSet.Contains(conn.End.Owner)).ToList(); foreach (var connector in partiallySelectedConns) { undoRecorder.RecordDeletionForUndo(connector); connector.Delete(); } #endregion #region Transfer nodes and connectors to new workspace var newNodes = new List<NodeModel>(); var newAnnotations = new List<AnnotationModel>(); // Step 4: move all nodes to new workspace remove from old // PB: This could be more efficiently handled by a copy paste, but we // are preservering the node foreach (var node in selectedNodeSet) { undoRecorder.RecordDeletionForUndo(node); currentWorkspace.RemoveNode(node); // Assign a new guid to this node, otherwise when node is // compiled to AST, literally it is still in global scope // instead of in function scope. node.GUID = Guid.NewGuid(); node.RenderPackages.Clear(); // shift nodes node.X = node.X - leftShift; node.Y = node.Y - topMost; newNodes.Add(node); } //Copy the group from newNodes foreach (var group in DynamoSelection.Instance.Selection.OfType<AnnotationModel>()) { undoRecorder.RecordDeletionForUndo(group); currentWorkspace.RemoveGroup(group); group.GUID = Guid.NewGuid(); group.SelectedModels = group.DeletedModelBases; newAnnotations.Add(group); } foreach (var conn in fullySelectedConns) { ConnectorModel.Make(conn.Start.Owner, conn.End.Owner, conn.Start.Index, conn.End.Index); } #endregion #region Process inputs var inConnectors = new List<Tuple<NodeModel, int>>(); var uniqueInputSenders = new Dictionary<Tuple<NodeModel, int>, Symbol>(); //Step 3: insert variables (reference step 1) foreach (var input in Enumerable.Range(0, inputs.Count).Zip(inputs, Tuple.Create)) { int inputIndex = input.Item1; NodeModel inputReceiverNode = input.Item2.Item1; int inputReceiverData = input.Item2.Item2; NodeModel inputNode = input.Item2.Item3.Item2; int inputData = input.Item2.Item3.Item1; Symbol node; var key = Tuple.Create(inputNode, inputData); if (uniqueInputSenders.ContainsKey(key)) { node = uniqueInputSenders[key]; } else { inConnectors.Add(Tuple.Create(inputNode, inputData)); node = new Symbol { InputSymbol = inputReceiverNode.InPortData[inputReceiverData].NickName, X = 0 }; // Try to figure out the type of input of custom node // from the type of input of selected node. There are // two kinds of nodes whose input type are available: // function node and custom node. List<Library.TypedParameter> parameters = null; if (inputReceiverNode is Function) { var func = inputReceiverNode as Function; parameters = func.Controller.Definition.Parameters.ToList(); } else if (inputReceiverNode is DSFunctionBase) { var dsFunc = inputReceiverNode as DSFunctionBase; var funcDesc = dsFunc.Controller.Definition; parameters = funcDesc.Parameters.ToList(); if (funcDesc.Type == DSEngine.FunctionType.InstanceMethod || funcDesc.Type == DSEngine.FunctionType.InstanceProperty) { var dummyType = new ProtoCore.Type() { Name = funcDesc.ClassName }; var instanceParam = new TypedParameter(funcDesc.ClassName, dummyType); parameters.Insert(0, instanceParam); } } // so the input of custom node has format // input_var_name : type if (parameters != null && parameters.Count() > inputReceiverData) { var typeName = parameters[inputReceiverData].DisplayTypeName; if (!string.IsNullOrEmpty(typeName)) { node.InputSymbol += " : " + typeName; } } node.SetNickNameFromAttribute(); node.Y = inputIndex*(50 + node.Height); uniqueInputSenders[key] = node; newNodes.Add(node); } //var curriedNode = curriedNodeArgs.FirstOrDefault(x => x.OuterNode == inputNode); //if (curriedNode == null) //{ ConnectorModel.Make(node, inputReceiverNode, 0, inputReceiverData); //} //else //{ // //Connect it to the applier // newNodeWorkspace.AddConnection(node, curriedNode.InnerNode, 0, 0); // //Connect applier to the inner input receive // newNodeWorkspace.AddConnection( // curriedNode.InnerNode, // inputReceiverNode, // 0, // inputReceiverData); //} } #endregion #region Process outputs //List of all inner nodes to connect an output. Unique. var outportList = new List<Tuple<NodeModel, int>>(); var outConnectors = new List<Tuple<NodeModel, int, int>>(); int i = 0; if (outputs.Any()) { foreach (var output in outputs) { if (outportList.All(x => !(x.Item1 == output.Item1 && x.Item2 == output.Item2))) { NodeModel outputSenderNode = output.Item1; int outputSenderData = output.Item2; //NodeModel outputReceiverNode = output.Item3.Item2; //if (curriedNodeArgs.Any(x => x.OuterNode == outputReceiverNode)) // continue; outportList.Add(Tuple.Create(outputSenderNode, outputSenderData)); //Create Symbol Node var node = new Output { Symbol = outputSenderNode.OutPortData[outputSenderData].NickName, X = rightMost + 75 - leftShift }; node.Y = i*(50 + node.Height); node.SetNickNameFromAttribute(); newNodes.Add(node); ConnectorModel.Make(outputSenderNode, node, outputSenderData, 0); i++; } } //Connect outputs to new node outConnectors.AddRange( from output in outputs let outputSenderNode = output.Item1 let outputSenderData = output.Item2 let outputReceiverData = output.Item3.Item1 let outputReceiverNode = output.Item3.Item2 select Tuple.Create( outputReceiverNode, outportList.FindIndex( x => x.Item1 == outputSenderNode && x.Item2 == outputSenderData), outputReceiverData)); } else { foreach (var hanging in selectedNodeSet.SelectMany( node => Enumerable.Range(0, node.OutPortData.Count) .Where(port => !node.HasOutput(port)) .Select(port => new { node, port })).Distinct()) { //Create Symbol Node var node = new Output { Symbol = hanging.node.OutPortData[hanging.port].NickName, X = rightMost + 75 - leftShift }; node.Y = i*(50 + node.Height); node.SetNickNameFromAttribute(); newNodes.Add(node); ConnectorModel.Make(hanging.node, node, hanging.port, 0); i++; } } #endregion var newId = Guid.NewGuid(); newWorkspace = new CustomNodeWorkspaceModel( nodeFactory, newNodes, Enumerable.Empty<NoteModel>(), newAnnotations, Enumerable.Empty<PresetModel>(), new WorkspaceInfo() { X = 0, Y = 0, Name = args.Name, Category = args.Category, Description = args.Description, ID = newId.ToString(), FileName = string.Empty }, currentWorkspace.ElementResolver); newWorkspace.HasUnsavedChanges = true; RegisterCustomNodeWorkspace(newWorkspace); var collapsedNode = CreateCustomNodeInstance(newId, isTestMode: isTestMode); collapsedNode.X = avgX; collapsedNode.Y = avgY; currentWorkspace.AddNode(collapsedNode, centered: false); undoRecorder.RecordCreationForUndo(collapsedNode); foreach (var connector in inConnectors.Select((x, idx) => new { node = x.Item1, from = x.Item2, to = idx }) .Select( nodeTuple => ConnectorModel.Make( nodeTuple.node, collapsedNode, nodeTuple.@from, nodeTuple.to)) .Where(connector => connector != null)) { undoRecorder.RecordCreationForUndo(connector); } foreach (var connector in outConnectors.Select( nodeTuple => ConnectorModel.Make( collapsedNode, nodeTuple.Item1, nodeTuple.Item2, nodeTuple.Item3)).Where(connector => connector != null)) { undoRecorder.RecordCreationForUndo(connector); } } return newWorkspace; }
/// <summary> /// Gathers the Ids of the upstream drawable nodes. /// </summary> /// <param name="inputs">A dictionary describing the inputs on the node.</param> /// <returns>A collection of strings.</returns> private IEnumerable<IRenderPackage> GetUpstreamPackages(Dictionary<int, Tuple<int, NodeModel>> inputs, int recursionLevelCount) { #if DEBUG const int MAX_RECURSION = 200; Validity.Assert(recursionLevelCount < MAX_RECURSION, "Stack Overflow protection trap"); #endif var packages = new List<IRenderPackage>(); foreach (KeyValuePair<int, Tuple<int, NodeModel>> pair in inputs) { if (pair.Value == null) continue; NodeModel node = pair.Value.Item2; //We no longer depend on OldValue, as long as the given node has //registered it's render description with Visualization manager //we will be able to visualize the given node. -Sharad if (node != null) { lock (node.RenderPackagesMutex) { packages.AddRange(node.RenderPackages); } } if (node.IsUpstreamVisible) packages.AddRange(GetUpstreamPackages(node.Inputs, recursionLevelCount + 1)); } return packages; }