Any pyRevit utility that can generate elevation from selected WALLS?

Is there a pyRevit utility that can generate elevation/s from selected WALLS?
I understand elevations can be generated for rooms, including obscure shape ones by utilising pyChilizer extension. Ability to generate elevations from selected WALLs would be fantastic for the generation of Precast Wall setout drawings, Window/Curtain Wall elevations, Feature Wall elevations etc…

I’ve spent 2 days trying to develop a dynamo script to undertake this, but have been unsuccessful.

Please help!
I am also aware of this guide, which utilises model lines - however, it does not work with walls, and it fails to consider view crop height to match the wall.

1 Like

@mwarnecke ,

the link is realy well explaned. The python snippets are good to convert look:

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
app = __revit__.Application


# ╔╦╗╔═╗╦╔╗╔
# ║║║╠═╣║║║║
# ╩ ╩╩ ╩╩╝╚╝ MAIN
# ==================================================


import time
start_time = time.time()

# 📝 conditions
toggle = True

# 0️⃣ Variables
elements = []
names = []
lst = []

# 🎯 Get ViewTypes
collector = FilteredElementCollector(doc).OfClass(ViewFamilyType).ToElements()

for i in collector:
    if i.ViewFamily == ViewFamily.Elevation:
        elements.append(i)

        for j in i.Parameters:
            if j.Definition.Name == "Type Name":
                names.append(j.AsString())

lst.append(elements)
lst.append(names)
print(lst)
# ____________________________________________________________________

# ____________________________________________________________________
# Geometry

points = []
modelPoints = []
cropCurves = []
viewType = []

# ____________________________________________________________________

# 0️⃣ Variables
finalList = []

# 🎯 Get ViewTypes
if toggle == True:

    # 🔓 Start
    t = Transaction(doc, "Set View to Element")
    t.Start()
    for ind, point in enumerate(points):
        modelMP = modelPoints[ind].ToXyz()
        modelMPX = modelMP.X
        modelMPY = modelMP.Y

        cropLines = cropCurves[ind].ToXyz()
        l1 = cropLines[0].ToRevitType()
        l2 = cropLines[1].ToRevitType()
        l3 = cropLines[2].ToRevitType()
        l4 = cropLines[3].ToRevitType()

        elevationPT = point.ToXyz()
        elptRotate = XYZ(elevationPT.X, elevationPT.Y, elevationPT.Z+100)
        ln = Line.CreateBound(elevationPT, elptRotate)

        elevationPTY = elevationPT.Y
        elevationPTX = elevationPT.X
        combY = elevationPTY - modelMPY
        combX = elevationPTX - modelMPX
        ang = atan(combY, combX)

        eleMarker = ElevationMarker.CreateElevationMarker(doc,viewType.Id, elevationPT, 100)
        ele = eleMarker.CreateElevation(doc, eleMarker.Id, ln, ang)

        crManager = ele.GetCropRegionShapeManager()

        newCurveLoop = []
        newCurveLoop.Add(l1)
        newCurveLoop.Add(l2)
        newCurveLoop.Add(l3)
        newCurveLoop.Add(l4)
        cLoop = CurveLoop.Create(newCurveLoop)

        try:
            crManager.SetCropRegionShape(cLoop)
            finalList.append("Elevation Created")

        except:
            pass
            finalList.append("Missed Elevation")

    t.Commit()
    # 🔒 Done!
    print(finalList)
else:
    print(finalList)

end_time = time.time()
print('\n Laufzeit: {} Sekunden'.format(end_time - start_time))

only one thing where i stuck is handling geometry. I hope here can someone help. I think pickObject methode and ISelection filter would work.

so i can use ISelection finally getting lines and points :wink:

Who can bridge the gab…

class CustomFilter(ISelectionFilter):

    def AllowElement(self, element):
        if element.Category.BuiltInCategory == BuiltInCategory.OST_Walls:
            return True

# ⭕ ISelectionFilter - Category wall only
custom_filter     = CustomFilter()
selected_walls = selection.PickElementsByRectangle(custom_filter, "Select walls ")

wallCurves = [i.Location.Curve for i in selected_walls]
# startpoints
startPoints = []
# endpoints
endPoints = []

for wall in selected_walls:
    wallCurve = wall.Location.Curve
    startPoints.append(wallCurve.GetEndPoint(0))
    endPoints.append(wallCurve.GetEndPoint(1))

result = [i for i in zip(startPoints, endPoints)]

for i in result:
    print(i)

for i in wallCurves:
    print(i)

@ErikFrits showed a code snippet in its latest yt video

1 Like

@mwarnecke ,

i found this from PyRevitMEP

# coding: utf8

__doc__ = """Create sections from selected linear objects (eg. walls)
SHIFT-CLICK to display options"""
__title__ = "CreateSectionFrom"
__author__ = "Cyril Waechter"
__context__ = "selection"


from Autodesk.Revit.DB import (
    Document,
    Line,
    FilteredElementCollector,
    ViewFamilyType,
    ViewFamily,
    Element,
    ViewSection,
    Transform,
    BoundingBoxXYZ,
    XYZ,
    BuiltInParameter,
)
from Autodesk.Revit.UI import UIDocument
from Autodesk.Revit import Exceptions

from pyrevit import script, forms, revit

uidoc = revit.uidoc  # type: UIDocument
doc = revit.doc  # type: Document
logger = script.get_logger()

section_types = {
    Element.Name.__get__(vt): vt
    for vt in FilteredElementCollector(doc).OfClass(ViewFamilyType)
    if vt.ViewFamily == ViewFamily.Section
}

section_type = section_types.get(
    forms.ask_for_one_item(
        section_types.keys(),
        section_types.keys()[0],
        prompt="Select view section type to use for generated sections",
        title="Select section type",
    )
)


# Retrieve parameters from config file
_config = script.get_config()
prefix = _config.get_option("prefix", "Mur")
depth_offset = float(_config.get_option("depth_offset", "1"))
height_offset = float(_config.get_option("height_offset", "1"))
width_offset = float(_config.get_option("width_offset", "1"))

sections = []

for element_id in uidoc.Selection.GetElementIds():
    element = doc.GetElement(element_id)  # type: Element

    # Determine if element can be used to create a section
    try:
        curve = element.Location.Curve
        if not isinstance(curve, Line):
            raise AttributeError
    except AttributeError:
        logger.info("{} has no Line Curve to guide section creation".format(element))
        continue

    # Create a BoundingBoxXYZ oriented parallel to the element
    curve_transform = curve.ComputeDerivatives(0.5, True)

    origin = curve_transform.Origin
    wall_direction = curve_transform.BasisX.Normalize()  # type: XYZ
    up = XYZ.BasisZ
    section_direction = wall_direction.CrossProduct(up)
    right = up.CrossProduct(section_direction)

    transform = Transform.Identity
    transform.Origin = origin
    transform.BasisX = wall_direction
    transform.BasisY = up
    transform.BasisZ = section_direction

    section_box = BoundingBoxXYZ()
    section_box.Transform = transform

    # Try to retrieve element height, width and lenght
    try:
        el_depth = element.WallType.Width
    except AttributeError:
        el_depth = 2

    el_width = curve.Length

    el_bounding_box = element.get_BoundingBox(None)
    z_min = el_bounding_box.Min.Z
    z_max = el_bounding_box.Max.Z
    el_height = z_max - z_min

    # Get Wall Offset Params if Element is Wall
    try:
        base_offset = element.Parameter[BuiltInParameter.WALL_BASE_OFFSET].AsDouble()
    except AttributeError:
        base_offset = 0

    # Set BoundingBoxXYZ's boundaries
    section_box.Min = XYZ(
        -el_width / 2 - width_offset,
        -height_offset + base_offset,
        -el_depth / 2 - depth_offset,
    )
    section_box.Max = XYZ(
        el_width / 2 + width_offset,
        el_height + height_offset + base_offset,
        el_depth / 2 + depth_offset,
    )

    # Append necessary parameters to create sections in a list
    suffix_param = element.get_Parameter(BuiltInParameter.DOOR_NUMBER)
    sections.append(
        {
            "box": section_box,
            "suffix": suffix_param.AsString() if suffix_param.HasValue else None,
        }
    )

with revit.Transaction("Create sections", doc):
    fallback_suffix = 1
    for section in sections:
        section_view = ViewSection.CreateSection(doc, section_type.Id, section["box"])
        base_suffix = section["suffix"]
        if base_suffix:
            try:
                section_view.Name = "{} {}".format(prefix, base_suffix)
            except Exceptions.ArgumentException:
                print(
                    "Failed to rename view {}. Desired name already exist.".format(
                        section_view.Name
                    )
                )
        else:
            while fallback_suffix < 10000:
                try:
                    section_view.Name = "{} {}".format(prefix, fallback_suffix)
                except Exceptions.ArgumentException:
                    fallback_suffix += 1
                    continue
                break




it works great!

1 Like

Do you know if there’s a way of controlling the orientation of the section with this tool?

The tool works great, but I’d like to be able to specify which side of the wall for example.

Thanks

By a quick look at the code, you would need to change the origin with the other end of the curve_transform and invert the wall_direction vector, so that the transformation matrix applied to the section_box points to the other side.