- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要为许多元素(>100'000 个项目)找到大纲。目标元素来自 FilteredElementCollector
。像往常一样,我正在寻找最快的方法。
现在我尝试遍历所有元素以获取其 BoudingBox.Min
和 BoudingBox.Max
并找出 minX
,minY
、minZ
、maxX
、maxY
、maxZ
。它工作得非常准确,但需要太多时间。
上面描述的问题是一个更大问题的一部分。我需要从具有墙、天花板、柱等的链接模型中找到管道、管道和其他基于曲线的元素的所有交点,然后在一般模型中放置开口。
我尝试结合使用 ElementIntersectElement
过滤器和 IntersectSolidAndCurve
方法在元素内找到曲线的一部分。
首先使用 ElementIntersectElement
我试图减少集合以进一步使用 IntersectSolidAndCurve
。IntersectSolidAndCurve
有两个参数:solid 和 curve 并且有在另一个循环中的两个嵌套一个中工作。因此,在我的案例中需要 54000 面墙(过滤后)和 18000 根管道 972'000'000 次操作。
操作次数为 10 ^ 5 时,算法显示可接受的时间。我决定通过按级别划分搜索区域来减少元素的数量。这对高层建筑很有效,但对扩展的低结构仍然不利。我决定按长度划分建筑物,但我没有找到一种为几个元素(整个建筑物)找到边界的方法。
我好像走错了路。有没有正确的方法用revit api工具制作它
最佳答案
要找到边界,我们可以利用二分查找的思想。
与经典的二分查找算法不同的是没有数组,我们应该找两个数而不是一个数。
几何空间中的元素可以表示为 XYZ 点的 3 维排序数组。
Revit api 提供了出色的Quick Filter
:BoundingBoxIntersectsFilter
,它采用Outline
因此,让我们定义一个区域,其中包含我们要为其寻找边界的所有元素。对于我的情况,例如 500 米,并为初始轮廓创建 min
和 max
点
double b = 500000 / 304.8;
XYZ min = new XYZ(-b, -b, -b);
XYZ max = new XYZ(b, b, b);
下面是一个方向的实现,但是,您可以通过调用上一次迭代的结果并将其提供给输入,轻松地将它用于三个方向
double precision = 10e-6 / 304.8;
var bb = new BinaryUpperLowerBoundsSearch(doc, precision);
XYZ[] rx = bb.GetBoundaries(min, max, elems, BinaryUpperLowerBoundsSearch.Direction.X);
rx = bb.GetBoundaries(rx[0], rx[1], elems, BinaryUpperLowerBoundsSearch.Direction.Y);
rx = bb.GetBoundaries(rx[0], rx[1], elems, BinaryUpperLowerBoundsSearch.Direction.Z);
GetBoundaries
方法返回两个XYZ
点:lower和upper,只在目标方向改变,其他两个维度不变
public class BinaryUpperLowerBoundsSearch
{
private Document doc;
private double tolerance;
private XYZ min;
private XYZ max;
private XYZ direction;
public BinaryUpperLowerBoundsSearch(Document document, double precision)
{
doc = document;
this.tolerance = precision;
}
public enum Direction
{
X,
Y,
Z
}
/// <summary>
/// Searches for an area that completely includes all elements within a given precision.
/// The minimum and maximum points are used for the initial assessment.
/// The outline must contain all elements.
/// </summary>
/// <param name="minPoint">The minimum point of the BoundBox used for the first approximation.</param>
/// <param name="maxPoint">The maximum point of the BoundBox used for the first approximation.</param>
/// <param name="elements">Set of elements</param>
/// <param name="axe">The direction along which the boundaries will be searched</param>
/// <returns>Returns two points: first is the lower bound, second is the upper bound</returns>
public XYZ[] GetBoundaries(XYZ minPoint, XYZ maxPoint, ICollection<ElementId> elements, Direction axe)
{
// Since Outline is not derived from an Element class there
// is no possibility to apply transformation, so
// we have use as a possible directions only three vectors of basis
switch (axe)
{
case Direction.X:
direction = XYZ.BasisX;
break;
case Direction.Y:
direction = XYZ.BasisY;
break;
case Direction.Z:
direction = XYZ.BasisZ;
break;
default:
break;
}
// Get the lower and upper bounds as a projection on a direction vector
// Projection is an extention method
double lowerBound = minPoint.Projection(direction);
double upperBound = maxPoint.Projection(direction);
// Set the boundary points in the plane perpendicular to the direction vector.
// These points are needed to create BoundingBoxIntersectsFilter when IsContainsElements calls.
min = minPoint - lowerBound * direction;
max = maxPoint - upperBound * direction;
double[] res = UpperLower(lowerBound, upperBound, elements);
return new XYZ[2]
{
res[0] * direction + min,
res[1] * direction + max,
};
}
/// <summary>
/// Check if there are any elements contains in the segment [lower, upper]
/// </summary>
/// <returns>True if any elements are in the segment</returns>
private ICollection<ElementId> IsContainsElements(double lower, double upper, ICollection<ElementId> ids)
{
var outline = new Outline(min + direction * lower, max + direction * upper);
return new FilteredElementCollector(doc, ids)
.WhereElementIsNotElementType()
.WherePasses(new BoundingBoxIntersectsFilter(outline))
.ToElementIds();
}
private double[] UpperLower(double lower, double upper, ICollection<ElementId> ids)
{
// Get the Midpoint for segment mid = lower + 0.5 * (upper - lower)
var mid = Midpoint(lower, upper);
// Сheck if the first segment contains elements
ICollection<ElementId> idsFirst = IsContainsElements(lower, mid, ids);
bool first = idsFirst.Any();
// Сheck if the second segment contains elements
ICollection<ElementId> idsSecond = IsContainsElements(mid, upper, ids);
bool second = idsSecond.Any();
// If elements are in both segments
// then the first segment contains the lower border
// and the second contains the upper
// ---------**|***--------
if (first && second)
{
return new double[2]
{
Lower(lower, mid, idsFirst),
Upper(mid, upper, idsSecond),
};
}
// If elements are only in the first segment it contains both borders.
// We recursively call the method UpperLower until
// the lower border turn out in the first segment and
// the upper border is in the second
// ---*****---|-----------
else if (first && !second)
return UpperLower(lower, mid, idsFirst);
// Do the same with the second segment
// -----------|---*****---
else if (!first && second)
return UpperLower(mid, upper, idsSecond);
// Elements are out of the segment
// ** -----------|----------- **
else
throw new ArgumentException("Segment is not contains elements. Try to make initial boundaries wider", "lower, upper");
}
/// <summary>
/// Search the lower boundary of a segment containing elements
/// </summary>
/// <returns>Lower boundary</returns>
private double Lower(double lower, double upper, ICollection<ElementId> ids)
{
// If the boundaries are within tolerance return lower bound
if (IsInTolerance(lower, upper))
return lower;
// Get the Midpoint for segment mid = lower + 0.5 * (upper - lower)
var mid = Midpoint(lower, upper);
// Сheck if the segment contains elements
ICollection<ElementId> idsFirst = IsContainsElements(lower, mid, ids);
bool first = idsFirst.Any();
// ---*****---|-----------
if (first)
return Lower(lower, mid, idsFirst);
// -----------|-----***---
else
return Lower(mid, upper, ids);
}
/// <summary>
/// Search the upper boundary of a segment containing elements
/// </summary>
/// <returns>Upper boundary</returns>
private double Upper(double lower, double upper, ICollection<ElementId> ids)
{
// If the boundaries are within tolerance return upper bound
if (IsInTolerance(lower, upper))
return upper;
// Get the Midpoint for segment mid = lower + 0.5 * (upper - lower)
var mid = Midpoint(lower, upper);
// Сheck if the segment contains elements
ICollection<ElementId> idsSecond = IsContainsElements(mid, upper, ids);
bool second = idsSecond.Any();
// -----------|----*****--
if (second)
return Upper(mid, upper, idsSecond);
// ---*****---|-----------
else
return Upper(lower, mid, ids);
}
private double Midpoint(double lower, double upper) => lower + 0.5 * (upper - lower);
private bool IsInTolerance(double lower, double upper) => upper - lower <= tolerance;
}
投影是向量的一种扩展方法,用于确定一个向量对另一个向量的投影长度
public static class PointExt
{
public static double Projection(this XYZ vector, XYZ other) =>
vector.DotProduct(other) / other.GetLength();
}
关于geometry - Revit API。如何获得多个元素的边界框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63083938/
我想用 revit api 控制加载族和创建类型的事件。有人可以给我一个方向吗?我不太了解我阅读的文档。 最佳答案 首先,您需要通过在 IExternalApplication OnStartup 方
我使用过 RevitPythonShell 和 Dynamo,但我想使用我现有的 Python IDE (Eclipse),我在其中配置了日志记录、调试、GitHub 集成等。 我对事务和整个 API
使用 Revit Python Shell,我尝试提示用户选择一个房间。我一直在阅读并实现此处描述的方法 Revit Python Pick Object / Select Object 。它工作正常
假设我想创建一个基于云的服务,该服务可以连接到 Revit Server 并获取模型数据、对其进行处理,然后在基于 Web 的界面中向用户返回一些有用的信息。然后用户修改模型并将更改提交到服务器。我的
我打开文件 A,其中链接了 x 个文件 B。文件 B 还链接了 x 个文件 C。我想知道文件 C 的位置名称。 我使用 dynamo for revit 收集文件 A 中的 RevitLinkInst
在 Revit API 中,我知道我可以获得当前正在运行的 Revit 实例的版本(ControlledApplication.VersionBuild,ControlledApplication.V
我正在尝试使用 Revit API 激活 View 。我想要做的正是提示用户选择一些墙,但是当用户被问到时,他无法切换 View 以选择更多墙(此时一切都变灰了)。 所以我想激活的 View (我的意
长期以来,我一直在使用 Autodesk Forge 的 Model Derivative API(成功)将 Revit 文件导出到 IFC。 但是,我注意到即使使用法语版软件(即 Revit FRA
我有一个非常“笼统”的问题。我正在使用 Revit API(使用 python)进行开发,有时我会观察到 Revit session 在我的测试和试验期间变得更慢(Revit 保持打开的时间越长,它似
我尝试使用 python 编辑我的 Revit.ini 文件,但是我仍然收到以下错误。今天大部分时间我都在用头撞墙。在此感谢任何帮助。 我一直在 python 2.7 上使用 ConfigParser
我需要为许多元素(>100'000 个项目)找到大纲。目标元素来自 FilteredElementCollector。像往常一样,我正在寻找最快的方法。 现在我尝试遍历所有元素以获取其 Bouding
有一个元素的参数有 5 个选择(组合框的样式)。我知道如何获取当前选定的选项,但是有没有办法检索其他 4 个选项? 最佳答案 它们存储在 SimilarObjectTypes作为 ElementSet
我想重写我的 Revit 插件之一,以便它通过 MVVM 使用 WPF,因为与 Windows 窗体相比,我更喜欢 WPF 的外观和功能。 我已将 Jeremy Tammik 的 Revit 模板向导
我看到一个已经运行多年的基准有一些奇怪的行为。该基准适用于 Autodesk Revit,它可以使用日志文件来自动执行任务和记录时间。基准测试将读取一系列模块化日志文件的 XML 文件,这些文件可以根
我有这段代码,但我不知道如何显示我选择的墙的位置、高度和长度: using System; using System.Collections.Generic; using System.Linq; u
是否可以在不运行 Revit 的情况下创建与 Revit 数据库模型交互的我自己的 Revit API 代码的单元测试。 如果是这样,如何实现。 最佳答案 我参与了其中提到的一些话题。我什至参与过一个
我对 C# 和编码还很陌生。如果可能的话,我正在寻找一些帮助来弄清楚如何修复这段代码以使其正常工作。 他们单独工作。我可以在功能区上创建一个新按钮并执行标准的 hello world。我还有一个宏,可
我正在尝试拦截 Revit 并阻止窗口打开。具体来说,我试图将基调应用于一个对象,然后让用户创建一个基调标签,但是我这样做的任何方式都让他们放置基调,但随后立即给他们对话框来选择一个基调,但我不' 希
我想在查看器中放置一些 Three.js 对象,并在 Revit 模型中获得该对象的估计坐标。如何将这些坐标转换为查看器坐标以放置对象? 最佳答案 由于 Forge 查看器默认会对加载的模型应用全局偏
在执行 IExternalCommand 时,我可以通过 ExternalCommandData 轻松获取应用程序和文档 UIApplication uiApp = commandDa
我是一名优秀的程序员,十分优秀!