前言
这个例子介绍了 Revit 的自由造型能力,内容包含创建拉伸、进行布尔操作等。
内容
创建一个内建体量,以及用模型线绘制一个轮廓。选择体量和轮廓,程序会用轮廓做一个拉伸,这个拉伸的高度比体量高。然后对两个体量进行布尔减操作,将结果作为常规模型族载入到当前文件,并放到对应位置。
代码逻辑
主要逻辑在 CreateNegativeBlock
,文件:Revit 2021 SDK\Samples\FreeFormElement\CS\FreeFormElementUtils.cs
从线的引用里获取线的几何图形
几点需要注意的:
- 通过
Reference
可以从文档获取Element
,doc.GetElement(reference)
- 对获得的 Curve 按首尾相接进行排序
public static IList<Curve> GetContiguousCurvesFromSelectedCurveElements(Document doc, IList<Reference> boundaries)
{
List<Curve> curves = new List<Curve>();
// Build a list of curves from the curve elements
foreach (Reference reference in boundaries)
{
CurveElement curveElement = doc.GetElement(reference) as CurveElement;
curves.Add(curveElement.GeometryCurve.Clone());
}
// Walk through each curve (after the first) to match up the curves in order
for (int i = 0; i < curves.Count; i++)
{
Curve curve = curves[i];
XYZ endPoint = curve.GetEndPoint(1);
// find curve with start point = end point
for (int j = i + 1; j < curves.Count; j++)
{
// Is there a match end->start, if so this is the next curve
if (curves[j].GetEndPoint(0).IsAlmostEqualTo(endPoint, 1e-05))
{
Curve tmpCurve = curves[i + 1];
curves[i + 1] = curves[j];
curves[j] = tmpCurve;
continue;
}
// Is there a match end->end, if so, reverse the next curve
else if (curves[j].GetEndPoint(1).IsAlmostEqualTo(endPoint, 1e-05))
{
Curve tmpCurve = curves[i + 1];
curves[i + 1] = CreateReversedCurve(curves[j]);
curves[j] = tmpCurve;
continue;
}
}
}
return curves;
}
创建闭合线圈
CurveLoop
的创建需要首尾相连的线GeometryCreationUtilities.CreateExtrusionGeometry
的参数是List<CurveLoop>
CurveLoop loop = null;
try
{
loop = CurveLoop.Create(curves);
}
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
// Curves are not contiguous
return FailureCondition.CurvesNotContigous;
}
List<CurveLoop> loops = new List<CurveLoop>();
loops.Add(loop);
创建自由造型几何形体
// 1. 确定拉伸的高度,确保比体量高1.
// Get elevation of loop
double elevation = curves[0].GetEndPoint(0).Z;
// Get height for extrusion
BoundingBoxXYZ bbox = targetElement.get_BoundingBox(null);
double height = bbox.Max.Z - elevation;
height += 1;
// 2. 创建一个拉伸体
Solid block = GeometryCreationUtilities.CreateExtrusionGeometry(loops, XYZ.BasisZ, height);
// 3. 用选中的体量作为减体量,源码中考虑多个solid,这里省略了。
IList<Solid> fromElement = GetTargetSolids(targetElement);
Solid toSubtract = fromElement[0];
// 4. 进行布尔操作
try
{
BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(block, toSubtract, BooleanOperationsType.Difference);
}
catch (Autodesk.Revit.Exceptions.InvalidOperationException)
{
return FailureCondition.NoIntersection;
}
用计算结果创建族
// Create family
Document familyDoc = app.NewFamilyDocument(familyTemplate);
// Create freeform element
using (Transaction t = new Transaction(familyDoc, "Add element"))
{
t.Start();
RevitFreeFormElement element = Autodesk.Revit.DB.FreeFormElement.Create(familyDoc, block);
t.Commit();
}
FreeFormElement 的接口:
namespace Autodesk.Revit.DB
{
public class FreeFormElement : GenericForm
{
public static FreeFormElement Create(Document document, Solid geometry);
public bool CanOffsetFace(Face face);
public void SetFaceOffset(Face face, double offset);
public void UpdateSolidGeometry(Solid newGeometry);
}
}
FreeFormElement 的继承层次:
载入族
Family family = familyDoc.LoadFamily(doc, familyLoadOptions);
放置族
// 1. 用 FamilySymbolFilter 找到对应的 FamilySymbol
FilteredElementCollector collector = new FilteredElementCollector(doc);
collector.WherePasses(new FamilySymbolFilter(family.Id));
FamilySymbol fs = collector.FirstElement() as FamilySymbol;
//2. 放置族到对应的位置,底面和输入轮廓重合
using (Transaction t2 = new Transaction(doc, "Place instance"))
{
t2.Start();
if (!fs.IsActive)
fs.Activate();
doc.Create.NewFamilyInstance(XYZ.Zero, fs, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
t2.Commit();
}