Skip to content

Commit

Permalink
add example
Browse files Browse the repository at this point in the history
  • Loading branch information
chuongmep committed Dec 4, 2024
1 parent e4a4cb9 commit 2c26306
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 5 deletions.
26 changes: 21 additions & 5 deletions Test/Sample/BenchmarkCommand/CategoriesCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -46,7 +47,7 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
Process.Start(filePath);
return Result.Succeeded;
}
public double CountWorksetName(ICollection<Workset> worksets,List<Element> elements)
private double CountWorksetName(ICollection<Workset> worksets,List<Element> elements)
{
List<string> names = new List<string>();
// get user workset created
Expand All @@ -59,7 +60,7 @@ public double CountWorksetName(ICollection<Workset> worksets,List<Element> eleme
}
return names.Distinct().Count();
}
public double CountFamilyTypeName(List<Element> elements)
private double CountFamilyTypeName(List<Element> elements)
{
List<string> names = new List<string>();
foreach (Element element in elements)
Expand All @@ -70,7 +71,7 @@ public double CountFamilyTypeName(List<Element> elements)
}
return names.Distinct().Count();
}
public double CountFamilyName(List<Element> elements)
private double CountFamilyName(List<Element> elements)
{
List<string?> names = new List<string?>();
foreach (Element element in elements)
Expand All @@ -82,7 +83,7 @@ public double CountFamilyName(List<Element> elements)
return names.Distinct().Count();
}

public double CountNestestElement(List<Autodesk.Revit.DB.Element> elements)
private double CountNestestElement(List<Autodesk.Revit.DB.Element> elements)
{
List<string> names = new List<string>();
foreach (Element element in elements)
Expand All @@ -99,8 +100,20 @@ public double CountNestestElement(List<Autodesk.Revit.DB.Element> elements)
return names.Distinct().Count();
}

private double CountAssemblyCode(List<Element> elements)
{
List<string> names = new List<string>();
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);
}
Expand All @@ -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; }
Expand Down
180 changes: 180 additions & 0 deletions Test/Sample/FindNearestComand.cs
Original file line number Diff line number Diff line change
@@ -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>() { category };
Element? findNearest2 = FindNearest2(commandData, locationPoint.Point, categories, new XYZ(0, 0, -1), true);
MessageBox.Show(findNearest2.Id.ToString());
// Way 2
IList<ReferenceWithContext> 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<Autodesk.Revit.DB.Category> 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<Element> elements = collector.WherePasses(categoryFilter)
.WhereElementIsNotElementType().ToElements();
if (isIncludeRevitLink)
{
var revitLinkTypes = new FilteredElementCollector(doc)
.OfClass(typeof(RevitLinkType)).Cast<RevitLinkType>();
foreach (RevitLinkType revitLinkType in revitLinkTypes)
{
var linkDoc = commandData.Application.Application.Documents.Cast<Document>()
.FirstOrDefault(x => x.Title+".rvt" == revitLinkType.Name);
var collectorLink = new FilteredElementCollector(linkDoc);
IList<Element> 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<ReferenceWithContext> FindNearest(Autodesk.Revit.DB.Document doc, XYZ point,
List<Category> categories, XYZ direction, FindReferenceTarget referenceTarget,
bool findReferencesInRevitLinks)
{
// Find a 3D view to use for the Reference Intersection constructor
FilteredElementCollector collector = new FilteredElementCollector(doc);
Func<View3D?, bool> isNotTemplate = v3 => !(v3.IsTemplate);
View3D? view3D = collector.OfClass(typeof(View3D))?.Cast<View3D>()?.First<View3D>(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<string> categoriesEnum = categories.Select(x => x.Name);
ElementFilter? elementFilter = FiltersElementByCategory(doc, categoriesEnum);
ReferenceIntersector refIntersect = new ReferenceIntersector(elementFilter, referenceTarget, view3D);
refIntersect.FindReferencesInRevitLinks = findReferencesInRevitLinks;
IList<ReferenceWithContext> referenceWithContexts = refIntersect.Find(point, direction);
// ReferenceWithContext referenceWithContext = refIntersect.FindNearest(point, direction);
return referenceWithContexts;
}

/// <summary>
/// </summary>
/// <param name="doc"></param>
/// <param name="categoryNames"></param>
/// <returns></returns>
private ElementFilter? FiltersElementByCategory(Document doc, IEnumerable<string> categoryNames)
{
ElementFilter? categoriesFilter = null;
if (categoryNames != null && categoryNames.Any())
{
var categoryIds = new List<ElementId>();
foreach (var categoryName in categoryNames)
{
var category = doc.Settings.Categories.get_Item(categoryName);
if (category != null)
{
categoryIds.Add(category.Id);
}
}

var categoryFilters = new List<ElementFilter>();
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;
}
}

0 comments on commit 2c26306

Please sign in to comment.