有个功能需要从模型中选面,做一些造型。
第一次:起初觉得很简单,使用sel.PickObject(ObjectType.Face)后发现存在问题:绘制的线有的在面上,有的不在面上,从face的属性看不出来任何规律。
第二次:上网搜到了一篇前辈的文章:https://blog.csdn.net/qq_34968766/article/details/82934915。觉得很有道理,抄过去之后,仍然存在同样问题。
第三次:折腾了半天,暂时找个折中的办法。采用 sel.PickObject(ObjectType.PointOnElement),判断点是不是在面上,若在就直接画线,若不在就采用上面那位前辈的方法。结果还可以。
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System;
namespace IECOMMAND.Task
{
/// <summary>
/// 从网上抄的选面画线,结果也不理想,会出现跑偏现象
/// </summary>
[Transaction(TransactionMode.Manual)]
class FaceToLine : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;//获取活动文档
Selection sel = uidoc.Selection;
sel.PickObject(ObjectType.Face);
Reference oneRR = sel.PickObject(ObjectType.PointOnElement);
if (oneRR == null) return Result.Cancelled;
Element e = doc.GetElement(oneRR);
XYZ onePt = oneRR.GlobalPoint;
PlanarFace face = doc.GetElement(oneRR).GetGeometryObjectFromReference(oneRR) as PlanarFace;
IntersectionResult oneIR = face.Project(onePt);
if (oneIR != null && oneIR.Distance == 0)
{
TaskDialog.Show("dd", "点在面上");
PtOnFace(doc, face);
}
else
{
TaskDialog.Show("dd", "点不在面上");
FamilyInstance fi = (FamilyInstance)e;
Transaction trans = new Transaction(doc);
FaceNewModelLine(doc, face, fi.GetTotalTransform());
}
return Result.Succeeded;
}
/// <summary>
/// 点在面上
/// </summary>
/// <param name="doc"></param>
/// <param name="face"></param>
private static void PtOnFace(Document doc, PlanarFace face)
{
try
{
BRepBuilder breBuild = new BRepBuilder(BRepType.OpenShell);
//先创建一个假面(不能直接用,每个面都需要添加至少一个循环边,带洞的面需要多个循环边)
bool faceReverse = face.OrientationMatchesSurfaceOrientation ? false : true;
BRepBuilderGeometryId faceId = breBuild.AddFace(BRepBuilderSurfaceGeometry.Create(face.GetSurface(), null), faceReverse);
EdgeArrayArrayIterator edgeAAIter = face.OrientationMatchesSurfaceOrientation ? face.EdgeLoops.ForwardIterator() : face.EdgeLoops.ReverseIterator();
while (edgeAAIter.MoveNext())
{
BRepBuilderGeometryId loopId = breBuild.AddLoop(faceId);
EdgeArray edgeArr = (EdgeArray)edgeAAIter.Current;
EdgeArrayIterator edgeIter = edgeArr.ForwardIterator();
while (edgeIter.MoveNext())
{
Edge gg = (Edge)edgeIter.Current;
BRepBuilderEdgeGeometry breEdge = BRepBuilderEdgeGeometry.Create(gg.AsCurveFollowingFace(face));
BRepBuilderGeometryId bEdgeId = breBuild.AddEdge(breEdge);
breBuild.AddCoEdge(loopId, bEdgeId, false);
}
breBuild.FinishLoop(loopId);
}
breBuild.FinishFace(faceId);
breBuild.Finish();
using (var ts = new Transaction(doc, "创建"))
{
ts.Start();
//使用体量的话,只能用面表示模板面积。好处是使用brepbuilder创建面对象比较简单。
var ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_Mass));
try
{
ds.SetShape(breBuild);
ts.Commit();
}
catch (Exception sdd)
{
TaskDialog.Show("dd", "set wrong\n" + sdd.Message);
ts.Dispose();
}
}
}
catch
{
TaskDialog.Show("dd", "build wrong");
}
}
//根据PlanarFace创建平面模型线
//考虑了trans变换,但是效果不理想
private void FaceNewModelLine(Document RevitDoc, PlanarFace face, Transform trans)
{
foreach (EdgeArray e in face.EdgeLoops)
{
foreach (Edge e2 in e)
{
if (e2.AsCurve() is Line)
{
Line line = (e2.AsCurve()) as Line;//因为怕存在Arc曲线无法转换
Plane plane = null;
if (trans != null)//转换坐标
{
plane = Plane.CreateByNormalAndOrigin(trans.OfVector(face.FaceNormal), trans.OfPoint(face.Origin));
XYZ xyz1 = line.GetEndPoint(0);
XYZ xyz2 = line.GetEndPoint(1);
line = Line.CreateBound(trans.OfPoint(xyz1), trans.OfPoint(xyz2));
}
else
{
plane = Plane.CreateByNormalAndOrigin(face.FaceNormal, face.Origin);
}
using (Transaction transaction = new Transaction(RevitDoc))
{
transaction.Start("Create Model Line");
//创建sketchPlane
SketchPlane modelSketch = SketchPlane.Create(RevitDoc, plane); //创建模型线
RevitDoc.Create.NewModelCurve(line, modelSketch);
transaction.Commit();
}
}
}
}
}
}
}