In Architecture I normally use upright families. When I need to place tilted families in the UI, I place them on a reference plane.
This method emulates that behavior
public FamilyInstance PlaceInstance(FamilySymbol symb, XYZ placementPoint, XYZ planeNormal, XYZ instHandDirection, bool OnReferencePlane = true)
{
if (symb == null) return null;
Document doc = symb.Document;
Family _family = symb.Family;
if (_family.FamilyPlacementType != FamilyPlacementType.WorkPlaneBased) return null;
if (planeNormal.IsAlmostEqualTo(XYZ.Zero)) planeNormal = new XYZ(0, 0, 1);
if (instHandDirection.IsAlmostEqualTo(XYZ.Zero)) instHandDirection = new XYZ(1, 0, 0);
if (planeNormal.DotProduct(instHandDirection).CompareTo(0) != 0) return null; // check instHandDirection perpendicular to planeNormal.
ReferencePlane refPlane = null;
FamilyInstance _instance1 = null;
XYZ YVec = planeNormal.CrossProduct(instHandDirection).Normalize();
using (SubTransaction trn = new SubTransaction(doc))
{
trn.Start();
refPlane = doc.Create.NewReferencePlane(placementPoint.Add(instHandDirection), placementPoint, YVec, doc.ActiveView);
refPlane.Name = "ref" + Guid.NewGuid().ToString();
_instance1 = doc.Create.NewFamilyInstance(refPlane.GetReference(), placementPoint, instHandDirection, symb);
trn.Commit();
}
if (!OnReferencePlane)
{
using (SubTransaction trn = new SubTransaction(doc))
{
trn.Start();
doc.Delete(refPlane.Id);
trn.Commit();
}
}
return _instance1;
}
The method requires an open transaction.
The family must be WorkplaneBased and "non" AlwaysVertical.
planeNormal needs to be perpendicular to instHandDirection
When creating the family through the API use:
FamilyDocument.OwnerFamily.get_Parameter(BuiltInParameter.FAMILY_ALWAYS_VERTICAL).Set((int) 0);
FamilyDocument.OwnerFamily.get_Parameter(BuiltInParameter.FAMILY_WORK_PLANE_BASED).Set((int)1);
for upside down placement use
planeNormal = XYZ.BasisZ.Negate();