21 sept. 2023

[Dynamo += Python] Cadrer une Vue 3D (CropBox)

 




Comment ajuster le cadrage d'une Vue 3D sous Revit ?


#CropBox#RevitAPI #DynamoBIM #3DView

if this article is not in your language, use the Google Translate widget ⬈ (bottom of page for Mobile version )



La "CropBox" (zone de cadrage de la Vue) joue un rôle crucial dans la définition de la portée visuelle de vos vues. Cependant, ajuster manuellement celles-ci peut être fastidieux, voyons comment l'automatiser sur des Vues 3D avec Dynamo.


Voici un script Python qui vous permet d'automatiser l'ajustement de la CropBox dans Revit en fonction des éléments présents dans une vue. 

Principe du script :

  • Collecte des éléments : Le script commence par collecter tous les éléments qui répondent à certains critères de filtrage, tels que la catégorie, la vue propriétaire et la présence d'une boîte englobante, pour ne garder que les éléments physiques.


  • Transformation des coordonnées : Pour chaque élément collecté, après obtention de leur boite englobante (BoundingBox), on transforme les coordonnées de celles-ci pour suivant la transformation de la vue 3D active.


  • Calcul des dimensions de la CropBox : Le script calcule ensuite les coordonnées minimales et maximales des points transformés pour déterminer les dimensions de la nouvelle CropBox de la vue. Des marges spécifiées peuvent être ajoutées pour un meilleur contrôle visuel.



code Python (fonctionne avec tous les moteurs Python)



import clr
import sys
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

def get_Global_Middle(all_bbx):
    """
    Calculates and returns the middle point of a collection of bounding boxes.
    """
    minX = min([bbx.Min.X for bbx in all_bbx])
    minY = min([bbx.Min.Y for bbx in all_bbx])
    minZ = min([bbx.Min.Z for bbx in all_bbx])
    
    maxX = max([bbx.Max.X for bbx in all_bbx])
    maxY = max([bbx.Max.Y for bbx in all_bbx])
    maxZ = max([bbx.Max.Z for bbx in all_bbx])
    
    return XYZ((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2 )

# Create a filter Predicate to select elements for processing
filterCatModel = System.Predicate[System.Object](lambda x: x.Category is not None and
                                                     x.Category.CategoryType == CategoryType.Model and 
                                                     x.OwnerViewId == ElementId.InvalidElementId and
                                                     x.get_BoundingBox(None) is not None )

# Create a filter to exclude certain built-in categories
builtInCat = List[BuiltInCategory]([BuiltInCategory.OST_Cameras, BuiltInCategory.OST_SectionBox])
not_filterCat = ElementMulticategoryFilter(builtInCat, True)

# Collect elements using the filters
lstElems = List[DB.Element](FilteredElementCollector(doc, doc.ActiveView.Id).WherePasses(not_filterCat).ToElements()).FindAll(filterCatModel)

# Get the active view and define margins
view = doc.ActiveView
margin = 1  # in feet
margin_anot = 0.01  # in feet

lstTfPts = []
lstBBx = []

# Start a transaction to modify the document
TransactionManager.Instance.EnsureInTransaction(doc)

# Transform the bounding box coordinates
tfView = view.CropBox.Transform.Inverse
for elem in lstElems:
    bbxElemB = elem.get_BoundingBox(view)
    if bbxElemB is not None:
        lstBBx.append(bbxElemB)
        pt1 = tfView.OfPoint(bbxElemB.Min)
        pt2 = tfView.OfPoint(XYZ(bbxElemB.Min.X, bbxElemB.Max.Y, bbxElemB.Min.Z))
        pt3 = tfView.OfPoint(XYZ(bbxElemB.Max.X, bbxElemB.Max.Y, bbxElemB.Min.Z))
        pt4 = tfView.OfPoint(XYZ(bbxElemB.Min.X, bbxElemB.Max.Y, bbxElemB.Min.Z))
        #
        pt5 = tfView.OfPoint(XYZ(bbxElemB.Min.X, bbxElemB.Min.Y, bbxElemB.Max.Z))
        pt6 = tfView.OfPoint(XYZ(bbxElemB.Max.X, bbxElemB.Min.Y, bbxElemB.Max.Z))
        pt7 = tfView.OfPoint(bbxElemB.Max)
        pt8 = tfView.OfPoint(XYZ(bbxElemB.Min.X, bbxElemB.Max.Y, bbxElemB.Max.Z))
        lstTfPts.extend([pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8])

# Calculate minimum and maximum coordinates from transformed points
minX = min(lstTfPts, key=lambda p: p.X).X
minY = min(lstTfPts, key=lambda p: p.Y).Y
maxX = max(lstTfPts, key=lambda p: p.X).X
maxY = max(lstTfPts, key=lambda p: p.Y).Y

# Define a new transformation
t = Transform.Identity
t.Origin = get_Global_Middle(lstBBx)
t.BasisX = tfView.BasisX
t.BasisY = tfView.BasisY
t.BasisZ = tfView.BasisZ

# Define a new bounding box
newBox = BoundingBoxXYZ()
newBox.Enabled = True
newBox.Min = XYZ(minX - margin, minY - margin, -10000)
newBox.Max = XYZ(maxX + margin, maxY + margin, -0.10)
newBox.Transform = t
view.CropBox = newBox

# Adjust crop margins
crop_shap_manag = view.GetCropRegionShapeManager()
crop_shap_manag.LeftAnnotationCropOffset = margin_anot
crop_shap_manag.RightAnnotationCropOffset = margin_anot
crop_shap_manag.BottomAnnotationCropOffset = margin_anot
crop_shap_manag.TopAnnotationCropOffset = margin_anot

# Complete the transaction
TransactionManager.Instance.TransactionTaskDone()

# Return the list of processed elements
OUT = lstElems

La connaissance s'accroît quand on la partage. (Socrate)

0 commentaires:

Enregistrer un commentaire