Friday, February 20, 2015

Quick Macro for Duplicating an Existing Sheet and Views

I had someone recently ask me if it was possible to duplicate a sheet and it's views in Revit. It isn't possible within Revit by default, but with a little bit of code, I was able to get a macro that would duplicate the sheet and it's views. Give the macro a try, just make sure you are in a sheet view before running the macro.

Note: the duplicated views and sheets are renamed with "-DUP" since they need to be unique in Revit. You can change this in the code to be anything you want.

public void DuplicateSheet()
{
    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;
    ViewSheet vs = doc.ActiveView as ViewSheet;
   
    using(Transaction t = new Transaction(doc, "Duplicate Sheet"))
    {
        t.Start();
   
        FamilyInstance titleblock = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance))
            .OfCategory(BuiltInCategory.OST_TitleBlocks).Cast<FamilyInstance>()
            .First(q => q.OwnerViewId == vs.Id);

        ViewSheet newsheet = ViewSheet.Create(doc, titleblock.GetTypeId());
        newsheet.SheetNumber = vs.SheetNumber + "-DUP";
        newsheet.Name = vs.Name;
       
        // all views but schedules
        foreach(ElementId eid in vs.GetAllPlacedViews())
        {
            View ev = doc.GetElement(eid) as View;
           
            View newview = null;
           
            // legends
            if (ev.ViewType == ViewType.Legend)
            {
                newview = ev;
            }
            // all non-legend and non-schedule views
            else
            {
                ElementId newviewid = ev.Duplicate(ViewDuplicateOption.WithDetailing);
                newview = doc.GetElement(newviewid) as View;
                newview.Name = ev.Name + "-DUP";
            }
           
            foreach (Viewport vp in new FilteredElementCollector(doc).OfClass(typeof(Viewport)))
            {
                                               
                if (vp.SheetId == vs.Id && vp.ViewId == ev.Id)
                {
                    BoundingBoxXYZ vpbb = vp.get_BoundingBox(vs);
                    XYZ initialCenter = (vpbb.Max + vpbb.Min) / 2;
                   
                    Viewport newvp = Viewport.Create(doc, newsheet.Id, newview.Id, XYZ.Zero);
                   
                    BoundingBoxXYZ newvpbb = newvp.get_BoundingBox(newsheet);
                    XYZ newCenter = (newvpbb.Max + newvpbb.Min) / 2;
                   
                    ElementTransformUtils.MoveElement(doc, newvp.Id, new XYZ(
                        initialCenter.X - newCenter.X,
                        initialCenter.Y - newCenter.Y,
                        0));
                }
                   
            }
           
        }
       
        // schedules
       
        foreach (ScheduleSheetInstance si in (new FilteredElementCollector(doc).OfClass(typeof(ScheduleSheetInstance))))
        {
            if (si.OwnerViewId == vs.Id)
            {
                if (!si.IsTitleblockRevisionSchedule)
                {                           
                    foreach (ViewSchedule vsc in new FilteredElementCollector(doc).OfClass(typeof(ViewSchedule)))
                    {
                        if (si.ScheduleId == vsc.Id)
                        {
                            BoundingBoxXYZ sibb = si.get_BoundingBox(vs);
                            XYZ initialCenter = (sibb.Max + sibb.Min) / 2;
                           
                            ScheduleSheetInstance newssi = ScheduleSheetInstance.Create(doc, newsheet.Id, vsc.Id, XYZ.Zero);
                           
                            BoundingBoxXYZ newsibb = newssi.get_BoundingBox(newsheet);
                            XYZ newCenter = (newsibb.Max + newsibb.Min) / 2;
                           
                            ElementTransformUtils.MoveElement(doc, newssi.Id, new XYZ(
                                initialCenter.X - newCenter.X,
                                initialCenter.Y - newCenter.Y,
                                0));
                        }
                    }
                }

            }
        }
       
   
        t.Commit();
    }
   
}

Wednesday, February 11, 2015

Revit Macro for Mass Importing Shared Parameters

The following was a quick attempt to see if I could mass import a bunch of shared parameters into my projects. Its part of a tool I am building that needed some unique parameters for schedules and tags.

public void ImportSharedParameters()
{
    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;
  
    // location of shared parameters file
    string spfile = @"\\corp.ktgy.com\bim\DT\API\Unit Coin\Shared Parameter-KTGY.txt";
  
    using (Transaction t = new Transaction(doc, "Import Shared Parameters"))
    {
        t.Start();
        

        // create a new line for each parameter like this:
       // doc, SharedParametersFile, ParameterName, Category, ParameterGroup, VaryByGroupInstance         CreateProjParameter(doc, spfile, "Building", BuiltInCategory.OST_Rooms, BuiltInParameterGroup.PG_IDENTITY_DATA, true);
        CreateProjParameter(doc, spfile, "Unit Area", BuiltInCategory.OST_Rooms, BuiltInParameterGroup.PG_GENERAL, true);
                      
        t.Commit();
    }
}


public void CreateProjParameter( Document doc, string sharedParameterFile, string parameterName,
                                BuiltInCategory bicategory, BuiltInParameterGroup bipgroup, Boolean varyByGroup)
{
    // load the shared parameters file
    Application.SharedParametersFilename = sharedParameterFile;
  
    // select the category
    Category cat = doc.Settings.Categories.get_Item(bicategory);
    // create a new category set
    CategorySet catset = Application.Create.NewCategorySet();
    // add category to category set
    catset.Insert(cat);
  
    // loaded shared parameter file
    DefinitionFile deffile = Application.OpenSharedParameterFile();
  
    try
    {
        // find the parameter in the shared parameters file
        // by searching each parameter group
        var v = (from DefinitionGroup dg in deffile.Groups
                 from ExternalDefinition d in dg.Definitions
                 where d.Name == parameterName
                 select d);
      
        ExternalDefinition def = v.First();
      
        // bind the parameter to the category and parameter group
        Binding binding = Application.Create.NewInstanceBinding(catset);
        BindingMap map = doc.ParameterBindings;
        map.Insert(def, binding, bipgroup);
      
        // change parameter to be "Values can vary by group instance"
        if(varyByGroup)
        {
            BindingMap grpmap = doc.ParameterBindings;
            DefinitionBindingMapIterator it = grpmap.ForwardIterator();
          
            while (it.MoveNext())
            {
                Definition d = it.Key as Definition;
                if (d.Name == parameterName)
                {
                    InternalDefinition idef = it.Key as InternalDefinition;
                    idef.SetAllowVaryBetweenGroups(doc, true);
                }
            }
        }
                      
    }
    catch (Exception ex)
    {
               TaskDialog.Show("Error", ex.Message);
    }
}