Apply transform to family instance
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello,
I've been trying to figure this out for several days now and can't find a good solution.
Scenario:
- Given a document with family instances
- Run a custom command which exports some family instance data (eg. file name, symbol name, transform)
- Create a new document and run custom import command
- Expectation: all family instances are identical (wrt. exported data)
- Actual: it seems impossible to consistently apply a transform to a family instance
JSON sample:
{
"Family": "test.rfa",
"Symbol": "test",
"Transform": {
"Origin": {
"X": 1.0,
"Y": 2.0,
"Z": 3.0.
},
"BasisX": {
"X": 1.0,
"Y": 0.0,
"Z": 0.0
},
"BasisY": {
"X": 0.0,
"Y": 1.0,
"Z": 0.0
},
"BasisZ": {
"X": 0.0,
"Y": 0.0,
"Z": 1.0
}
}
}
Approach 1
create the family instance on a correctly rotated/mirrored sketch plane
let private frame origin basisX basisY basisZ =
new Frame(origin, basisX, basisY, basisZ)
let private plane origin basisX basisY basisZ =
frame origin basisX basisY basisZ |> Plane.Create
let private sketchPlane (doc : Document) origin basisX basisY basisZ =
SketchPlane.Create(doc, plane origin basisX basisY basisZ)
let private creationData doc transform symbol =
let origin = transform.Origin.ToXYZ()
let basisX = transform.XAxis.Normalize() |> unitVectorToXYZ
let basisY = transform.YAxis.Normalize() |> unitVectorToXYZ
let basisZ = transform.ZAxis.Normalize() |> unitVectorToXYZ
let sketchPlane = sketchPlane doc origin basisX basisY basisZ
let creationData = new Creation.FamilyInstanceCreationData(origin, symbol, sketchPlane, Structure.StructuralType.NonStructural)
creationData
This seems to work for most rotations, but fails when mirroring along z-axis (and probably other cases I didn't test yet):
Expected: <CoordinateSystem 4x4-Double
1 0 0 1
0 1 0 2
0 0 -1 3
0 0 0 1
>
But was: <CoordinateSystem 4x4-Double
1 0 0 1
0 -1 0 2
0 0 -1 3
0 0 0 1
Revit decides that this instance should also be mirrored along the y-axis.
Approach 2
create all family instances in XYZ.Zero and use ElementTransformUtils.CopyElements(...) to apply the transform:
let private applyTransform (doc : Document) (transform, id) =
let transformedId = ElementTransformUtils.CopyElements(doc, [| id |], doc, transform, null) |> Seq.exactlyOne
doc.Delete id |> ignore
transformedId
let private creationData symbol =
new Creation.FamilyInstanceCreationData(XYZ.Zero, symbol, Structure.StructuralType.NonStructural)
This doubles the runtime of the import and also fails when mirroring along z-axis:
Expected: <CoordinateSystem 4x4-Double
1 0 0 1
0 1 0 2
0 0 -1 3
0 0 0 1
>
But was: <CoordinateSystem 4x4-Double
1 0 0 1
0 -1 0 2
0 0 1 3
0 0 0 1
This time only the y-axis is mirrored.
Dynamo implementation
public static FamilyInstance ByCoordinateSystem(FamilyType familyType, CoordinateSystem coordinateSystem)
They extract the euler angles from the transform, then throw rotations around X- and Y-axis away and apply rotation around Z-axis. Mirroring instances is not supported.
I played around with this idea and the gimbal-lock problem but eventually gave up, since I couldn't find a way to extract mirror properties (plane or direction) from the transform. It also seems very inefficient to decompose the transform, apply all rotations and mirror operations just to get the same transform in Revit.
Other idea: maybe it's possible to get the native Trf* pointer and override it. Probably breaks internal Revit invariants.
If you know how to simply apply a (non-scaling) transform to a family instance, please help.
Best regards