Problems editing wall profile - Python

Good morning.

I’m trying to edit the profile of a wall.
In my code below, I’ve managed to create a wall using the method shown. The wall is created in a basic way, but what I’m trying to do is edit the wall’s profile immediately after its creation. I’ve tried to do this, but without success. The code doesn’t return any runtime errors; it simply seems that it’s not assigning the profile to the wall. I know that “wall_profile = data[3]” is already a list of lists of native Revit lines and not Dynamo lines, where the first sublist is always the outline of the shape I want, and the other sublists are the perforations or openings in the wall. I’ve searched everywhere for something on the subject or how to achieve my goal, but I can’t find a solution or any way forward. Note that I’m using Revit 2023, in Dynamo with CyPython, which uses Python 3.8.10.

The AI ​​queries are only returning errors… so I would greatly appreciate any help in resolving this issue.

Thank you very much.
#region TRATAMIENTO PARA PODER OBTENER SUPERFICIES Y DATOS DEL ELEMENTO.

nivel_elemento = NivelElemento(elemento_recubrimiento_resultante, doc)

nuevo_nivel = MapearNuevoNivel(nivel_elemento, doc)



if solido_recubrimiento_resultante and nuevo_nivel:

    superficies_recubrimiento = Geometry.Explode(solido_recubrimiento_resultante)

    superficies_exteriores = \[\]

    for superficie in superficies_recubrimiento:

        evaluacion = Geometry.DoesIntersect(superficie, solido_elemento_resultante)

        if evaluacion == False:

            superficies_exteriores.append(superficie)



    class FailuresPreprocessorPerfil(IFailuresPreprocessor):

        def PreprocessFailures(self, failuresAccessor):

            return FailureProcessingResult.Continue



    for su in superficies_exteriores:

        tipo_superficie = TipoSuperficie(su)

        if tipo_superficie == "Plana":

            tipo_orientacion = OrientacionSuperficie(su)

            if tipo_orientacion == "MURO NORMAL":

                datos = DatosSuperficiePlanaVertical(su, nuevo_nivel)

                altura_muro   = datos\[0\]

                desfase_muro  = datos\[1\]

                eje_muro      = datos\[2\]

                perfil_muro   = datos\[3\]




                \# Crear muro

                TransactionManager.Instance.EnsureInTransaction(doc)

                nuevo_muro = Wall.Create(

                    doc,

                    eje_muro,

                    tipo_muro.Id,

                    nuevo_nivel.Id,

                    altura_muro \* 3.28084,

                    desfase_muro \* 3.28084,

                    False,

                    False

                )

                TransactionManager.Instance.TransactionTaskDone()

                X.append(nuevo_muro)

                \# Editar perfil inmediatamente

                if nuevo_muro and nuevo_muro.CanHaveProfileSketch():

                    sketch_id = nuevo_muro.SketchId

                    sketch = doc.GetElement(sketch_id) if sketch_id else None

                    if sketch:

                        sketchEditScope = SketchEditScope(doc, "Editar perfil de muro")

                        sketchEditScope.Start(sketch.Id)



                        t = Transaction(doc, "Modificar perfil de muro")

                        t.Start()

                        try:

                            \# Eliminar curvas existentes

                            for elId in sketch.GetAllElements():

                                doc.Delete(elId)



                            plano_sketch = sketch.SketchPlane



                            \# Crear curvas del contorno y huecos en orden

                            for loop in perfil_muro:   # primer loop = contorno, demás = huecos

                                for curva in loop:

                                    doc.Create.NewModelCurve(curva, plano_sketch)



                            t.Commit()

                        except Exception as e:

                            if t.HasStarted():

                                t.RollBack()

                            sketchEditScope.Cancel()

                            raise Exception("Error al modificar perfil del muro: {}".format(e))



                        sketchEditScope.Commit(FailuresPreprocessorPerfil())

#endregion

OUT = X

Hi,

Try using this method directly instead of editing the wall.

public static Wall Create(
	Document document,
	IList<Curve> profile,
	ElementId wallTypeId,
	ElementId levelId,
	bool structural
)

Resource and example for adding a hole.

For a single opening (list of joined model lines in this instance)

@AMMED You will need to reconfigure to run for multiple wall definitions / openings.

Good luck :slightly_smiling_face:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from System.Collections.Generic import List

doc = DocumentManager.Instance.CurrentDBDocument

# Inputs
profCurves = IN[0] if isinstance(IN[0], list) else [IN[0]]
profCurves = [UnwrapElement(c) for c in profCurves]
wType = UnwrapElement(IN[1])
lvl = UnwrapElement(IN[2])
openCurves = IN[3] if isinstance(IN[3], list) else [IN[3]] if len(IN) > 3 and IN[3] else []
openCurves = [UnwrapElement(o) for o in openCurves] if openCurves else []

msgs = []

try:
    TransactionManager.Instance.EnsureInTransaction(doc)
    
    allCurves = profCurves + openCurves
    
    cList = List[Curve]()
    minZ = None
    
    # Add all curves to list and find minimum Z elevation
    for c in allCurves:
        gc = c.GeometryCurve
        cList.Add(gc)
        
        p1 = gc.GetEndPoint(0)
        p2 = gc.GetEndPoint(1)
        
        if minZ is None:
            minZ = min(p1.Z, p2.Z)
        else:
            minZ = min(minZ, p1.Z, p2.Z)
    
    # Calculate base offset to align wall with curves
    lvlElev = lvl.Elevation
    baseOffset = minZ - lvlElev
    
    # Calculate horizontal normal vector perpendicular to wall profile
    fc = cList[0]
    p1 = fc.GetEndPoint(0)
    p2 = fc.GetEndPoint(1)
    
    v1 = p2.Subtract(p1).Normalize()
    norm = v1.CrossProduct(XYZ.BasisZ).Normalize()
    
    if norm.IsAlmostEqualTo(XYZ.Zero):
        if cList.Count > 1:
            sc = cList[1]
            p3 = sc.GetEndPoint(0)
            v2 = p3.Subtract(p1).Normalize()
            norm = v2.CrossProduct(XYZ.BasisZ).Normalize()
        else:
            norm = XYZ.BasisX
    
    # Create wall from profile curves
    wall = Wall.Create(doc, cList, wType.Id, lvl.Id, False, norm)
    
    # Set base offset parameter
    offsetParam = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET)
    if offsetParam != None:
        offsetParam.Set(baseOffset)
    
    TransactionManager.Instance.TransactionTaskDone()
    OUT = wall
    
except Exception as e:
    TransactionManager.Instance.TransactionTaskDone()
    OUT = str(e)
3 Likes
Thank you so much, it was very helpful... thanks.

Good day.
I apologize for reopening this thread... I'm having a problem... I used this code before in another project and it worked... but I don't know why it's telling me I'm entering an incorrect argument... ??? Or maybe it's a problem with my Revit; perhaps it's corrupted, or maybe I accidentally deleted something?
Thank you for your help.

Prueba_superficie.rvt (6.2 MB)

Error_perfile_muro.dyn (55.3 KB)

Good morning.
I’ve been experimenting a bit more with the wall creation method and I’ve encountered some strange behavior. In my images, I see a wall with windows and a door, and if I select the wall face, the method creates a new wall with the profile. However, if I raise the door a little higher, the method stops creating the new wall and tells me there’s an error with the profile line list. Could someone explain this behavior in more detail, why it happens, and how to fix it?

This is driving me crazy… or have my Revit and Dynamo gone haywire…?

lst_plana_lineas_revit_u must be a List<Curve> not a python list

With PythonNet, you must strictly adhere to the signature of a .NET method, which means that:

  • The method name is correct.
  • The method is called on the correct type of object (instance method vs static method).
  • The types of objects passed as arguments are correct.

If you pass a native Python list to a .NET method that expects a .NET collection, you must explicitly cast/convert the Python list.

from System.Collections.Generic import List
# rest of code
# Convertimos las líneas de dynamo a líneas nativas de revit
lst_plana_lineas_revit_u = List[Curve]()
for li in lst_plana_lineas_dynamo:
    lrevit = li.ToRevitType()
    lst_plana_lineas_revit_u.Add(lrevit)
1 Like

I just like create the wall with profile, and use a real opening node or void after IMO just more easy, instead of wall by profile with opening loops..just faster when thing change…and again just IMO :wink: hahah

For internal loops with Wall.Create() , there are rules to follow regarding the order of curves.

https://forums.autodesk.com/t5/revit-api-forum/create-wall-using-curves/td-p/13188675

1 Like

Thanks for the link.
I’ve checked the forum comments, but what they’re saying isn’t entirely accurate. I’ve run multiple tests, and it only works in a few rare cases. It’s not because the line is vertical or horizontal; I’ve even been able to create walls by going in the opposite direction to what the post suggests. This leads me to conclude that this isn’t the reason or method for creating walls. I’ve tried analyzing it line by line, segment by segment, point by point, coordinate by coordinate, and I haven’t been able to find the cause of the failure. I’m still working on it. If anyone has a solution, I would be very grateful.