How to get lines from the columns..?

Good day.
I am currently working with columns and I have run into the following problem…! I describe the problem below and attach some images.
When applying the GET LOCATION it returns me points of the VERTICAL columns but in the inclined columns it returns a LINE.
By what means, method, node or code can I obtain the lines of all the columns, both vertical and inclined.
Taking into consideration something particular that happens with the line of the INCLINED COLUMN when applying GET LOCATION, this line that returns is a complete line of the column, I mention this since a possible solution would be to create lines and apply an INTERSECT in order to stay with the intersection cut, but that would only return what is inside the geometry, not the actual length of the column and what is required as the final result is the REAL LINE of the column as it happens in the INCLINED COLUMN.
I greatly appreciate your comments and suggestions.

Good morning,

Here’s a line of thought:

1/Create a large surface at about mid-height to shoot all the side surfaces of the columns with the intersections of all the surfaces with this surface
2/ create lines for the non-inclined posts with a vector (0,0,1) from point location
3/ Unify all the remaining surfaces
4/ split column curves with the polysurface
5/ take the biggest curves

Surely there must be something easier

Cordially
christian.stan

Any sample images please?

here is


cordially
christian.stan

Perhaps a simpler solution in terms of node count and memory consumption: use a custom function and a List.Filter node to split the objects by resulting geometry type of the location.

The function would have 3 steps: GetLocation node, Object.Type node, and an == node looking for the object type returned by a line.

On the upper (equal to lines) output of the List.filter node you can use a GetLocation node as is.

On the lower (not equal to lines) output of the list.Filter node you can use a GetLocation node followed by a Line.ByBestFitThroughPoints node. The locations can then be merged into one list via a List.Join, as can the in and out inputs if you need to keep the column sort the same as the locations for other downstream use.

1 Like

by analyzing non-visible geometries

import clr
import sys
import System
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

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

#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_line_of_column(column):
    global opt
    if isinstance(column.Location, DB.LocationCurve):
        return column.Location.Curve.ToProtoType()
    else:
        geo_set = column.get_Geometry(opt)
        for geo in geo_set:
            if isinstance(geo, DB.Line):
                #
                return geo.ToProtoType()
        
opt = Options()
opt.DetailLevel = ViewDetailLevel.Coarse
opt.IncludeNonVisibleObjects = True


lst_elems = UnwrapElement(IN[0])

OUT = [get_line_of_column(x) for x in lst_elems]
2 Likes

Hi, even by mastering python I would miss it.
(brilliant to use the level of detail: respect M.)

cordially
christian.stan

1 Like

First I would like to thank you for your support and response.
You see, I don’t have the intellectual capacity that you have in Python to be able to understand what is happening in the code.
I would really appreciate it if you could make the code a bit simpler as a step by step so that I can learn from you… I am very new to python.
On the other hand, where I could learn to manipulate the invisible geometry… because it is exactly what I am needing… Thank you very much for your help

@AM3D.BIM.STUDIO

here is the code with comments


# Import necessary modules and references
import clr
import sys
import System
clr.AddReference('ProtoGeometry')  # add ProtoGeometry reference for importing DesignScript.Geometry
from Autodesk.DesignScript.Geometry import *  # import DesignScript.Geometry
import Autodesk.DesignScript.Geometry as DS  # import DesignScript.Geometry as DS for convenience

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

# Import RevitNodes for importing extensions
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

# Import transactionManager and DocumentManager for interacting with the Revit document in Dynamo context
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument

# Define a function to get the line of a column
def get_line_of_column(column):
    global opt  # Declare the global 'opt' variable

    # Check if the location of the column is a DB.LocationCurve object
    if isinstance(column.Location, DB.LocationCurve):
        # If it is, return the location's curve as a ProtoGeometry type
        return column.Location.Curve.ToProtoType()
    else:
        # If it is not, get the geometry of the column with the 'opt' options and check for a line in the geometry set
        geo_set = column.get_Geometry(opt)
        for geo in geo_set:
            if isinstance(geo, DB.Line):
                # If a line is found, return it as a ProtoGeometry type
                return geo.ToProtoType()

# Define options for getting geometry from the Revit document
opt = Options()
opt.DetailLevel = ViewDetailLevel.Coarse
opt.IncludeNonVisibleObjects = True

# Unwrap input elements from Revit document
lst_elems = UnwrapElement(IN[0])

# Call the 'get_line_of_column' function for each input element and output a list of the returned lines
OUT = [get_line_of_column(x) for x in lst_elems]

for the IncludeNonVisibleObjects property, there is some explanation here

3 Likes

Like the lines, could you help me to obtain the surface of the upper lid, the surface of the lower lid, and the surfaces that are on the sides?

The LocationCurve is a line. It has a start and end XYZ. The points you want.
The verticals have a LocationPoint. You can use that with the associated levels and top and bottom offsets to calculate the points and the line between. It is just a + and - Z value.

1 Like

A code review using a dictionary at output


# Import necessary modules and references
import clr
import sys
import System
clr.AddReference('ProtoGeometry')  # add ProtoGeometry reference for importing DesignScript.Geometry
from Autodesk.DesignScript.Geometry import *  # import DesignScript.Geometry
import Autodesk.DesignScript.Geometry as DS  # import DesignScript.Geometry as DS for convenience

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

# Import RevitNodes for importing extensions
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

# Import transactionManager and DocumentManager for interacting with the Revit document in Dynamo context
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument

# Define a function to get the geometry of a column
def get_Geometry_column(column):
    global opt  # Declare the global 'opt' variable
    dict_geo = {"RvtElement": column, "Line" : None, "VerticalSurfaces" : [], "TopBottomSurfaces" : []}
    #  get the geometry of the column with the 'opt' options and check for a line in the geometry set
    geo_set = column.get_Geometry(opt)
    if isinstance(column.Location, DB.LocationCurve):
        dict_geo["Line"] =  column.Location.Curve.ToProtoType()
    else:
        for geo in geo_set:
            if isinstance(geo, DB.Line):
                # If a line is found, return it as a ProtoGeometry type
                dict_geo["Line"] = geo.ToProtoType()
    # get the surfaces
    for geo in geo_set:
        if isinstance(geo, DB.Solid):
            for face in geo.Faces:
                bbxUV = face.GetBoundingBox()
                midUV = (bbxUV.Min + bbxUV.Max) *0.5
                faceNormal = face.ComputeNormal(midUV)
                # check if this vector is parrallal to the line coloumn
                if abs(faceNormal.DotProduct(dict_geo["Line"].Direction.ToXyz())) < 0.1:
                    dict_geo["VerticalSurfaces"].extend(face.ToProtoType())
                else:
                    dict_geo["TopBottomSurfaces"].extend(face.ToProtoType())
    # sort the TopBottomSurfaces
    dict_geo["TopBottomSurfaces"] = sorted(dict_geo["TopBottomSurfaces"], key = lambda surf : surf.PointAtParameter(0.5, 0.5).Z, reverse = True)
    #geo_set.Dispose()
    return dict_geo

# Define options for getting geometry from the Revit document
opt = Options()
opt.DetailLevel = ViewDetailLevel.Coarse
opt.IncludeNonVisibleObjects = True

# Unwrap input elements from Revit document
lst_elems = [x for x in UnwrapElement(IN[0]) if x.Category.Id == ElementId(BuiltInCategory.OST_StructuralColumns)]

# Call the 'get_line_of_column' function for each input element and output a list of the returned lines
OUT = [get_Geometry_column(x) for x in lst_elems]
3 Likes

Hello, Mr Poupin
I tried to transcribe your code in Cpython3 starting from an element at startup to learn and progress
I have many questions :
How to install IronPython 2 engine (just in case)?
Why are there 2 Solids (in the geometry)?
What type of data are bb.Min and bb.Max (list or tuple)

a=UnwrapElement(IN[0])
temp=[]
opt = Options()
opt.DetailLevel = ViewDetailLevel.Fine
geo_set=a.get_Geometry(opt)
for geo in geo_set:
    if isinstance(geo, DB.Solid):
        for face in geo.Faces:
            bb=face.GetBoundingBox()
            #midUV = (bb.Min + bb.Max) *0.5
            coord_UV=((bb.Max[0]+bb.Min[0])/2,(bb.Max[1]+bb.Min[1])/2)
            
            temp.append(coord_UV)
OUT =temp,geo_set,type(bb.Min),bb.Min,bb.Max

image

It is not a request for transcription in Cpython 3 that I am asking you, those are tracks to be able to achieve this
thanks in advance

edit

I progress

cor_rev=UV((bb.Max[0]+bb.Min[0])/2,(bb.Max[1]+bb.Min[1])/2)
faceNormal = face.ComputeNormal(cor_rev)
temp.append(faceNormal)

edit2:
I succeeded
image

Cordially
christian.stan

1 Like

Good morning colleague. Thanks for your support and your comments.
You see, I’m very new to this PYTHON thing, I don’t understand your code.
When I mean to simplify it, I am referring to being able to code step by step… since the intention is not only to solve the problem, but also to learn from the way the solution is proposed, my goal behind all my questions It is to learn from the basics of how to break down the problem and based on it, solve each fragment of the problem, I hope you understand me and thank you very much again

1 Like

hello, I learn from the many codes present on the forum, there is a lot to learn when you start from scratch like me (I think that even sometimes I skip important steps of the good basic mastery of python before titillating the api, regular feedback is also good in progress, at each their own pace)
good learning, (my “lux”_python is still weak, I have to work, there are no secrets only facts)
Good evening
Cordially
christian.stan

The Surface that is missing there is a side face, internement revit knows what its top and bottom faces are as well as it knew what its lines were.??

@AM3D.BIM.STUDIO

I use operations between vector to determine if the Face Normal is perpendicular to the column line vector

I wrote an article about vectors operation, maybe can help you (use the translation button, if necessary)

3 Likes

Math Operator overloading is not supported in PythonNet 2.5.2 (the problem is not Cpython3)

pending PythonNet3.0 which fixes the problem :

  • you can use Math methods too (like Add() , Divide() , Multiply() , Subtract() )
    OR
  • install IronPython2 with Package Manager

1 Like


Use Element.GetActualLocation