初步代码和思路还需要完善与X轴有夹角的情况,套管尺寸和洞的尺寸参照套管图集02S404,已完善旋转问题
namespace OpeningHole
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
[Journaling(JournalingMode.NoCommandData)]
public class Class1 : IExternalCommand
{
string path = @“C:\Users\Administrator\source\repos\OpeningHole\Resources\刚性套管A-DN50-DN2000.rfa”;
string holePath = @“C:\Users\Administrator\source\repos\OpeningHole\Resources\墙圆形洞口.rfa”;
string holePathTable = @“C:\Users\Administrator\source\repos\OpeningHole\Resources\洞口尺寸对照表.csv”;
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uIDocument = commandData.Application.ActiveUIDocument;
Document document = uIDocument.Document;
Reference element = uIDocument.Selection.PickObject(ObjectType.Element, "选择要开洞的管线");
Pipe pipe = document.GetElement(element) as Pipe;
if (pipe == null)
{
return Result.Cancelled;
}
Dictionary<Element, XYZ> pointXYZ = GetCenterPoint(document, pipe);
using (Transaction tr = new Transaction(document, "载入套管族"))
{
tr.Start();
Bushing(document, pointXYZ, pipe);
tr.Commit();
}
return Result.Succeeded;
}
/// <summary>
/// 放置墙洞口,并设置参数
/// </summary>
/// <param name="doc"></param>
/// <param name="filePath"></param>
/// <param name="pipeDiameter"></param>
/// <param name="pipeHeight"></param>
/// <param name="pipeDiameterD"></param>
/// <param name="level"></param>
/// <param name="pointXYZ"></param>
private void WallOpeningHole(Document doc, string filePath, string pipeDiameter, double pipeHeight, double pipeDiameterD, Level level, Element element, XYZ point)
{
Family holeFamily = LoadFamily(doc, holePath);
FamilySymbol holeFamilySymbol = GetFamilySymbol(doc, holeFamily);
holeFamilySymbol.Activate();
try
{
FamilyInstance holeFamilyInstance = doc.Create.NewFamilyInstance(point, holeFamilySymbol, element, level, StructuralType.NonStructural);
Parameter holeParameter = holeFamilyInstance.LookupParameter("R");
double RValue = CsvReader(holePathTable, pipeDiameter) / 2 / 304.8;
holeParameter.Set(RValue);
Parameter holeHeight = holeFamilyInstance.LookupParameter("相对标高的偏移");
double t = pipeHeight - RValue;
holeHeight.Set(t);
}
catch (Exception ex)
{
TaskDialog.Show("Revit", $"{ex.Message}");
}
}
/// <summary>
/// 查找套管开洞尺寸对照表
/// </summary>
/// <param name="path"></param>
/// <param name="searchValue">150mm</param>
/// <returns></returns>
private double CsvReader(string path, string searchValue)
{
string str = searchValue.Substring(0, searchValue.Length - 2).Trim();
try
{
using (StreamReader reader = new StreamReader(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] values = line.Split(",");
if (values[0] == str)
{
return Convert.ToDouble(values[1]);
}
}
}
}
catch (Exception e)
{
TaskDialog.Show("Error", $"读取CSV文件时出错: {e.Message}");
}
return -1.0;
}
/// <summary>
/// 放置套管和开洞
/// </summary>
/// <param name="document"></param>
/// <param name="pointXYZ"></param>
/// <param name="pipe"></param>
private void Bushing(Document document, Dictionary<Element, XYZ> pointXYZ, Pipe pipe)
{
Family family = LoadFamily(document, path);//载入套管族
FamilySymbol familySymbol = GetFamilySymbol(document, family);//套管的族类型
familySymbol.Activate();
double pipeDiameter = pipe.Diameter;//获取管道直径
ElementId levelID = pipe.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM).AsElementId();
Level level = document.GetElement(levelID) as Level;
string pipeDiameterStr = pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).AsValueString();
double pipeHeight = pipe.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble();
try
{
foreach (var item in pointXYZ)
{
familySymbol.Activate();
FamilyInstance familyInstance = document.Create.NewFamilyInstance(item.Value, familySymbol, StructuralType.NonStructural);//放置套管
Parameter parameter = familyInstance.LookupParameter("公称尺寸");
parameter.Set(pipeDiameter);//设置套管尺寸
Element instance = item.Key;//与管道碰撞的墙或者梁实例
if (instance.Category.Name == "墙")
{
double wallThickness = (instance as Wall).Width;
Parameter length = familyInstance.LookupParameter("套管长度");
//length.Set(UnitUtils.ConvertFromInternalUnits(wallThickness, UnitTypeId.Millimeters));
length.Set(wallThickness);//设置套管长度
Line axis = Line.CreateBound(item.Value, new XYZ(item.Value.X, item.Value.Y, item.Value.Z + 1));
double angle = PipeToXAngle(pipe);
ElementTransformUtils.RotateElement(document, familyInstance.Id, axis, angle);//设置套管旋转角度
WallOpeningHole(document, holePath, pipeDiameterStr, pipeHeight, pipeDiameter, level, item.Key, item.Value);
}
else if (instance.Category.Name == "楼板")
{
double RValue = CsvReader(holePathTable, pipeDiameterStr) / 2 / 304.8;
Arc arc = Arc.Create(item.Value, RValue, 0, 2 * Math.PI, XYZ.BasisX, XYZ.BasisY);
CurveArray curveArray = new CurveArray();
curveArray.Append(arc);
document.Create.NewOpening(instance, curveArray, true);
Line axis = Line.CreateBound(item.Value, new XYZ(item.Value.X, item.Value.Y + 1, item.Value.Z));
ElementTransformUtils.RotateElement(document, familyInstance.Id, axis, Math.PI / 2);
Parameter length = familyInstance.LookupParameter("套管长度");
double floorHeight = instance.get_Parameter(BuiltInParameter.FLOOR_ATTR_THICKNESS_PARAM).AsDouble();
length.Set(floorHeight);//获取楼板的厚度
}
else if (instance.Category.Name == "结构框架")
{
double RValue = CsvReader(holePathTable, pipeDiameterStr) / 2 / 304.8;
Arc arc = Arc.Create(item.Value, RValue, 0, 2 * Math.PI, XYZ.BasisX, XYZ.BasisZ);
CurveArray curveArray = new CurveArray();
curveArray.Append(arc);
FamilyInstance beamInstance = instance as FamilyInstance;
Parameter length = familyInstance.LookupParameter("套管长度");
double b = beamInstance.Symbol.LookupParameter("b").AsDouble();
TaskDialog.Show("Revit", $"{b}");
//document.Create.NewOpening(instance, curveArray, Autodesk.Revit.Creation.eRefFace.CenterY);
length.Set(b);
double angle = PipeToXAngle(pipe);
Line axis = Line.CreateBound(item.Value, new XYZ(item.Value.X, item.Value.Y, item.Value.Z + 1));
ElementTransformUtils.RotateElement(document, familyInstance.Id, axis, angle);//设置套管旋转角度
document.Create.NewOpening(instance, curveArray, Autodesk.Revit.Creation.eRefFace.CenterY);
TaskDialog.Show("Revit", "{梁}");
}
}
}
catch (Exception e)
{
TaskDialog.Show("Revit", $"放置族失败{e.Message}");
}
}
/// <summary>
/// 获取套管的族实例
/// </summary>
/// <param name="document"></param>
/// <param name="family"></param>
/// <returns></returns>
private FamilySymbol GetFamilySymbol(Document document, Family family)
{
FilteredElementCollector col = new FilteredElementCollector(document);
FamilySymbol familySymbol = col.OfClass(typeof(FamilySymbol)).Cast<FamilySymbol>().FirstOrDefault(fs => fs.Name == family.Name);
return familySymbol;
}
/// <summary>
/// 获取与管道碰撞的墙
/// </summary>
/// <param name="document"></param>
/// <param name="pipe"></param>
/// <returns></returns>
private List<Element> GetIntersectsWall(Document document, Pipe pipe)
{
FilteredElementCollector cols = new FilteredElementCollector(document);
ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(pipe);
ElementCategoryFilter Cfilter = new ElementCategoryFilter(BuiltInCategory.OST_Walls);
LogicalAndFilter logicalAndFilter = new LogicalAndFilter(elementIntersectsElementFilter, Cfilter);
return cols.WherePasses(logicalAndFilter).ToList();
}
/// <summary>
/// 获取与管道碰撞的楼板
/// </summary>
/// <param name="document"></param>
/// <param name="pipe"></param>
/// <returns></returns>
private List<Element> GetIntersectFloor(Document document, Pipe pipe)
{
FilteredElementCollector cols = new FilteredElementCollector(document);
ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(pipe);
ElementCategoryFilter Cfilter = new ElementCategoryFilter(BuiltInCategory.OST_Floors);
LogicalAndFilter logicalAndFilter = new LogicalAndFilter(elementIntersectsElementFilter, Cfilter);
return cols.WherePasses(logicalAndFilter).ToList();
}
/// <summary>
/// 获取与管道碰撞的梁
/// </summary>
/// <param name="document"></param>
/// <param name="pipe"></param>
/// <returns></returns>
private List<Element> GetIntersectBeam(Document document, Pipe pipe)
{
FilteredElementCollector cols = new FilteredElementCollector(document);
ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(pipe);
ElementCategoryFilter Cfilter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralFraming);
LogicalAndFilter logicalAndFilter = new LogicalAndFilter(elementIntersectsElementFilter, Cfilter);
return cols.WherePasses(logicalAndFilter).ToList<Element>();
}
/// <summary>
/// 获取与管线碰撞的元素和中心点
/// </summary>
/// <param name="doc"></param>
/// <param name="pipe"></param>
/// <returns></returns>
private Dictionary<Element, XYZ> GetCenterPoint(Document doc, Pipe pipe)
{
List<Element> element1 = GetIntersectsWall(doc, pipe);
List<Element> element2 = GetIntersectFloor(doc, pipe);
List<Element> element3 = GetIntersectBeam(doc, pipe);
List<Element> elements = new List<Element>();
elements.AddRange(element1);
elements.AddRange(element2);
elements.AddRange(element3);
//List<XYZ> centerPoint = new List<XYZ>();
List<XYZ> point = new List<XYZ>();
Dictionary<Element, XYZ> intersectElementAndPoint = new Dictionary<Element, XYZ>();
try
{
foreach (Element item in elements)
{
point.Clear();
point = Get_Intersection(GetCurve(pipe), GetFace(item));
XYZ centerPoint = new XYZ((point[0].X + point[1].X) / 2,
(point[0].Y + point[1].Y) / 2, (point[0].Z + point[1].Z) / 2);
intersectElementAndPoint.Add(item, centerPoint);
}
}
catch (Exception)
{
TaskDialog.Show("Revit", "未找到与选择管线碰撞的墙,梁和楼板");
}
return intersectElementAndPoint;
}
private Curve GetCurve(Pipe pipe)
{
Curve curve = null;
LocationCurve locationCurve = pipe.Location as LocationCurve;
if (locationCurve != null)
{
curve = locationCurve.Curve;
}
return curve;
}
/// <summary>
/// 获取梁或者墙的表面
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private List<Face> GetFace(Element element)
{
Options opt = new Options { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
GeometryElement geometryElement = element.get_Geometry(opt);
List<Face> faces = new List<Face>();
foreach (GeometryObject item in geometryElement)
{
if (item is Solid)
{
Solid solid = item as Solid;
if (solid != null && solid.Faces.Size > 0)
{
foreach (Face soliFace in solid.Faces)
{
PlanarFace planarFace = soliFace as PlanarFace;
if (planarFace != null)
{
faces.Add(planarFace);
}
}
}
}
else if (item is GeometryInstance)
{
GeometryInstance instance = item as GeometryInstance;
if (instance != null)
{
GeometryElement ge = instance.GetInstanceGeometry();
foreach (GeometryObject go in ge)
{
Solid solid = go as Solid;
if (solid != null && solid.Faces.Size > 0)
{
foreach (Face face in solid.Faces)
{
PlanarFace planarFace = face as PlanarFace;
if (planarFace != null)
{
faces.Add(planarFace);
}
}
}
}
}
}
}
return faces;
}
/// <summary>
/// 获取管道与面的交点
/// </summary>
/// <param name="pipeLine"></param>
/// <param name="listFace"></param>
/// <returns></returns>
public List<XYZ> Get_Intersection(Curve pipeLine, List<Face> listFace)
{
List<XYZ> lstIntersection = new List<XYZ>();
foreach (Face item in listFace)
{
XYZ ptJd = CaculateIntersection(item, pipeLine);
if (ptJd != null)
{
lstIntersection.Add(ptJd);
}
}
return lstIntersection;
}
/// <summary>
/// 计算线与面的交点
/// </summary>
/// <param name="face"></param>
/// <param name="curve"></param>
/// <returns></returns>
private XYZ CaculateIntersection(Face face, Curve curve)
{
XYZ intersection = null;
try
{
IntersectionResultArray resultArray = new IntersectionResultArray();
SetComparisonResult setComparisonResult = face.Intersect(curve, out resultArray);
if (SetComparisonResult.Disjoint != setComparisonResult && resultArray != null)
{
if (!resultArray.IsEmpty)
{
intersection = resultArray.get_Item(0).XYZPoint;
}
}
}
catch (Exception ex)
{ }
return intersection;
}
private double PipeToXAngle(Pipe pipe)
{
Curve curve = GetCurve(pipe);
Line line = curve as Line;
XYZ direction = line.Direction;
// 获取管道方向向量与X轴的夹角
double angleToXAxis = XYZ.BasisX.AngleTo(direction);
if (direction.Y<0)
{
return 2 * Math.PI - angleToXAxis;
}
return angleToXAxis;
}
#region 载入族
private Family LoadFamily(Document doc, string path)
{
Family family = IsFamilyInFile(doc, path);
if (family == null)
{
bool loadResult = doc.LoadFamily(path, out family);
if (loadResult)
{
return family;
}
else
{
TaskDialog.Show(“载入族”, $“族 ‘{family.Name}’ 载入失败。”);
}
}
return family;
}
private Family IsFamilyInFile(Document doc, string path)
{
Family family = null;
string name = Path.GetFileNameWithoutExtension(path);//不带文件后缀
FilteredElementCollector elements = new FilteredElementCollector(doc);
List familys = elements.OfClass(typeof(Family)).Cast().ToList();
foreach (Family item in familys)
{
if (item.Name == name)
{
family = item;
break;
}
}
return family;
}
#endregion
}
}