Set the family instance's Point location at its center in Python

Hi everyone,
This thread is related to my last topic How to place family Instances according to the levels below them in python ; After placing my instances according my levels I should rotate the even ones by 180 degrees as shown in the reference below but they become miss placed because their point location which is their rotation axis is not in their center, so How can I set it to the center to avoid this issue

Here my script:

Python_code
import sys
import clr
import math
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitNodes')
import Revit
from Revit.Elements import *

R_exter_Shaft = IN[0]
Thk_Shaft = IN[1]
R_inter_Shaft = R_exter_Shaft - Thk_Shaft 
H_Total = IN[2]
H_Shaft = IN[3]
Thk_Slab = IN[4]
H_1 = H_Shaft - Thk_Slab
Family_Cat = IN[5]
Family_Path = IN[6]
Material = IN[7]
Family1_name = 'Shaft1'
Family2_name = 'Shaft2'
Long_Trape = 0.8
angle_Trape = math.degrees(math.atan((Long_Trape/2) / R_inter_Shaft))

# Set Levels_List
n = int(math.ceil(H_Total / H_Shaft))
if H_Total % H_Shaft > 0:
    H_2 = H_Total - (n-1) * H_Shaft
else:
    H_2 = 0

#Shaft1_Profil
lst1 = []
Pt1 = Point.ByCoordinates( R_exter_Shaft, 0, -Thk_Slab)
lst1.append(Pt1)
Pt2 = Point.ByCoordinates( R_exter_Shaft, 0, H_1)
lst1.append(Pt2)
Pt3 = Point.ByCoordinates( R_inter_Shaft , 0, H_1)
lst1.append(Pt3)
Pt4 = Point.ByCoordinates( R_inter_Shaft , 0, -Thk_Slab)
lst1.append(Pt4)
vector = Vector.ByCoordinates(0, 0, 1)
Center_pt = Point.ByCoordinates(0, 0, 0)
Shaft1_Profil = Polygon.ByPoints(lst1)
Shaft1 = Solid.ByRevolve(Shaft1_Profil, Center_pt, vector, 0, 360)

#Shaft2_Profil
lst2 = []
Pt_1 = Point.ByCoordinates( R_exter_Shaft, 0, -Thk_Slab)
lst2.append(Pt_1)
Pt_2 = Point.ByCoordinates( R_exter_Shaft, 0, H_2)
lst2.append(Pt_2)
Pt_3 = Point.ByCoordinates( R_inter_Shaft , 0, H_2)
lst2.append(Pt_3)
Pt_4 = Point.ByCoordinates( R_inter_Shaft , 0, -Thk_Slab)
lst2.append(Pt_4)
vector = Vector.ByCoordinates(0, 0, 1)
Center_pt = Point.ByCoordinates(0, 0, 0)
Shaft2_Profil = Polygon.ByPoints(lst2)
Shaft2 = Solid.ByRevolve(Shaft2_Profil, Center_pt, vector, 0, 360)

Slab_Profil = Surface.ByPatch(Circle.ByCenterPointRadius(Center_pt, R_inter_Shaft ))
Slab = Surface.Thicken(Slab_Profil, -Thk_Slab, bool(0))

# opening profil to be subtract from the slab
Trape_arc = Arc.ByCenterPointRadiusAngle(Center_pt, R_inter_Shaft, -angle_Trape, angle_Trape, vector )
Pt1 = Trape_arc.StartPoint
Pt2 = Trape_arc.EndPoint
Pt3 = Pt1.Translate(-Long_Trape)
Pt4 = Pt2.Translate(-Long_Trape)
Line1 = Line.ByStartPointEndPoint(Pt3, Pt4)
Line2 = Line.ByStartPointEndPoint(Pt3, Pt1)
Line3 = Line.ByStartPointEndPoint(Pt4, Pt2)

Profil_Trape = Surface.ByPatch(PolyCurve.ByJoinedCurves([Line1, Line2, Trape_arc, Line3]))
Trape = Surface.Thicken(Profil_Trape, Thk_Slab, bool(0))

Finale_Slab = Solid.Difference(Slab, Trape)

# Shaft1 geometry and Family Type
lst3 = [Shaft1, Finale_Slab]
Final_Shaft1 = Solid.ByUnion(lst3)
Final_Shaft1 = Geometry.Translate(Final_Shaft1, -Thk_Slab)
Final_Shaft1 = Geometry.Scale(Final_Shaft1, 0.3048)
Final_Shaft1 = FamilyType.ByGeometry(Final_Shaft1, Family1_name, Family_Cat, Family_Path, Material, 'a')

# Shaft2 geometry and Family Type
lst4 = [Shaft2, Finale_Slab]
Final_Shaft2 = Solid.ByUnion(lst4)
Final_Shaft2 = Geometry.Translate(Final_Shaft2, -Thk_Slab)
Final_Shaft2 = Geometry.Scale(Final_Shaft2, 0.3048)
Final_Shaft2 = FamilyType.ByGeometry(Final_Shaft2, Family2_name, Family_Cat, Family_Path, Material, 'a')

levels = []
shafts = []
remainder = []


for i in range(n):
    currentHeight = i * H_Shaft
    name = "Niveau " + str(i+1)
    level = Level.ByElevationAndName(currentHeight, name)
    remainingHeight = H_Total - currentHeight
    remainder.append(remainingHeight)
    if remainingHeight <= H_Shaft:
        if remainingHeight != H_Shaft:
            Shaft2 = FamilyInstance.ByPointAndLevel(Final_Shaft2, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level)
            shafts.append(Shaft2)
        else:    
            Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level )
            shafts.append(Shaft1)
        name = "Level " + str(i+2) 
        level = Level.ByElevationAndName(H_Total, name)
        levels.append(level)
    else:
        Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level )
        shafts.append(Shaft1)
      
shafts_1 = [FamilyInstance.SetRotation(i, 180) for count, i in enumerate(shafts) if count % 2 == 1] 

for i in range(len(shafts),2):
    for j in range(len(shafts_1)):
        shafts_1[j] = shafts[i]
        
OUT = shafts

Thanks.

After rotating the even ones, move them by 1/2 of the X and Y component of the bounding box.

  • Get the bounding box of one element
  • Get the min and max point of the bounding box
  • Define a vector from the min and max points
  • Get the X and Y values of the vector
  • Build a vector by the X and Y values (leaving the Z component as a 0)
  • Move the rotated elements by the new X Y only vector using the Element.MoveByVector node (name might be off on that)
2 Likes

Hi @jacob.small

I tried these steps using dynamo graph as you telled me in my thread How to classify unsorted levels name and its works perfectly…but I prefer using an other approch and set the family instances’s insert point (or point location) to be their center and avoid translating them, so is that possible?

Thanks.

Couldn’t you just edit the family so that their rotation point is in the center?

1 Like

This is correct. You’d have to modify the python in the previous thread to either:

  • Use a different insertion point
  • translate the import by the bounding box
  • manually edit the family to modify the insertion point
1 Like

@jacob.small

I’ve not understand your steps!!
My instances are automaticly created and placed according their levels (see the code)
I want everything to go automatically with python, so why I should manually edit the family to modify the insertion point?

Thanks?

@leonard.moelders
You mean manually edit the family ?
I want everything to go automatically with python

Thanks.

hello if you join your element alone to a group, in fact the position point of the group is the center of your geometry
But it’s still a move to disguise

Cordially
christian.stan

Not steps in this case - a list of options. I’ll add a 4th here:

Option 1: Revisit the code which created the family geometry and alter the origin point.
Option 2: Revisit the code which created the family geometry and translate the geometry via the bounding box method above while still in the family document.
Option 3: Post instance creation, edit the family (manually or via code) to move all model content and reload the family into the document.
Option 4: Move the instances in the document (as noted above) and let the minimum point continue to be the origin.

There is not an ‘easy’ means to accomplish this ask, so the reasoning for doing so needs to be more significant than a desire. How does moving the objects break your workflow?

In particular this line (and ones like it) will need to be revised to be complete Revit API based tools, similar to the code in the FamilyIntance.ByGeometry node:Final_Shaft1 = FamilyType.ByGeometry(Final_Shaft1, Family1_name, Family_Cat, Family_Path, Material, 'a')

Hi,
try to move the Final_Shaft2 solid to 0,0,0

example (not tested)

Final_Shaft2 = Geometry.Scale(Final_Shaft2, 0.3048)
# get boundingbox
bbx = Final_Shaft2.BoundingBox
center = Point.ByCoordinates((bbx.MinPoint.X + bbx.MaxPoint.X) / 2.0, (bbx.MinPoint.Y + bbx.MaxPoint.Y) / 2.0, 0)
vectorTranslation = Vector.ByCoordinates(center.X, center.Y, 0).Reverse()
Final_Shaft2 = Final_Shaft2.Translate(vectorTranslation)
#
Final_Shaft2 = FamilyType.ByGeometry(Final_Shaft2, Family2_name, Family_Cat, Family_Path, Material, 'a')
2 Likes

I can’t use the boundingBoxe solution to move the even instances they have been rotated in the case were I have a single family type Shaft1 to be duplicated in all levels (to use boundingBoxe I should create two familys type of Shaft1 and alter their origin point ).

Thanks.

@jacob.small

I chosed this option to solve my problem…the idea came to me is alter levels creation or otherwise set two levels groups (even and odd that alternate between them) which allows me to alter the position of my instances and finally to be able to rotate the even ones and get the desired orientation.

Here my code for any suggestions (to reduce its length or shorten the steps):

Final_Shaft
import sys
import clr
import math
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitNodes')
import Revit
from Revit.Elements import *

R_exter_Shaft = IN[0]
Thk_Shaft = IN[1]
R_inter_Shaft = R_exter_Shaft - Thk_Shaft 
H_Total = IN[2]
H_Shaft = IN[3]
Thk_Slab = IN[4]
H_1 = H_Shaft - Thk_Slab
Family_Cat = IN[5]
Family_Path = IN[6]
Material = IN[7]
Family1_name = 'Shaft1'
Family2_name = 'Shaft2'
Long_Trape = 0.8
angle_Trape = math.degrees(math.atan((Long_Trape/2) / R_inter_Shaft))

# Set Levels_List
n = int(math.ceil(H_Total / H_Shaft))
if H_Total % H_Shaft > 0:
    H_2 = H_Total - (n-1) * H_Shaft
else:
    H_2 = 0

#Shaft1_Profil
lst1 = []
Pt1 = Point.ByCoordinates( R_exter_Shaft, 0, -Thk_Slab)
lst1.append(Pt1)
Pt2 = Point.ByCoordinates( R_exter_Shaft, 0, H_1)
lst1.append(Pt2)
Pt3 = Point.ByCoordinates( R_inter_Shaft , 0, H_1)
lst1.append(Pt3)
Pt4 = Point.ByCoordinates( R_inter_Shaft , 0, -Thk_Slab)
lst1.append(Pt4)
vector = Vector.ByCoordinates(0, 0, 1)
Center_pt = Point.ByCoordinates(0, 0, 0)
Shaft1_Profil = Polygon.ByPoints(lst1)
Shaft1 = Solid.ByRevolve(Shaft1_Profil, Center_pt, vector, 0, 360)

#Shaft2_Profil
lst2 = []
Pt_1 = Point.ByCoordinates( R_exter_Shaft, 0, -Thk_Slab)
lst2.append(Pt_1)
Pt_2 = Point.ByCoordinates( R_exter_Shaft, 0, H_2)
lst2.append(Pt_2)
Pt_3 = Point.ByCoordinates( R_inter_Shaft , 0, H_2)
lst2.append(Pt_3)
Pt_4 = Point.ByCoordinates( R_inter_Shaft , 0, -Thk_Slab)
lst2.append(Pt_4)
vector = Vector.ByCoordinates(0, 0, 1)
Center_pt = Point.ByCoordinates(0, 0, 0)
Shaft2_Profil = Polygon.ByPoints(lst2)
Shaft2 = Solid.ByRevolve(Shaft2_Profil, Center_pt, vector, 0, 360)

Slab_Profil = Surface.ByPatch(Circle.ByCenterPointRadius(Center_pt, R_inter_Shaft ))
Slab = Surface.Thicken(Slab_Profil, -Thk_Slab, bool(0))

# opening profil to be subtract from the slab
Trape_arc = Arc.ByCenterPointRadiusAngle(Center_pt, R_inter_Shaft, -angle_Trape, angle_Trape, vector )
Pt1 = Trape_arc.StartPoint
Pt2 = Trape_arc.EndPoint
Pt3 = Pt1.Translate(-Long_Trape)
Pt4 = Pt2.Translate(-Long_Trape)
Line1 = Line.ByStartPointEndPoint(Pt3, Pt4)
Line2 = Line.ByStartPointEndPoint(Pt3, Pt1)
Line3 = Line.ByStartPointEndPoint(Pt4, Pt2)

Profil_Trape = Surface.ByPatch(PolyCurve.ByJoinedCurves([Line1, Line2, Trape_arc, Line3]))
Trape = Surface.Thicken(Profil_Trape, Thk_Slab, bool(0))

Finale_Slab = Solid.Difference(Slab, Trape)

# Shaft1 geometry and Family Type
lst3 = [Shaft1, Finale_Slab]
Final_Shaft1 = Solid.ByUnion(lst3)
Final_Shaft1 = Geometry.Translate(Final_Shaft1, -Thk_Slab)
Final_Shaft1 = Geometry.Scale(Final_Shaft1, 0.3048)
Final_Shaft1 = FamilyType.ByGeometry(Final_Shaft1, Family1_name, Family_Cat, Family_Path, Material, 'a')

# Shaft2 geometry and Family Type
vect = Vector.ByCoordinates(0,0,-Thk_Slab)
lst4 = [Shaft2, Finale_Slab]
Final_Shaft2 = Solid.ByUnion(lst4)
Final_Shaft2 = Geometry.Translate(Final_Shaft2, -Thk_Slab)
Final_Shaft2 = Geometry.Scale(Final_Shaft2, 0.3048)
Final_Shaft2 = Final_Shaft2.Translate(vect)
Final_Shaft2 = FamilyType.ByGeometry(Final_Shaft2, Family2_name, Family_Cat, Family_Path, Material, 'a')

levels = []
shafts = []
remainder = []
      
for i in range(n):
    if i % 2 == 0:
        currentHeight1 = i * H_Shaft
        name1 = "Niveau " + str(i+1)
        level1 = Level.ByElevationAndName(currentHeight1, name1)
        remainingHeight1 = H_Total - currentHeight1
        remainder.append(remainingHeight1)
        if remainingHeight1 <= H_Shaft:
            if remainingHeight1 != H_Shaft:
                Shaft2 = FamilyInstance.ByPointAndLevel(Final_Shaft2, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level1)
                shafts.append(Shaft2)
            else:    
                Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level1 )
                shafts.append(Shaft1)
            name1 = "Niveau " + str(i+2) 
            level1 = Level.ByElevationAndName(H_Total, name1)
        else:
            Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level1 )
            shafts.append(Shaft1)  
      
    else:
        currentHeight2 = i * H_Shaft
        name2 = "Niveau " + str(i+1)
        level2 = Level.ByElevationAndName(currentHeight2, name2)
        remainingHeight2 = H_Total - currentHeight2
        remainder.append(remainingHeight2)
        levels.append(level2)
        if remainingHeight2 <= H_Shaft:
            if remainingHeight2 != H_Shaft:
                Shaft2 = FamilyInstance.ByPointAndLevel(Final_Shaft2, Point.ByCoordinates(-R_exter_Shaft, -R_exter_Shaft, 0), level2)
                shafts.append(Shaft2)
            else:    
                Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(R_exter_Shaft, R_exter_Shaft, 0), level2 )
                shafts.append(Shaft1)
        
            name2 = "Niveau " + str(i+2) 
            level2 = Level.ByElevationAndName(H_Total, name2)
            levels.append(level2)        
        else:
            Shaft1 = FamilyInstance.ByPointAndLevel(Final_Shaft1, Point.ByCoordinates(R_exter_Shaft, R_exter_Shaft, 0), level2 )
            shafts.append(Shaft1)  
        
shafts1 = [FamilyInstance.SetRotation(i, 180) for count, i in enumerate(shafts) if count % 2 == 1]

for i in range(len(shafts),2):
    for j in range(len(shafts_1)):
        shafts_1[j] = shafts[i]
OUT = shafts, remainder

I still have a small trick to fix :
my instances are placed with an offset of 10cm (which is the slab thickness) compared to their levels… I know that I can move them manualy or using Element.MoveByVector node but in this case I loose the instances proprities, so any suggetion to correct this trick?

Thanks.

Looks good. Not sure I follow the issue though. Which way is it supposed to shift?

1 Like

@jacob.small
My family type is a solid by union between slab (thickness = 10 cm) and wall, so when the family instances by level are created they are placed at the bottom face of the slab compared to their levels but they should be placed at the top face of the slab (The instances should shifted down with 10cm).

Thanks.

Can you set the elevation or offset by level for the family instance?

What options and data is in the properties pallet to work with?

@jacob.small

You mean in The Revit model? yes I can and as I said above I can fix that manually but I’m looking for a way to fix that inside the code?

As you said we can play on the “offset by level” proprities of the instance

Thanks.

Once the instance exists you can set the parameter with an Element.SetParameterValueByName node, allowing you to bulk shift each one down the given distance. Note that this may cause some issues at the base (unless you intend that one to be recess?)

1 Like