Creating New Nodes

Hi All,

Just wondering if anyone has any experience creating icon/nodes from functions.

To explain what I am trying to do:

I have created a few functions using the basic method shown in the 2019_02 GC SIG "The GC SDK Digging_Deeper".

Using just a script in simple string form, as a easy way to get into creating Add-ins. 

That all works fine as and we can utilise the function from the function dialog or using a function call.

I would however like to create an icon/node that I can link to this function.

I have created an icon/node and placed it into a NodeTypePaletteCateory etc 

Just wondering what how I would go about calling the function I created? I assume I would need to create a funcitoncall as an input and populate it with the new function I created. 

We are trying to make the custom function more accessible to new users that are more familiar with node based workflows.

Any help would be appreciated.

Will post the results, maybe someone will find it useful.

Thanks

Wayne

Parents
  • Hi Wayne,

    I'm not familiar with that SIG, but I assume you're talking about a custom function and a custom node type that you've implemented in a GC add-in, which you created in Visual Studio.

    From a GC user's point of view, there should be no difference between your custom function and any other GC function. Likewise, there should be no difference between your custom node type and any other GC node type. In other words, the user shouldn't need to know -- or care -- where that function and node type came from.

    Just as in any other scenario, you should be able to call your custom function within an expression that you provide to an input to your custom node. Or, you should be able to create a FunctionCall node that calls your custom function, and then reference that FunctionCall node in an expression that you provide as an input to your custom node.

    Or am I off track from what you're asking?

    Jeff

  • Hi Jeff,

    Thanks for responding.

    Sorry my question was a bit vague on what I am exactly trying to do.

    As an example I wrote a new add-in by just using gcscript language in Visual Studio. I will attache an example below.

    This makes it easy as someone that is not familiar with Visual Studio to get an add-in for delivering function to a team.

    Basically found the handy line:

    GCScriptTools.ExecuteInItsEntirety(GCTools.UIGCSpace(), scriptwayne, ScriptFlags.UserAuthored, BreakpointAcknowledgement.Ignore);

    What i would like to do now is take that function and present it as a icon/node to the user in a new PaletteCateory.

    I managed to create an icon and a new Palette Category but I am struggling on how to now call the function in Visual Studio context.

    As an example I have included a bit of script from Visual Studio I was using for the icon.

    Hope that makes sense

    Thanks again 
    Wayne

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Bentley.GenerativeComponents;
    using Bentley.GenerativeComponents.AddInSupport;
    using Bentley.GenerativeComponents.Features;
    using Bentley.GenerativeComponents.Features.Specific;
    using Bentley.GenerativeComponents.GeneralPurpose;
    using Bentley.GenerativeComponents.GCScript;
    using Bentley.GenerativeComponents.GCScript.FundamentalValues;
    using Bentley.GenerativeComponents.GCScript.GCTypes;
    using Bentley.GenerativeComponents.GCScript.NameScopes;
    using Bentley.GenerativeComponents.MicroStation;
    using Bentley.Interop.MicroStationDGN;
    using Bentley.GeometryNET;
    using System.ComponentModel;
    using Bentley.GenerativeComponents.View;
    
    
    namespace SampleAddIn
    {
        [GCNamespace("User")]                                   // The GCNamespace attribute lets us specify where this SimpleLine node
                                                                // type will appear within GCScript's namespace tree (that is, the
                                                                // namespaces that are perceived by the GC user). This namespace has no
                                                                // relation to our C# namespace, which is (in this case) SampleAddIn.
    
        [NodeTypePaletteCategory("Wayne")]              // The NodeTypePaletteCategory attribute lets us specify where this
                                                                // SimpleLine node type will appear within GC's Node Types dialog.
                                                                // So, it will appear within a group named "Sample Add-In".
    
        [NodeTypeIcon("Resources/SimpleLineNode.png")]
    
        [Summary("Is a script i wrote")]
    
    
    
    
        public class ScriptFunctions
    
    
        //static internal class ScriptFunctions
        {
            static internal void Load()
            {
                // This method is called from within the constructor of the class, Initializer (within this project). So, this
                // method will be called automatically whenever the user loads this assembly, SampleAddIn, into GC.
    
                IGCEnvironment environment = UniversalGCEnvironment.TheOnlyInstance;
                NameCatalog nameCatalog = environment.TopLevelNameCatalog();
    
                // To add a new function to the GCScript processor, we call the method, nameCatalog.AddNamespaceLevelFunction.
                //
                // 1. The first argument is the name of the new function, as the GC user will see it. (It's our responsibility
                //    to ensure that the name doesn't conflict with another top-level name in GC.)
                //
                // 2. The second argument is the type (also known as the signature) of the new function, expressed in GCScript
                //    language.
                //
                // 3. The third argument is the name of the C# method that implements the new function. That method can have any
                //    name; however, we recommend that it have the same name as the function.
    
                
    
                DefineScriptFunctionsWrittenInScript();
            }
    
            // Each method that implements a script function may be prefaced by a 'Summary' attribute, which provides user
            // documentation for that function. The documentation text will appear in GC's Functions dialog. (The presence
            // or absence of a Summary attribute has no effect on how the function may be used in GC.)
    
           
    
    
    
            static void DefineScriptFunctionsWrittenInScript()
            {
                // The following script is copied from the contents of the script transaction that results if we define one or more
                // new script function in the Functions dialog, then commit that transaction.
    
                string scriptwayne = "global redeclare object WayneReverse(object List)\n" +
                                "{\n" +
                                "object NewList = Reverse(List);\n" +
                                "return NewList;\n" +
                                "}\n";
    
    
                // Now run the aforementioned script, which results in the script functions (in this case, the one function 'Angle360') being defined,
                // as though we were running a script transaction containing that script.
    
                GCScriptTools.ExecuteInItsEntirety(GCTools.UIGCSpace(), scriptwayne, ScriptFlags.UserAuthored, BreakpointAcknowledgement.Ignore);
                
            }
            
           
    
            
    
        }
    }
    

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using Bentley.GenerativeComponents;
    using Bentley.GenerativeComponents.AddInSupport;
    using Bentley.GenerativeComponents.Features;
    using Bentley.GenerativeComponents.GCScript;
    using Bentley.GenerativeComponents.GCScript.NameScopes;
    using Bentley.GenerativeComponents.GeneralPurpose;
    using Bentley.GenerativeComponents.MicroStation;
    using Bentley.GenerativeComponents.View;
    using Bentley.Interop.MicroStationDGN;
    using Bentley.GenerativeComponents.GCScript.FundamentalValues;
    using Bentley.GenerativeComponents.GCScript.GCTypes;
    using Bentley.GeometryNET;
    using Bentley.GenerativeComponents.UtilityNodes;
    
    namespace SampleAddIn
    {
        [GCNamespace("Waynetest")]                              // The GCNamespace attribute lets us specify where this SimpleLine node
                                                                // type will appear within GCScript's namespace tree (that is, the
                                                                // namespaces that are perceived by the GC user). This namespace has no
                                                                // relation to our C# namespace, which is (in this case) SampleAddIn.
    
        [NodeTypePaletteCategory("Wayne")]              // The NodeTypePaletteCategory attribute lets us specify where this
                                                        // SimpleLine node type will appear within GC's Node Types dialog.
                                                        // So, it will appear within a group named "Sample Add-In".
    
        [NodeTypeIcon("Resources/SimpleLineNode.png")]          // The NodeTypeIcon attribute lets us specify the graphical image (icon)
                                                                // that will appear on the SimpleLine node type's button within GC's Node
                                                                // Types dialog.
    
        [Summary("A line that connects two points in space.")]  // The Summary attribute lets us provide a brief description of this
                                                                // node's intended purposed. The text will be displayed when the user
                                                                // hovers over our node type in GC's Node Types dialog.
    
        public class WayneSimpleLine: UtilityNode
        {
    
           
        } // class
    
    } // namespace
    
    

  • Hi Wayne,

    I'm glad you're successful with your new node types. Congratulations!

    Regarding your SplitList node type, I see the problem: In your NodeState's first constructor, you're missing this statement:

    ResultList1Property = AddProperty(NameOfResultList1Property);

    Sometimes it just takes a second set of eyes. Slight smile

    Jeff

    Answer Verified By: Wayne Dickerson 

  • Thanks Jeff,

    I missed that one!

    I did have another error in the loop but fixed that up and it is all working now.

    So another couple of questions.

    1. How do you make the output display on the node by default. ( rather then clicking the drop down and pinning it)

    2. How would l set the colour of the node by default. (I found a possible class, Bentley.GenerativeComponents.UtilityNodes.Specific.Color.Color that might be the place to set it, but I am just guessing)

    Thanks again.

    Wayne

  • Hi Wayne,

    1. To make an output port appear on the node by default, add ".SetIsAlwaysPinned(PropertyDirections.Output)" to the end of your call to 'AddParameterDefinition' for that property.

    Here I've added that phrase to the end of the two outputs on your SplitList node type:

    technique1.AddParameterDefinition(environment, NameOfResultList1Property, typeof(object[]), "",
        Ls.Literal("The first part of the list."), NodePortRole.TechniqueOutputOnly).SetIsAlwaysPinned(PropertyDirections.Output);

    technique1.AddParameterDefinition(environment, NameOfResultList2Property, typeof(object[]), "",
        Ls.Literal("The second part of the list."), NodePortRole.TechniqueOutputOnly).SetIsAlwaysPinned(PropertyDirections.Output);

    2. I don't recommend forcing a node's color, since the node-color facility is intended for users to color the nodes as they wish, based on the significance of those nodes in their own GC models.

    However, since you asked, here's how to force a node to be a particular color: Somewhere within the body of your class (but not within the embedded NodeState class), add this method:

    public override System.Windows.Media.Color GetNodeColor(bool enablePropertyCalculatorIfThereIsOne=true)
    {
        return Colors.Orange; // ...Or whichever color you want.
    }

    (Note: In order to use the types 'System.Windows.Media.Color' and 'Colors', your project must have a reference to the standard Framework assembly, PresentationCore. It probably already does.)

    Jeff

    Answer Verified By: Wayne Dickerson 

  • HI Jeff,

    Thanks again,

    Perfect. You are probably right. Setting the colour as a default would not be a great idea.

    I have just updated all the nodes and doing some testing. Will post a version here that people might find useful.

    Wayne

  • HI All,

    With a  big thanks to Jeff for his help. i have posted the list nodes I created and created a short video on their use on youtube.

    We have found them very useful, hopefully you will too.

    https://youtu.be/c_ULDGRjAXU

    Thanks

    Wayne

Reply Children
No Data