BIMBANK 导言:今天程序员辣翅给大家分享一下 Revit 中 Analysis Visualization Framework (下面简称 AVF)的使用心得。AVF 是主要用于将分析数据可视化的一个框架。分析显示的样式有如下图五种。
我们这次着重讨论下有色表面。使用的软件是 Revit 2018,不同的版本样式种类可能也会有不同。
我们以墙面为例来介绍一下这里的有色表面分析样式。实际用途可以为墙面形变分析或者受力分析等等。首先,按通常一样新建一个类继承 IExternalCommand,这里命名为 AvfCommand。为了方便说明,我们将所有功能都写在这个类里面。先提示用户选择要分析的墙面。
[Transaction(TransactionMode.Manual)]
class AvfCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, refstring message, ElementSet elements)
{
UIDocument uidoc =commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
//获取选择的墙面
Reference faceRef =uidoc.Selection.PickObject(ObjectType.Face, "请选择墙面");
Element wall = doc.GetElement(faceRef.ElementId);
Face face = wall.GetGeometryObjectFromReference(faceRef)as Face;
return Result.Succeeded;
}
}
在给所选墙面“涂”上分析颜色之前,我们需要先添加两个辅助方法SetDisplayStyle
和SetupSFM
,分别用来设置好显示样式和SpatialFieldManager。SpatialFieldManager是用来管理分析数据的。
private void SetDisplayStyle(View view)
{
//确认当前视图中有没有我们的测试分析样式,有的话直接使用,否则我们新建样式
Document doc = view.Document;
ElementId id = AnalysisDisplayStyle.FindByName(doc, "测试分析样式");
if (ElementId.InvalidElementId == id)
{
//新建样式
using (Transaction t = new Transaction(doc))
{
t.Start("Create AVF Display Style");
//有色表面设置,这里我们只设置了不显示表面网格线
AnalysisDisplayColoredSurfaceSettingscoloredSurfaceSettings = newAnalysisDisplayColoredSurfaceSettings();
coloredSurfaceSettings.ShowGridLines = false;
//颜色设置,设置数据最大值和最小值的颜色,中间值会在这两者之间过渡
AnalysisDisplayColorSettings colorSettings = newAnalysisDisplayColorSettings();
colorSettings.MinColor = new Color(0, 255, 0);
colorSettings.MaxColor = new Color(255, 0, 0);
//图例设置,显示图例
AnalysisDisplayLegendSettings legendSettings = newAnalysisDisplayLegendSettings();
legendSettings.ShowLegend = true;
//创建显示样式并使用到当前视图
AnalysisDisplayStyle analysisDisplayStyle =AnalysisDisplayStyle.CreateAnalysisDisplayStyle(
doc, "测试分析样式", coloredSurfaceSettings, colorSettings,legendSettings);
view.AnalysisDisplayStyleId = analysisDisplayStyle.Id;
t.Commit();
}
}
else
{
//使用已有的样式
using (Transaction t = new Transaction(doc))
{
t.Start("Set AVF Display Style");
view.AnalysisDisplayStyleId = id;
t.Commit();
}
}
}
public SpatialFieldManager SetupSFM(View view, ReferencefaceRef)
{
//确认当前视图已设置了显示样式
if (view.AnalysisDisplayStyleId ==ElementId.InvalidElementId)
SetDisplayStyle(view);
SpatialFieldManager sfm =SpatialFieldManager.GetSpatialFieldManager(view);
if (null == sfm)
sfm = SpatialFieldManager.CreateSpatialFieldManager(view,1);
//通过faceRef我们在SpatialFieldManager中创建一个空白的原始的分析结果
//sfpIndex是一个成员变量,初始值为-1. 这里判断之前是否已经创建过分析结果,如果有就移除之前的
if (0 < sfpIndex)
{
sfm.RemoveSpatialFieldPrimitive(sfpIndex);
}
sfpIndex = sfm.AddSpatialFieldPrimitive(faceRef);
//注册AnalysisResultSchema, AnalysisResultSchema包含了所有分析结果的信息
//schemaId是一个成员变量,初始值为-1,用于避免重复注册
if (-1 != schemaId)
{
IList<int> results = sfm.GetRegisteredResults();
if (!results.Contains(schemaId))
{
schemaId = -1;
}
}
if (-1 == schemaId)
{
AnalysisResultSchema schema = new AnalysisResultSchema("测试分析", "测试分析");
List<string> unitNames = new List<string>(new string[1] {"mm" });
List<double> unitFactors = new List<double>(new double[1] { 1.0 });
schema.SetUnits(unitNames, unitFactors);
schemaId = sfm.RegisterResult(schema);
}
return sfm;
}
然后我们就可以给墙面“上色”了,添加PaintFace
方法。
private void PaintFace(SpatialFieldManager sfm, Face face)
{
//通过墙面的BoundingBox,我们可以获得该墙面的最小和最大坐标点
//两者之间的所有点就是我们可以添加分析数据的点,根据实际数据选择合理的点
//这里我们简单的通过ustep和vstep遍历整个墙面
BoundingBoxUV bb = face.GetBoundingBox();
double umin = bb.Min.U;
double umax = bb.Max.U;
double ustep = 0.2 * (umax - umin);
double vmin = bb.Min.V;
double vmax = bb.Max.V;
double vstep = 0.2 * (vmax - vmin);
//遍历整个墙面,记录所有点和每个点对应的分析数据值
//这里我们给每个点随机匹配个值
IList<UV> uvPts = new List<UV>();
IList<ValueAtPoint> uvValues = new List<ValueAtPoint>();
List<double> vals = new List<double>(1);
vals.Add(0);
Random random = new Random();
for (double u = umin; u <= umax; u += ustep)
{
for (double v = vmin; v <= vmax; v += vstep)
{
UV uv = new UV(u, v);
//确认点在面上
if (face.IsInside(uv))
{
uvPts.Add(uv);
vals[0] = random.NextDouble();
uvValues.Add(new ValueAtPoint(vals));
}
}
}
//用设置好的点和值更新分析结果
FieldDomainPointsByUV fpts = newFieldDomainPointsByUV(uvPts);
FieldValues fvals = new FieldValues(uvValues);
sfm.UpdateSpatialFieldPrimitive(sfpIndex, fpts, fvals,schemaId);
}
最后在Execute
方法中调用下PaintFace
就完成了。
public Result Execute(ExternalCommandData commandData, refstring message, ElementSet elements)
{
UIDocument uidoc =commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
//获取选择的墙面
Reference faceRef =uidoc.Selection.PickObject(ObjectType.Face, "请选择墙面");
Element wall = doc.GetElement(faceRef.ElementId);
Face face = wall.GetGeometryObjectFromReference(faceRef)as Face;
SpatialFieldManager sfm = SetupSFM(uidoc.ActiveView,faceRef);
PaintFace(sfm, face);
return Result.Succeeded;
}
运行测试结果如下。因为是固定间隔随机值,所以看着有点奇怪。
参考:https://github.com/jeremytammik/RvtFader