Fan des coupes sur Revit? Voici une petite aide à la création
if this article is not in your language, use the Google Translate widget
(bottom of page for Mobile version) ⬈
La réalisation de coupes sur la plupart des viewer IFC se fait à partir d'une sélection de surface, mais comment réaliser une fonction similaire sous Revit avec Python ?
Voici un script qui permet de faire une coupe à partir d'une sélection
d'une face, peu importe l'orientation, qu'il s'agisse d'une face liée (maquette liée) ou locale.
Pour ceux qui découvrent la notion de Transformation, vous avez dans ce code un bon exemple d'usage.
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
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
class FaceSelection(ISelectionFilter):
def AllowElement(self, e):
return True
def AllowReference(self, ref, point):
if ref.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_SURFACE:
return True
else:
return False
viewFamilyType = FilteredElementCollector(doc).OfClass(ViewFamilyType).ToElements().Find(lambda x : x.ViewFamily == ViewFamily.Section)
v = None
margin_c = 0.4
#
TaskDialog.Show("Selection", "Pick Point on a Planar Face")
ref = uidoc.Selection.PickObject(ObjectType.PointOnElement, FaceSelection(), "Pick Point on a Planar Face")
# get Face Geometry
sel_elem = doc.GetElement(ref)
if isinstance(sel_elem, RevitLinkInstance):
tf1 = sel_elem.GetTotalTransform()
linkDoc = sel_elem.GetLinkDocument()
elem = linkDoc.GetElement(ref.LinkedElementId)
if isinstance(elem, FamilyInstance):
tf2 = elem.GetTotalTransform()
tf1 *= tf2
face_ref2 = ref.CreateReferenceInLink()
face = elem.GetGeometryObjectFromReference(face_ref2)
else:
elem = sel_elem
face = elem.GetGeometryObjectFromReference(ref)
if isinstance(elem, FamilyInstance):
tf1 = sel_elem.GetTotalTransform()
else:
tf1 = Transform.Identity
#
bbxUV = face.GetBoundingBox()
midpoint = tf1.OfPoint(face.Evaluate((bbxUV.Min + bbxUV.Max) * 0.5))
# get the max point on face
pt_maxUV = tf1.OfPoint(face.Evaluate(bbxUV.Max))
pt_minUV = tf1.OfPoint(face.Evaluate(bbxUV.Min))
maxptZface = max([pt_maxUV, pt_minUV], key = lambda x : x.Z)
selectPoint = ref.GlobalPoint
# get faceNormal and compute the margin for section View
faceNormal = tf1.OfVector(face.ComputeNormal((bbxUV.Min + bbxUV.Max) * 0.5).Negate())
bbxElem = elem.get_BoundingBox(None)
minUV = bbxUV.Min
maxUV = bbxUV.Max
midleUV = (bbxUV.Min + bbxUV.Max) * 0.5
marginCropbox = UV(margin_c, margin_c) # margin_c -> 0.4
# calculate minUV and maxUV for section
min_uv = minUV - midleUV - marginCropbox
max_uv = maxUV - midleUV + marginCropbox
# calculate Basis for section BBX
zV = faceNormal
if faceNormal.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero):
xV = XYZ.BasisY.CrossProduct(faceNormal).Normalize()
else:
xV = XYZ.BasisZ.CrossProduct(faceNormal).Normalize()
yV = zV.CrossProduct(xV).Normalize()
#
t = Transform.Identity
t.Origin = midpoint
t.BasisX = xV
t.BasisY = yV
t.BasisZ = zV
#
sectionBox = BoundingBoxXYZ()
sectionBox.Enabled = True
sectionBox.Min = XYZ(min_uv.U, min_uv.V, -2)
sectionBox.Max = XYZ(max_uv.U, max_uv.V, 0.5)
sectionBox.Transform = t
#
TransactionManager.Instance.EnsureInTransaction(doc)
#
v = DB.ViewSection.CreateSection(doc, viewFamilyType.Id, sectionBox)
v.get_Parameter(BuiltInParameter.VIEWER_BOUND_FAR_CLIPPING).Set(1)
#
# fix some outline on vertical and horizontal view section
crsm = v.GetCropRegionShapeManager()
# fix with horizontal faces -> use face_curvLoop with offset
if abs(faceNormal.Z) > 0.99:
face_curvLoop = face.GetEdgesAsCurveLoops()[0]
curveloop_shape = CurveLoop.CreateViaTransform(face_curvLoop, tf1)
curveloop_shape = CurveLoop.CreateViaOffset(curveloop_shape, 1.02, v.ViewDirection)
crsm.SetCropShape(curveloop_shape)
# check with vertical faces
# rotate 90 degre the 'outline curveloop shape' if any curve of 'curveloop shape' are not near to maxptface point
elif abs(faceNormal.Z) < 0.01:
curveloop_shape = crsm.GetCropShape()[0]
tf3 = Transform.CreateRotationAtPoint(faceNormal, System.Math.PI * 0.5, midpoint)
candiate_curveloop_shape = CurveLoop.CreateViaTransform(curveloop_shape, tf3)
maxZCurveLoop = max(c.GetEndPoint(i).Z for c in curveloop_shape for i in range(2))
if not margin_c - 0.01 <= abs(maxZCurveLoop - maxptZface.Z) < margin_c + 0.1:
crsm.SetCropShape(candiate_curveloop_shape)
else:
pass
#
TransactionManager.Instance.TransactionTaskDone()
TransactionManager.Instance.ForceCloseTransaction()
#
uidoc.RequestViewChange(v)
OUT = face, selectPoint.ToPoint(), midpoint.ToPoint(), maxptZface.ToPoint(), faceNormal
Note 1
Le cadrage des vues de coupe sera alignée à la 'BoundingBox' de la face, mais parfois, dû aux caractéristiques de certaines d'entre elles, il se peut que le cadrage soit décalé.
Note 2
Le contour des vues de coupes horizontales est alignée au contour de la face sélectionnée.
Aperçu en Vidéo
Bonjour Cyril, j'ai Revit 2023 avec sa dernière mise à jour, donc Dynamo 2.16
RépondreSupprimerAvec le scrip, j'ai une erreur ligne 40 'list' object as no attribut 'file'
Daniel OLIVES d.olives@live.fr
Bonjour Cyril, j'ai la version 2.16 de Dynamo et j'ai un message d'erreur en ligne 40 'list' as no attribut 'Find'
RépondreSupprimerDaniel OLIVES
Salut, utilise IronPython2
Supprimer