diff --git a/Test/Sample/BenchmarkCommand/CategoriesCommand.cs b/Test/Sample/BenchmarkCommand/CategoriesCommand.cs index 3f3d9d9..3ca029d 100644 --- a/Test/Sample/BenchmarkCommand/CategoriesCommand.cs +++ b/Test/Sample/BenchmarkCommand/CategoriesCommand.cs @@ -33,6 +33,7 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme categoryBenchmark.Workset = CountWorksetName(worksets,category.ToList()); categoryBenchmark.Family = CountFamilyName(category.ToList()); categoryBenchmark.Type = CountFamilyTypeName(category.ToList()); + categoryBenchmark.AssemblyCode = CountAssemblyCode(category.ToList()); categoryBenchmark.Nestest = CountNestestElement(category.ToList()); categoryBenchmark.Length = category.Sum(x=> UnitFeetToMeter(x.LookupParameter("Length")?.AsDouble() ?? 0)); categoryBenchmark.Width = category.Sum(x=> UnitFeetToMeter(x.LookupParameter("Width")?.AsDouble() ?? 0)); @@ -46,7 +47,7 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme Process.Start(filePath); return Result.Succeeded; } - public double CountWorksetName(ICollection worksets,List elements) + private double CountWorksetName(ICollection worksets,List elements) { List names = new List(); // get user workset created @@ -59,7 +60,7 @@ public double CountWorksetName(ICollection worksets,List eleme } return names.Distinct().Count(); } - public double CountFamilyTypeName(List elements) + private double CountFamilyTypeName(List elements) { List names = new List(); foreach (Element element in elements) @@ -70,7 +71,7 @@ public double CountFamilyTypeName(List elements) } return names.Distinct().Count(); } - public double CountFamilyName(List elements) + private double CountFamilyName(List elements) { List names = new List(); foreach (Element element in elements) @@ -82,7 +83,7 @@ public double CountFamilyName(List elements) return names.Distinct().Count(); } - public double CountNestestElement(List elements) + private double CountNestestElement(List elements) { List names = new List(); foreach (Element element in elements) @@ -99,8 +100,20 @@ public double CountNestestElement(List elements) return names.Distinct().Count(); } + private double CountAssemblyCode(List elements) + { + List names = new List(); + var familySymbols = elements.Select(x => x.Document.GetElement(x.GetTypeId()) as FamilySymbol); + foreach (FamilySymbol familySymbol in familySymbols) + { + string? assemblyCode = familySymbol?.get_Parameter(BuiltInParameter.UNIFORMAT_CODE)?.AsValueString(); + if (assemblyCode != null) names.Add(assemblyCode); + } + return names.Distinct().Count(); + } + - public double UnitFeetToMeter(double value) + private double UnitFeetToMeter(double value) { return UnitUtils.Convert(value,UnitTypeId.Feet,UnitTypeId.Meters); } @@ -112,8 +125,11 @@ public class CategoryBenchmark public double Count { get; set; } = 0; public double Workset { get; set; } public double Family { get; set; } = 0; + public double Type { get; set; } = 0; public double Nestest { get; set; } = 0; + + public double AssemblyCode { get; set; } = 0; // set feild name csv [CsvHelper.Configuration.Attributes.Name("Length(m)")] public double Length { get; set; } diff --git a/Test/Sample/FindNearestComand.cs b/Test/Sample/FindNearestComand.cs new file mode 100644 index 0000000..9b3906a --- /dev/null +++ b/Test/Sample/FindNearestComand.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using Autodesk.Revit.UI.Selection; + +namespace Test; + +[Transaction(TransactionMode.Manual)] +public class FindIntersectCommand : IExternalCommand +{ + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + var uidoc = commandData.Application.ActiveUIDocument; + var doc = commandData.Application.ActiveUIDocument.Document; + Reference? refElement = uidoc.Selection.PickObject(ObjectType.Element); + var element = doc.GetElement(refElement); + LocationPoint? locationPoint = element.Location as LocationPoint; + if (locationPoint == null) throw new Exception("element location is null"); + var category = doc.Settings.Categories.get_Item(BuiltInCategory.OST_Floors); + var categories = new List() { category }; + Element? findNearest2 = FindNearest2(commandData, locationPoint.Point, categories, new XYZ(0, 0, -1), true); + MessageBox.Show(findNearest2.Id.ToString()); + // Way 2 + IList referenceWithContext = FindNearest(doc, locationPoint!.Point, categories, + new XYZ(0, 0, 1), FindReferenceTarget.All, true); + if (referenceWithContext.Count==0) + { + MessageBox.Show("Nothing"); + } + else + { + StringBuilder sb = new StringBuilder(); + foreach (ReferenceWithContext context in referenceWithContext) + { + sb.AppendLine(context.GetReference().ElementId.ToString()); + sb.AppendLine(context.GetReference().LinkedElementId.ToString()); + sb.AppendLine(context.GetReference().GlobalPoint.ToString()); + } + MessageBox.Show(sb.ToString()); + } + + return Result.Succeeded; + } + + private Element? FindNearest2(ExternalCommandData commandData, XYZ point, + List categories, XYZ direction,bool isIncludeRevitLink) + { + var doc = commandData.Application.ActiveUIDocument.Document; + var categoryFilter = new ElementMulticategoryFilter(categories.Select(x => x.Id).ToList()); + var collector = new FilteredElementCollector(doc); + IList elements = collector.WherePasses(categoryFilter) + .WhereElementIsNotElementType().ToElements(); + if (isIncludeRevitLink) + { + var revitLinkTypes = new FilteredElementCollector(doc) + .OfClass(typeof(RevitLinkType)).Cast(); + foreach (RevitLinkType revitLinkType in revitLinkTypes) + { + var linkDoc = commandData.Application.Application.Documents.Cast() + .FirstOrDefault(x => x.Title+".rvt" == revitLinkType.Name); + var collectorLink = new FilteredElementCollector(linkDoc); + IList elementIsNotElementType = collectorLink + .WherePasses(categoryFilter) + .WhereElementIsNotElementType() + .ToElements(); + elements = elements.Concat(elementIsNotElementType).ToList(); + + } + } + // check distance between point and element by direction + Element? nearestElement = null; + double minDistance = double.MaxValue; + foreach (Element element in elements) + { + BoundingBoxXYZ boundingBoxXyz = element.get_BoundingBox(null); + if (boundingBoxXyz == null) continue; + var center = boundingBoxXyz.Max.Add(boundingBoxXyz.Min).Divide(2); + // check distance by project direction from input + var plane = Plane.CreateByNormalAndOrigin(direction, point); + // if direction is opposite with element direction, skip + if (IsOppositeDirection(direction, center - point)) continue; + //calc distance from point to plane by math + double currentDis = CalculateDistanceFromPointToPlane(center, plane); + if (currentDis < minDistance) + { + minDistance = currentDis; + nearestElement = element; + } + } + return nearestElement; + } + bool IsOppositeDirection(XYZ direction, XYZ vector) + { + return direction.DotProduct(vector) < 0; + } + + public double CalculateDistanceFromPointToPlane(XYZ point, Plane plane) + { + // Get the normal vector of the plane + XYZ normal = plane.Normal; + + // Get a point on the plane + XYZ pointOnPlane = plane.Origin; + + // Calculate the vector from the point on the plane to the given point + XYZ vectorToPoint = point - pointOnPlane; + + // Use the dot product to find the signed distance + double signedDistance = normal.DotProduct(vectorToPoint); + + // The absolute value of the signed distance gives the shortest distance + return Math.Abs(signedDistance); + } + + private IList FindNearest(Autodesk.Revit.DB.Document doc, XYZ point, + List categories, XYZ direction, FindReferenceTarget referenceTarget, + bool findReferencesInRevitLinks) + { + // Find a 3D view to use for the Reference Intersection constructor + FilteredElementCollector collector = new FilteredElementCollector(doc); + Func isNotTemplate = v3 => !(v3.IsTemplate); + View3D? view3D = collector.OfClass(typeof(View3D))?.Cast()?.First(isNotTemplate); + if (view3D == null) + { + throw new ArgumentNullException($"FindNearest require 3D view open"); + } + + // Use the center of the skylight bounding box as the start point. + // Project in the negative Z direction down to the ceiling. + IEnumerable categoriesEnum = categories.Select(x => x.Name); + ElementFilter? elementFilter = FiltersElementByCategory(doc, categoriesEnum); + ReferenceIntersector refIntersect = new ReferenceIntersector(elementFilter, referenceTarget, view3D); + refIntersect.FindReferencesInRevitLinks = findReferencesInRevitLinks; + IList referenceWithContexts = refIntersect.Find(point, direction); + // ReferenceWithContext referenceWithContext = refIntersect.FindNearest(point, direction); + return referenceWithContexts; + } + + /// + /// + /// + /// + /// + private ElementFilter? FiltersElementByCategory(Document doc, IEnumerable categoryNames) + { + ElementFilter? categoriesFilter = null; + if (categoryNames != null && categoryNames.Any()) + { + var categoryIds = new List(); + foreach (var categoryName in categoryNames) + { + var category = doc.Settings.Categories.get_Item(categoryName); + if (category != null) + { + categoryIds.Add(category.Id); + } + } + + var categoryFilters = new List(); + if (categoryIds.Count > 0) + { + var categoryRule = new FilterCategoryRule(categoryIds); + var categoryFilter = new ElementParameterFilter(categoryRule); + categoryFilters.Add(categoryFilter); + } + + if (categoryFilters.Count > 0) + { + categoriesFilter = new LogicalOrFilter(categoryFilters); + } + } + + return categoriesFilter; + } +} \ No newline at end of file