I'm trying to create a tool that will host an adaptive component on an edge in the project environment. The tool should prompt for an adaptive family to host and then for the edge to host it on.
I created the following helper method:
Function HostOnEdge(document As Document, familyTohost As FamilySymbol, edgeReference As Reference, normalizedParameter As Double) As FamilyInstance 'create a family instance and get it's adaptive points Dim familyInstance As FamilyInstance = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(document, familyTohost) Dim placementPoints As IList(Of ElementId) = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(familyInstance) 'create reference point Dim location As New PointLocationOnCurve(PointOnCurveMeasurementType.NormalizedCurveParameter, normalizedParameter, PointOnCurveMeasureFrom.Beginning) Dim pointOnEdge As PointOnEdge = document.Application.Create.NewPointOnEdge(edgeReference, location) 'attach first adaptive point to ref point Dim firstPoint As ReferencePoint = TryCast(document.GetElement(placementPoints(0)), ReferencePoint) firstPoint.SetPointElementReference(pointOnEdge) Return familyInstance End Function
I then call it from an external command as follows:
....
'select family to host Dim selectedElementId As ElementId = UiDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, "Select Element To Host:").ElementId 'select edge Dim selectedEdge As Reference = UiDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Edge) 'get the selected elements family symbol Dim familyInstance As FamilyInstance = TryCast(Document.GetElement(selectedElementId), FamilyInstance) Dim familySymbol As FamilySymbol = familyInstance.Symbol 'create hosted element HostOnEdge(Document, familySymbol, selectedEdge, 0.5)
....
If I select a system family like a floor edge or a wall edge as the host it works as expected. (see attached GIF) If i select an edge of a loaded family such as a beam an internal exception is thrown (snippet attached). What is the correct way to create a pointOnEdge on an edge of a family instance?
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
the cause of your problem, Revit has 2 ways of calculating solids.
see my answer to https://forums.autodesk.com/t5/revit-api-forum/incorrect-face-normal/td-p/7108787
In this case, I think it's an error in the Revit-API. The perfect valid EdgeReference ( of the "SolidInstance") apparently can't be used in the firstPoint.SetPointElementReference() method. I say perfect valid, because you can use the EdgeReference for the creation of a Dimension without a problem.
If you have a familyInstance that is cut, joined (or Coped) your code will work.
Thanks for the tip. As suggested if the "host" family is joined/cut/copped by another element it works as expected. If not the exception is thrown.
Dear Brett,
Thank you for your query, and many thanks to Fair59 for his many invaluable answers!
This and related issues have come up a number of times in the past, besides the thread that Fair59 points to on the incorrect face normal:
The question is whether the family instance geometry is returned in local or world coordinates, in LCS or WCS.
Another example:
Some related blog posts:
Have you tried using the `GetInstanceGeometry` method taking a `Transform` argument, and passing in an identity transform to it?
The docs recommend avoiding it in general, but you might call that as an alternative if you hit your exception.
I hope this helps.
Please do let us know how you solve this, since a blog post summarising the situation and providing the ultimate answer is long overdue.
Thank you!
Cheers,
Jeremy
By the way, The Building Code never discussed the AdaptiveComponentInstanceUtils class... can you say something about what it is, how you use it, in what way you find it useful, what functionality it provides not found elsewhere, SDK samples demonstrating its use, etc.?
Thank you!
Cheers,
Jeremy
@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.
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:
[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; } }
dusting of this old thread...
Seems like an easy enough workaround. Before i go and code it up, after the dummy element is deleted does the hosted element remain? is it still hosted?
I tried this approach manually, (see attached) when the dummy element is deleted the hosted element gets deleted also.
You placed the adaptive family on a edge that was formed by cutting the 2 elements. When you remove the cutting element, you also remove the edge ( the host for the adaptive family)
Because I place the dummy element way off, there is no interaction with the selected edge, and the edge doesn't change as the dummy element is
removed.
Hello everyone,
I come to the news about this problem. I did some tests and I noticed that it only works with family categories that can be joined/cut/copped (example category: Walls, Framing, Generic Models). But I want to perform this operation on the specialized equipment category but it does not work. Would you have a solution for categories that can not be joined/cut/copped?
I found!
I replaced this part of code with
using (SubTransaction st = new SubTransaction(doc)) { st.Start(); JoinGeometryUtils.JoinGeometry(doc, dummyInstance, el); st.Commit(); }
by
using (SubTransaction st = new SubTransaction(doc)) { st.Start(); SolidSolidCutUtils.AddCutBetweenSolids(doc, dummyInstance, el); st.Commit();
}
Works with "Speciality Equipment"
Congratulations! Could you provide am minimal reproducible case that demonstrates the usage of your solution?
https://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
This seems to be a pretty tricky issue with some high level research and discussion invested, so it would be really nice to summarise in a conclusive blog post...
Thank you!
Cheers,
Jeremy
Can't find what you're looking for? Ask the community or share your knowledge.