Hi All,
I've been working with dimensions for a while for multiple objects. The method needs a ReferenceArray to work. Now, I need to create dimensions for a filled region and I can't get the reference for the curves contained in the boundary.
Any tip of advice will be very well received.
Thanks in advance!
Solved! Go to Solution.
Solved by aignatovich. Go to Solution.
Dear Jorge,
Thank you for your query.
How did you create the dimensions in your second image?
Hove you used RevitLookup to explore in depth the filled region geometry and the dimension object with their respective references?
I have passed on your question to the development team for advice for you.
Best regards,
Jeremy
Hi @jeremytammik , Thanks for your reply.
The dimensions in the second image were created using native commands (no API, just clicking using "Align Dimension").
Indeed, I used Revit Lookup searching for some "Reference" in the Filled Region sub-elements with no results. Already tried to get the references from the CUrveLoop curves, but again, with no results. All I get is "Reference = null".
Any tip of advice will be very well received.
Thanks for escalating the query to the development team.
Regards
Hi! Try this code:
[Transaction(TransactionMode.Manual)] public class CreateFillledRegionDimensionsCommand : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { var uiapp = commandData.Application; var uidoc = uiapp.ActiveUIDocument; var doc = uidoc.Document; var view = uidoc.ActiveGraphicalView; var filledRegions = FindFilledRegions(doc, view.Id).ToList(); using (var transaction = new Transaction(doc, "filled regions dimensions")) { transaction.Start(); foreach (var filledRegion in filledRegions) { CreateDimensions(filledRegion, -1*view.RightDirection); CreateDimensions(filledRegion, view.UpDirection); } transaction.Commit(); } return Result.Succeeded; } private static void CreateDimensions(FilledRegion filledRegion, XYZ dimensionDirection) { var document = filledRegion.Document; var view = (View) document.GetElement(filledRegion.OwnerViewId); var edgesDirection = dimensionDirection.CrossProduct(view.ViewDirection); var edges = FindRegionEdges(filledRegion) .Where(x => IsEdgeDirectionSatisfied(x, edgesDirection)) .ToList(); if (edges.Count < 2) return; var shift = UnitUtils.ConvertToInternalUnits(-10*view.Scale, DisplayUnitType.DUT_MILLIMETERS)*edgesDirection; var dimensionLine = Line.CreateUnbound(filledRegion.get_BoundingBox(view).Min + shift, dimensionDirection); var references = new ReferenceArray(); foreach (var edge in edges) references.Append(edge.Reference); document.Create.NewDimension(view, dimensionLine, references); } private static bool IsEdgeDirectionSatisfied(Edge edge, XYZ edgeDirection) { var edgeCurve = edge.AsCurve() as Line; if (edgeCurve == null) return false; return edgeCurve.Direction.CrossProduct(edgeDirection).IsAlmostEqualTo(XYZ.Zero); } private static IEnumerable<Edge> FindRegionEdges(FilledRegion filledRegion) { var view = (View)filledRegion.Document.GetElement(filledRegion.OwnerViewId); var options = new Options { View = view, ComputeReferences = true }; return filledRegion .get_Geometry(options) .OfType<Solid>() .SelectMany(x => x.Edges.Cast<Edge>()); } private static IEnumerable<FilledRegion> FindFilledRegions(Document document, ElementId viewId) { var collector = new FilteredElementCollector(document, viewId); return collector .OfClass(typeof (FilledRegion)) .Cast<FilledRegion>(); } }
It produces something like this:
Thanks, @aignatovich. I really appreciate it.
I'll give it a try with my script and I'll post here how it turned!.
Regards
Hi @aignatovich . Your suggestion was the solution to my problem!. I took (if you don't mind) the liberty to extend the approach, so the method asks for the type name (string) of the dimension you want to assign:
private void CreateDimensions( FilledRegion filledRegion, XYZ dimensionDirection, string typeName) { var document = filledRegion.Document; var view = (View)document.GetElement(filledRegion.OwnerViewId); var edgesDirection = dimensionDirection.CrossProduct(view.ViewDirection); var edges = FindRegionEdges(filledRegion) .Where(x => IsEdgeDirectionSatisfied(x, edgesDirection)) .ToList(); if (edges.Count < 2) return; // Se hace este ajuste para que la distancia no depende de la escala. <<<<<< evaluar para información de acotado y etiquetado!!! var shift = UnitUtils.ConvertToInternalUnits(5 * view.Scale, DisplayUnitType.DUT_MILLIMETERS) * edgesDirection; var dimensionLine = Line.CreateUnbound( filledRegion.get_BoundingBox(view).Min + shift, dimensionDirection); var references = new ReferenceArray(); foreach (var edge in edges) references.Append(edge.Reference); Dimension dim = document.Create.NewDimension(view, dimensionLine, references); ElementId dr_id = DimensionTypeId( document, typeName); if (dr_id != null) { dim.ChangeTypeId(dr_id); } } private static bool IsEdgeDirectionSatisfied(Edge edge, XYZ edgeDirection) { var edgeCurve = edge.AsCurve() as Line; if (edgeCurve == null) return false; return edgeCurve.Direction.CrossProduct(edgeDirection).IsAlmostEqualTo(XYZ.Zero); } private static IEnumerable<FilledRegion> FindFilledRegions(Document document, ElementId viewId) { var collector = new FilteredElementCollector(document, viewId); return collector .OfClass(typeof(FilledRegion)) .Cast<FilledRegion>(); } private static IEnumerable<Edge> FindRegionEdges(FilledRegion filledRegion) { var view = (View)filledRegion.Document.GetElement(filledRegion.OwnerViewId); var options = new Options { View = view, ComputeReferences = true }; return filledRegion .get_Geometry(options) .OfType<Solid>() .SelectMany(x => x.Edges.Cast<Edge>()); } private static ElementId DimensionTypeId( Document doc, string typeName) { List<Element> mt_coll = new FilteredElementCollector(doc) .OfClass(typeof(DimensionType)) .WhereElementIsElementType() .ToList(); DimensionType dimType = null; foreach (Element type in mt_coll) { if (type is DimensionType) { if (type.Name == typeName) { dimType = type as DimensionType; break; } } } return dimType.Id; }
Hope this helps someone else!
Regards!
Hi @aignatovich . Your suggestion was the solution to my problem!. I took (if you don't mind) the liberty to extend the approach, so the method asks for the type name (string) of the dimension you want to assign:
private void CreateDimensions( FilledRegion filledRegion, XYZ dimensionDirection, string typeName) { var document = filledRegion.Document; var view = (View)document.GetElement(filledRegion.OwnerViewId); var edgesDirection = dimensionDirection.CrossProduct(view.ViewDirection); var edges = FindRegionEdges(filledRegion) .Where(x => IsEdgeDirectionSatisfied(x, edgesDirection)) .ToList(); if (edges.Count < 2) return; // Se hace este ajuste para que la distancia no depende de la escala. <<<<<< evaluar para información de acotado y etiquetado!!! var shift = UnitUtils.ConvertToInternalUnits(5 * view.Scale, DisplayUnitType.DUT_MILLIMETERS) * edgesDirection; var dimensionLine = Line.CreateUnbound( filledRegion.get_BoundingBox(view).Min + shift, dimensionDirection); var references = new ReferenceArray(); foreach (var edge in edges) references.Append(edge.Reference); Dimension dim = document.Create.NewDimension(view, dimensionLine, references); ElementId dr_id = DimensionTypeId( document, typeName); if (dr_id != null) { dim.ChangeTypeId(dr_id); } } private static bool IsEdgeDirectionSatisfied(Edge edge, XYZ edgeDirection) { var edgeCurve = edge.AsCurve() as Line; if (edgeCurve == null) return false; return edgeCurve.Direction.CrossProduct(edgeDirection).IsAlmostEqualTo(XYZ.Zero); } private static IEnumerable<FilledRegion> FindFilledRegions(Document document, ElementId viewId) { var collector = new FilteredElementCollector(document, viewId); return collector .OfClass(typeof(FilledRegion)) .Cast<FilledRegion>(); } private static IEnumerable<Edge> FindRegionEdges(FilledRegion filledRegion) { var view = (View)filledRegion.Document.GetElement(filledRegion.OwnerViewId); var options = new Options { View = view, ComputeReferences = true }; return filledRegion .get_Geometry(options) .OfType<Solid>() .SelectMany(x => x.Edges.Cast<Edge>()); } private static ElementId DimensionTypeId( Document doc, string typeName) { List<Element> mt_coll = new FilteredElementCollector(doc) .OfClass(typeof(DimensionType)) .WhereElementIsElementType() .ToList(); DimensionType dimType = null; foreach (Element type in mt_coll) { if (type is DimensionType) { if (type.Name == typeName) { dimType = type as DimensionType; break; } } } return dimType.Id; }
Hope this helps someone else!
Regards!
Thank you very much, both, for the nice solution!
Edited and preserved for posterity by The Building Coder:
https://thebuildingcoder.typepad.com/blog/2019/08/auto-dimension-filled-region-boundary.html
Cheers,
Jeremy
Hi @jeremytammik, It is an honor to be mentioned on The Building Coder.
All the credits must go to @aignatovich, who's a solution was outstanding! I just tweaked it a little bit.
Thanks again on helping with the solution!
Regards!
Can't find what you're looking for? Ask the community or share your knowledge.