10 janv. 2020

[Revit] Interopérabilité Excel







Analyses, modifications,  import de données, transfert vers une application tierce, transmissions de quantitatifs, etc..., dans l'écosystème du BIM, l'utilisation d'Excel devient incontournable.

Le plus souvent la nécessité d'exporter vers Excel provient des Nomenclatures, plusieurs méthodes pour y parvenir.

  • Avec l'export natif de Revit 

Après export de rapport de nomenclatures au format texte avec choix du délimiteur, il suffit de d'importer le fichier txt en tant que données depuis Excel ou de changer directement l'extension "txt" en "csv" puis de l'ouvrir avec Excel.


  • Avec des Add-Ins
Ce n'est pas le choix qui manque, exemple sur l'AutodeskAppStore

voici mes préférés (gratuit) :
    • Import/Export Excel de BIM One (export - import de nomenclatures, modification possible des paramètres d’Occurrence)
    •  SheetLink de Diroots  (export - import de nomenclatures et bien plus, modification possible des paramètres d’Occurrence et de Type avec précautions)

  • Avec Dynamo 

    • avec ses 2 nœuds natifs 



  • Par programmation avec les API(s) 

    • Pour des besoins très spécifiques, on peut également personnaliser ses propres exports avec les API de Revit et de Microsoft, par exemple pour exporter des données spécifiques ou pour personnaliser la mise en page des données sur Excel.
Les données des Nomenclatures peuvent être récupérées au travers de diverses Classes comme TableData ou TableView
Pour rappel les nomenclatures sont des vues... on peut donc parcourir les éléments via la méthode 
FilteredElementCollector

    Voici un exemple d'utilisation de l'API de Microsoft pour exporter les paramètres de fichiers Familles Revit contenu dans un dossier.
    Ici les données sont stockées dans un Array puis transférées dans un Range  via la variable Value2 (sauf pour les couleurs de cellules 😕...y'en a qui ont essayé ils ont eu des problèmes 😅... bref, obligé de passer une boucle)

    Plus d'informations ici 
      gist_export_Excel
      
      # Copyright (c) 20119- POUPIN.C
      import clr
      import re
      clr.AddReference('ProtoGeometry')
      from Autodesk.DesignScript.Geometry import *
      clr.AddReference('RevitAPI')
      import Autodesk
      from Autodesk.Revit.DB import *
      clr.AddReference('RevitServices')
      import RevitServices
      from RevitServices.Persistence import DocumentManager
      from RevitServices.Transactions import TransactionManager
      app = DocumentManager.Instance.CurrentUIApplication.Application
      
      clr.AddReference('System.Drawing')
      from System import Array
      from System.Drawing import *
      
      clr.AddReferenceByName('Microsoft.Office.Interop.Excel, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c')
      from Microsoft.Office.Interop import Excel
      from System.Runtime.InteropServices import Marshal
      import sys
      sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')
      import os
              
      class ParameterProp():
          def __init__(self, para):
              self._para = para
              self._pname = para.Definition.Name
              self._pisinstance = para.IsInstance
          
      class FamiliesCheck():
          def __init__(self, dirpath):
              self.dirpath = dirpath
              self.full_lstP = [] 
              for dir, subdir, files in os.walk(dirpath):
                  for file in files:
                      if file.endswith(".rfa") and re.search(r'\.\d+.rfa$', file) is None and re.search(r'[aA]ncien', dir) is None:
                          famDoc = app.OpenDocumentFile(dir + '\\' + file)
                          if famDoc.IsFamilyDocument:
                              famManager = famDoc.FamilyManager
                              lst_para = [ ParameterProp(x) for x in famManager.Parameters]
                              lst_para.sort(key = lambda x : x._pname)
                              lst_para[0:0] = [file]
                              self.full_lstP.append(lst_para)             
                          famDoc.Close(False)     
          
          def XlsWriter(self):
              ex = Excel.ApplicationClass()
              ex.Visible = True
              ex.DisplayAlerts = False
              workbook = ex.Workbooks.Add()
              workbook.SaveAs(self.dirpath + "\\reportFamilies.xlsx")
              ws = workbook.Worksheets[1]     
              nbr_row = 1
              for sub_lst in self.full_lstP:
                  nbr_col = len(sub_lst)
                  xlrange  = ws.Range[ws.Cells(nbr_row, 1), ws.Cells(nbr_row, len(sub_lst))]
                  a = Array.CreateInstance(object, 1, len(sub_lst))
                  b = Array.CreateInstance(object, 1, len(sub_lst))
                  for index, i in enumerate(sub_lst):
                      # if i is string
                      if isinstance(i, str):
                          a[0,index] = i
                      #else i is a ParameterProp objet    
                      else:
                          a[0,index] = i._pname
                          if i._pisinstance == False:
                              b[0,index] = 6
                          elif i._pisinstance == True:
                              b[0,index] = 8      
                          else:
                              b[0,index] = None
                  #copy Array in range            
                  xlrange.Value2 = a  
                  for cell, color_index in zip(xlrange, b):
                      cell.Interior.ColorIndex = color_index
                  nbr_row += 1
              used_range = ws.UsedRange   
              for column in used_range.Columns:
                  column.AutoFit()
              workbook.Save() 
                  
      dirpath = IN[0]
      obj_check = FamiliesCheck(dirpath)
      obj_check.XlsWriter()
      OUT = obj_check.full_lstP
      
      Aperçu en Vidéo avec quelques lignes supplémentaire


      un 2ᵉ exemple ou l'on exporte des preview des familles vers Excel
      (avec les méthodes Clipboard  et Paste )
      
      # coding: utf-8 
      import clr
      clr.AddReference('ProtoGeometry')
      from Autodesk.DesignScript.Geometry import *
      
      clr.AddReference('RevitAPI')
      import Autodesk
      from Autodesk.Revit.DB import *
      
      clr.AddReference('RevitServices')
      import RevitServices
      from RevitServices.Persistence import DocumentManager
      
      doc = DocumentManager.Instance.CurrentDBDocument
      uiapp = DocumentManager.Instance.CurrentUIApplication
      app = uiapp.Application
      uidoc = uiapp.ActiveUIDocument
      
      
      import System
      from System import Environment
      from System import Array
      from System.Collections.Generic import *
      
      clr.AddReference('System.Drawing')
      import System.Drawing
      from System.Drawing import *
      clr.AddReference('System.Windows.Forms')
      from System.Windows.Forms import Clipboard
      
      
      clr.AddReferenceByName('Microsoft.Office.Interop.Excel, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' )
      from Microsoft.Office.Interop import Excel
      from System.Runtime.InteropServices import Marshal
      
      
      class ExcelUtils():
          def __init__(self, expSettings, filepath, sizebitmap):
              self.expSettings = expSettings
              self.filepath = filepath
              self.sizebitmap = sizebitmap
              print self.filepath
              
              
          def exportXls(self):
              
              ex = Excel.ApplicationClass()
              ex.Visible = True
              ex.DisplayAlerts = False
              workbook = ex.Workbooks.Add()
              workbook.SaveAs(self.filepath)
              ws = workbook.Worksheets[1] 
              nbr_row = len(self.expSettings)
              nbr_colum = len(self.expSettings[0])
              #
              xlrange  = ws.Range[ws.Cells(1, 2), ws.Cells(nbr_row, nbr_colum )]
              xlrange.EntireRow.RowHeight  = self.sizebitmap.Height
              ws.Range("a1").EntireColumn.ColumnWidth = self.sizebitmap.Width / 4
              a = Array.CreateInstance(object, nbr_row, nbr_colum - 1)
              #
              for indexR, row in enumerate(self.expSettings):
                  for indexC , value in  enumerate(row):
                      if indexC == 0 and value is not None:
                          Clipboard.SetDataObject(value)
                          rng  = ws.Range[ws.Cells(indexR + 1, 1), ws.Cells(indexR + 1 , 1)]
                          ws.Paste(rng, False)
                          
                      else:
                          a[indexR, indexC - 1] = value
                      
              #copy Array in range            
              xlrange.Value2 = a      
              used_range = ws.UsedRange   
              for column in used_range.Columns:
                  column.AutoFit()
                  
      toList = lambda x : x if hasattr(x, '__iter__') else [x]        
      listcat = toList(UnwrapElement(IN[0]))          
      #make filter            
      lstbipCat = [System.Enum.ToObject(BuiltInCategory, x.Id.IntegerValue) for x in listcat]         
      filtercat = ElementMulticategoryFilter(List[BuiltInCategory](lstbipCat))
      #collector
      fecSymb = FilteredElementCollector(doc).WherePasses(filtercat).WhereElementIsElementType().ToElements()
      outdata = []
      imgSize = Size( 100, 100 )
      for symb in fecSymb:
          bitm = symb.GetPreviewImage(imgSize) 
          famName = symb.Family.Name
          symbName = Element.Name.GetValue(symb)
          outdata.append([bitm, famName, symbName])
          
      #define folder to export        
      directory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
      
      objXls = ExcelUtils(outdata, directory + '\\test.xls', imgSize)
      objXls.exportXls()
      
      OUT = directory  
      

       Bonne Année et Meilleurs vœux 

      0 commentaires:

      Enregistrer un commentaire