@jeremytammik nice collection of documentation / information. Sadly this problem has to do with hosting a Adaptive Point on a "real" Edge, so work arounds creating clones won't solve the issue.
I still think it's a bug in the Reference.SetPointElementReference(pointOnEdge) method. Looks to me there is a transformation to world coordinates missing somewhere.
- For a Element with "in situ" geometry (element cut, joined or coped), Brett's code works.
- Reworking the code to get a reference to a Voodoo-magic Edge (no transformation required) , the code works.
Only in the circumstances of the query does the code fail. (transformation to world coordinates required)
Having said that, we can trick Revit into placing the adaptive family in the right place.
These are the steps:
- Find start and End point of selected Edge.
- Place a dummy Element
- Join the dummy with the FamilyInstance containing the selected Edge, creating "in situ " geometry.
- Find the new Edge Reference of the "in Situ" geometry with correct start and End point.
- Place adaptive Family on that Edge.
- Delete dummy element.
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class Fa_HostAdaptiveFamilyOnEdge_Trick : IExternalCommand
{
public Result Execute(ExternalCommandData revit, ref string message, ElementSet elements)
{
Document doc = revit.Application.ActiveUIDocument.Document;
var selectedElementId = ElementId.InvalidElementId;
//select family to host
try
{
selectedElementId = revit.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, "Select Element To Host:").ElementId;
}
catch
{
return Result.Failed;
}
//get the selected family symbol to host on edge
var familyInstance = doc.GetElement(selectedElementId) as FamilyInstance;
if (familyInstance == null) return Result.Failed;
var familySymbol = familyInstance.Symbol;
//select edge
Reference selectedEdge = null;
try
{
selectedEdge = revit.Application.ActiveUIDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Edge);
}
catch
{
return Result.Failed;
}
if (selectedEdge == null) return Result.Succeeded;
bool SolidInstance = selectedEdge.ConvertToStableRepresentation(doc).Contains("INSTANCE");
Element el = null;
FamilySymbol dummy = null;
XYZ startPt = XYZ.Zero;
XYZ endPt = XYZ.Zero;
if (SolidInstance)
{
el = doc.GetElement(selectedEdge.ElementId);
dummy = (el as FamilyInstance).Symbol;
Transform elTrans = (el as FamilyInstance).GetTransform();
GeometryObject geoobj = el.GetGeometryObjectFromReference(selectedEdge);
Edge selEdge = geoobj as Edge;
startPt = elTrans.OfPoint( selEdge.AsCurve().GetEndPoint(0));
endPt = elTrans.OfPoint( selEdge.AsCurve().GetEndPoint(1));
}
using (Transaction t = new Transaction(doc, "create adaptive family"))
{
t.Start();
FamilyInstance dummyInstance = null;
if (SolidInstance)
{
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
dummyInstance = doc.Create.NewFamilyInstance(new XYZ(double.MinValue, double.MinValue, 0), dummy, XYZ.BasisX, null, StructuralType.NonStructural);
st.Commit();
}
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
JoinGeometryUtils.JoinGeometry(doc, dummyInstance, el);
st.Commit();
}
Options options = new Options();
options.ComputeReferences = true;
options.View = doc.ActiveView;
GeometryElement geoElem = el.get_Geometry(options);
bool quitloop = false;
// find the "InSitu:" Edge
foreach (GeometryObject geoobj in geoElem)
{
Solid solid = geoobj as Solid;
if (solid == null) continue;
foreach (Edge e in solid.Edges)
{
XYZ pt1 = e.AsCurve().GetEndPoint(0);
XYZ pt2 = e.AsCurve().GetEndPoint(1);
if (pt1.IsAlmostEqualTo(startPt) || pt1.IsAlmostEqualTo(endPt))
{
if (pt2.IsAlmostEqualTo(startPt) || pt2.IsAlmostEqualTo(endPt))
{
selectedEdge = e.Reference;
quitloop = true;
break;
}
}
}
if (quitloop) break;
}
}
FamilyInstance famInst = null;
ReferencePoint firstPoint = null;
using (SubTransaction st = new SubTransaction(doc))
{
try
{
st.Start();
//create a family instance and get it's adaptive points
famInst = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(doc, familySymbol);
List<ElementId> placementPoints = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(famInst).ToList();
//create reference point
PointLocationOnCurve location = new PointLocationOnCurve(PointOnCurveMeasurementType.NormalizedCurveParameter, 0.5, PointOnCurveMeasureFrom.Beginning);
PointOnEdge pointOnEdge = doc.Application.Create.NewPointOnEdge(selectedEdge, location);
//attach first adaptive point to ref point
firstPoint = doc.GetElement(placementPoints.FirstOrDefault()) as ReferencePoint;
firstPoint.SetPointElementReference(pointOnEdge);
st.Commit();
}
catch {
TaskDialog.Show("catch","Failed to place on selectededge "+selectedEdge.ConvertToStableRepresentation(doc));
}
}
if (SolidInstance)
{
using (SubTransaction st = new SubTransaction(doc))
{
st.Start();
doc.Delete(dummyInstance.Id);
st.Commit();
}
}
t.Commit();
}
return Result.Succeeded;
}
}