Friday, January 17, 2014

Set Element Parameters in Dynamo Revit

I have been working diligently with my co-worker Michael Coffey (Revit API Guru) to try and develop some great tools that are missing inside of Dynamo.
We recently were able to modify the "Set Family Instance Parameters" node, which is currently limited to only family instances to allow you to set any element parameter weather its a loaded family or a system family! 

















We have found it particularly useful when trying to edit multiple sheet parameters at once in the entire file. Next step in the process will be to work out setting up custom filters to gather lists of specific elements in a project file.

In order to deploy it, copy the following files into....


....the below location....


Here is the source code:


using System;

using System.Collections.Generic;

using System.Globalization;

using System.Linq;

using System.Xml;

using Autodesk.Revit.DB;

using Dynamo.FSchemeInterop;

using Dynamo.Models;

using Dynamo.Utilities;


using Microsoft.FSharp.Collections;

using Value = Dynamo.FScheme.Value;
using Dynamo.Revit;

namespace Dynamo.Nodes
{
    /// <summary>
    ///     Create a custom node.
    /// </summary>
    [NodeName("Set Element Parameters")]
    [NodeCategory(BuiltinNodeCategories.REVIT_DOCUMENT)]
    [NodeDescription("Set Element Parameters from a given Input")]
    public class SetElementParameters : RevitTransactionNodeWithOneOutput
    {
        public SetElementParameters()
        {
          InPortData.Add(new PortData("elements", "The element from which to get parameters", typeof (Value.Container)));
            InPortData.Add(new PortData("param", "Parameter to modify (string).", typeof (Value.String)));
            InPortData.Add(new PortData("value", "Value to set the parameter to.", typeof (object)));
            OutPortData.Add(new PortData("elements", "Modified Elements.", typeof (Value.Container)));
            
            RegisterAllPorts();

//            ArgumentLacing = LacingStrategy.Longest;
        }
private static Value setParam(Element elem, string paramName, Value valueExpr)
        {
            var p = elem.get_Parameter(paramName);
            if (p != null)
            {
                return _setParam(elem, p, valueExpr);
            }
            throw new Exception("Parameter \"" + paramName + "\" was not found!");
        }

        private static Value setParam(Element elem, Definition paramDef, Value valueExpr)
        {
            var p = elem.get_Parameter(paramDef);
            if (p != null)
            {
                return _setParam(elem, p, valueExpr);
            }
            throw new Exception("Parameter \"" + paramDef.Name + "\" was not found!");
        }

        private static Value _setParam(Element elem, Parameter p, Value valueExpr)
        {
            if (p.StorageType == StorageType.Double)
            {
                p.Set(((Value.Number) valueExpr).Item);
            }
            else if (p.StorageType == StorageType.Integer)
            {
                p.Set((int) ((Value.Number) valueExpr).Item);
            }
            else if (p.StorageType == StorageType.String)
            {
                p.Set(((Value.String) valueExpr).Item);
            }
            else if (p.StorageType == StorageType.ElementId)
            {
                p.Set((ElementId) ((Value.Container) valueExpr).Item);
            }
            else if (valueExpr.IsNumber)
            {
                p.Set(new ElementId((int) (valueExpr as Value.Number).Item));
            }
            else
            {
                p.Set((ElementId) ((Value.Container) valueExpr).Item);
            }
            return Value.NewContainer(elem);
        }

        public override Value Evaluate(FSharpList<Value> args)
        {
            var valueExpr = args[2];

            var param = args[1];
            if (param.IsString)
            {
                var paramName = ((Value.String) param).Item;

                var input = args[0];
                if (input.IsList)
                {
                    var elemList = (input as Value.List).Item;
                    return Value.NewList(
                        Utils.SequenceToFSharpList(
                            elemList.Select(
                                x =>
                                setParam(
                                    (Element) ((Value.Container) x).Item,
                                    paramName,
                                    valueExpr))));
                }
                else
                {
                    var fs = (Element) ((Value.Container) input).Item;

                    return setParam(fs, paramName, valueExpr);
                }
            }
            else
            {
                var paramDef = (Definition) ((Value.Container) param).Item;

                var input = args[0];
                if (input.IsList)
                {
                    var eList = (input as Value.List).Item;
                    return Value.NewList(
                        Utils.SequenceToFSharpList(
                            eList.Select(
                                x =>
                                setParam(
                                    (Element) ((Value.Container) x).Item,
                                    paramDef,
                                    valueExpr))));
                }
                else
                {
                    var fs = (Element) ((Value.Container) input).Item;

                    return setParam(fs, paramDef, valueExpr);
                }
            }
        }
    }
}


10 comments:

  1. Thanks a lot for sharing. Out of curiosity, is this node able to set the "Revisions on Sheet" parameter? I think I know the answer, but one can dream, right? :)

    ReplyDelete
  2. wouldn't that be great! I am pretty sure that in Revit 2014 this is possible. Have you used BIM link yet? they are able to pull these parameters. I think it will just take a bit more diving into the code I have a few more nodes in mind and I will certainly make them more deploy-able! stay tuned.

    ReplyDelete
  3. No dice, tried BIM Link (Ideate) & Exceler8 (Case) and the parameter is not even an option. It is however available in Spreadsheet Link in the Revit Express Tools (CTC), but the output is blank cells *sad trombone*...

    ReplyDelete
    Replies
    1. Latest install of BIMlink seems to be able to set true or false for even given revision sequence...I can't recall if we discussed this already or not, lol?

      Delete
  4. Hi, as the dev team works hard on Dynamo, there's no longer such files (dll and pdb) in the actual builds directory. Isn't it safer to publish this great work as a package? thanks.

    ReplyDelete
  5. thanks for the comment! I actually put in a pull request on the github site to get it integrated into the default build. this is only a temporary solution. along with the source code. and if i nested this node into a package, it would be broken since you wont have the source .dll, the thought in later builds is to allow for dynamo to pull the source code when sharing custom written nodes.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. What is the current status for this custom Node? I still dont see it in the build.Does it have another name? If not can you be more specific where to place it in the current build? Thanks

    ReplyDelete
  8. Hi, the link is broken. Could you fix it?I´m trying to modify a read only parameter but I can´t. Argghh.Thanks

    ReplyDelete
  9. Hi, the link is broken. Could you fix it?I´m trying to modify a read only parameter but I can´t. Argghh.Thanks

    ReplyDelete