Adaptive Family - Transform Troubles

Hello Dynamo Friends :slight_smile:

I have a script to place these lighting families:

The script also attempts to rotate this family by 3 axis, but in revit this is not possible at all.
I have to go the workaround to nest the family in an adaptive family.

So I changed the graph to work with adaptive families:

This works by building a source and target coordinatesystem for every instance.

As I now had no “FamilyInstance.Transform” node to convert from one CS to another, I had to build this node myself, and that’s where the trouble starts. I´m doing something wrong at transforming because the families get moved far away from their origin.

    # Get inverse transform of the source coordinate system
    sourceTransform = Transform.Identity
    sourceTransform.Origin = sourceCS.Origin.ToXyz()
    sourceTransform.BasisX = sourceCS.XAxis.Normalized().ToXyz()
    sourceTransform.BasisY = sourceCS.YAxis.Normalized().ToXyz()
    sourceTransform.BasisZ = sourceCS.ZAxis.Normalized().ToXyz()
    sourceTransformInverse = sourceTransform.Inverse

    # Get transform of the target coordinate system
    targetTransform = Transform.Identity
    targetTransform.Origin = targetCS.Origin.ToXyz()
    targetTransform.BasisX = targetCS.XAxis.Normalized().ToXyz()
    targetTransform.BasisY = targetCS.YAxis.Normalized().ToXyz()
    targetTransform.BasisZ = targetCS.ZAxis.Normalized().ToXyz()

    # Compute the transformation from source to target
    transform = sourceTransformInverse.Multiply(targetTransform)

The placing works fine it is just my transforming in the end that’s messing everything up. I´m out of ideas and hope for someone to go to the rescue! Files and full code attached, happy about any advice!

Place_Adaptive_on_Line.rvt (6.9 MB)

FamilyAtPointOnPolycurveTransformAdaptive.dyn (52.4 KB)

import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import System
from System import Array
from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

def create_transform_from_coordinate_systems(sourceCS, targetCS):

    # Get inverse transform of the source coordinate system
    sourceTransform = Transform.Identity
    sourceTransform.Origin = sourceCS.Origin.ToXyz()
    sourceTransform.BasisX = sourceCS.XAxis.Normalized().ToXyz()
    sourceTransform.BasisY = sourceCS.YAxis.Normalized().ToXyz()
    sourceTransform.BasisZ = sourceCS.ZAxis.Normalized().ToXyz()
    sourceTransformInverse = sourceTransform.Inverse

    # Get transform of the target coordinate system
    targetTransform = Transform.Identity
    targetTransform.Origin = targetCS.Origin.ToXyz()
    targetTransform.BasisX = targetCS.XAxis.Normalized().ToXyz()
    targetTransform.BasisY = targetCS.YAxis.Normalized().ToXyz()
    targetTransform.BasisZ = targetCS.ZAxis.Normalized().ToXyz()

    # Compute the transformation from source to target
    transform = sourceTransformInverse.Multiply(targetTransform)
    return transform
    
def move_adaptive_component(famInst, trf, unHost):
    try:
        AdaptiveComponentInstanceUtils.MoveAdaptiveComponentInstance(famInst, trf, unHost)
    except Exception as ex:
        OUT = str(ex)

adaptive_components = UnwrapElement(IN[0])
sourceCSs = UnwrapElement(IN[1])
targetCSs = UnwrapElement(IN[2])

for component, sourceCS, targetCS in zip(adaptive_components, sourceCSs, targetCSs):
	transform = create_transform_from_coordinate_systems(sourceCS, targetCS)
	move_adaptive_component(component, transform, True)

OUT = []

Might be easier to use a 3 point adaptive component so that users can control the location of the family, and you can quickly set the location with transforms by the origin, local X axis and local Y or local Z axis.

2 Likes

For my use case I see no benefit in adding more points and get corresponding parameters. I really like transforming from CS to another CS with nodes, so it can’t be that hard to build such a transform in python?!

I now got it working a single time by switching x/y coordinates in the transform. Then tryied to reproduce it for over an hour without success…transforming is weird

I see the problem, the instances are rotated about project 0,0,0 and not their own origin…but I can´t get it right…

Multiple points isn’t a bad thing for adaptive, after all users are likely going to want to be able to manually adjust these at some point, right?

That said, I recommend the following for deciphering transforms.

  1. Work in feet, and nearish the origin for the exercise.
  2. Build a Dynamo solid geometry which can easily be identified in any position. A box with a Pyramid and two cones to identify Z and the X and Y axis works well.
  3. Build a half dozen random coordinate systems.
  4. Take the geometry and transform it to each of the coordinate systems to identify what things should look like.
  5. Generate a family type from the geometry.
  6. For each coordinate system create an instance of the family type.

My best guess is you need to transform from the internal origin, not the location, but following the steps above should clarify.

2 Likes

Thanks jacob i will give up for today but could reproduce my “working” workflow. I have to run the graph a second time to get the components get placed right. For some reason dynamo is not creating new component instances at the second run, it takes the existing ones and transforms them right. But i have to change X/Y coordinates at the second run.

So it must somehow be possible but there are some mistakes in there…

I could not solve it by making the two transforms inside one run…

[video-to-gif output image]

That sounds like you might need to commit the transaction to create, and then start a new transaction to transform. Which kind of makes sense - the existing objects don’t have a location to transform until they exist after all…

1 Like

To move adaptive family to new location you can use BriMohareb_xxxx packages. Also there is node to transform cs.

2 Likes

Oh no, I have this amazing package but it seems i relyed on the dynamo search and didn’t find a node for transforming.
I will have a closer look now, thank you @RMohareb :grinning:

1 Like

2 Likes

@jacob.small

It´s not a transaction problem, adding transactions doesn´t change the behavior.
That I have to run the graph twice with different settings is most likely a mistake in my logic, less likely an api method failure.
That there are no new instances created by adaptivecomponent.bypoints is most likely because the points don´t change. maybe there can only exist one adaptive family at a point, so instead of creating a new instance the node collects the existing ones (the Id stays the same).

@RMohareb

I can’t find a node that will transform the adaptive family, but i can use the node that translates (moves) the family as a workaround.

The graph will now transform the families to outer space, but then translates them back in position. For sure not the best solution, but hey, as long as it works…

So I think this is just how transforms work, you have to do a rotation and translation.

Trying to put this all in one python node gave me the same problems, I had to run the code twice with commented out rotation/transaltion to make it work, but now i found the root of all evil:

The key to success is doc.Regenerate() :smiley:

All working fine now! Thanks for the help!

import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import System
from System import Array
from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *


doc = DocumentManager.Instance.CurrentDBDocument

def create_rotation_transform(sourceCS, targetCS):
    sourceTransform = Transform.Identity
    sourceTransform.Origin = XYZ(0,0,0)
    sourceTransform.BasisX = sourceCS.XAxis.Normalized().ToXyz()
    sourceTransform.BasisY = sourceCS.YAxis.Normalized().ToXyz()
    sourceTransform.BasisZ = sourceCS.ZAxis.Normalized().ToXyz()
    sourceTransformInverse = sourceTransform.Inverse

    targetTransform = Transform.Identity
    targetTransform.Origin = XYZ(0,0,0)
    targetTransform.BasisX = targetCS.XAxis.Normalized().ToXyz()
    targetTransform.BasisY = targetCS.YAxis.Normalized().ToXyz()
    targetTransform.BasisZ = targetCS.ZAxis.Normalized().ToXyz()

    return sourceTransformInverse.Multiply(targetTransform)

def create_translation_transform(sourcePoint, targetPoint):
    return Transform.CreateTranslation(targetPoint - sourcePoint)

def apply_transform(famInst, transform):
    try:
        AdaptiveComponentInstanceUtils.MoveAdaptiveComponentInstance(famInst, transform, True)
    except Exception as ex:
        return str(ex)

adaptive_components = UnwrapElement(IN[0])
sourceCSs = UnwrapElement(IN[1])
targetCSs = UnwrapElement(IN[2])

for component, sourceCS, targetCS in zip(adaptive_components, sourceCSs, targetCSs):
    # Rotation
    componentLocation1 = component.Location.Point
    rotationTransform = create_rotation_transform(sourceCS, targetCS)
    TransactionManager.Instance.EnsureInTransaction(doc)
    apply_transform(component, rotationTransform)
    TransactionManager.Instance.TransactionTaskDone()
    doc.Regenerate()
    # Translation
    componentLocation = component.Location.Point
    translationTransform = create_translation_transform(componentLocation, targetCS.Origin.ToXyz())
    TransactionManager.Instance.EnsureInTransaction(doc)
    apply_transform(component, translationTransform)
    TransactionManager.Instance.TransactionTaskDone()
    componentLocation2 = component.Location.Point
    
OUT = adaptive_components

3 Likes