463 lines
18 KiB
C#
463 lines
18 KiB
C#
using Autodesk.Revit.DB;
|
||
using RookieStation.ProjectConfig;
|
||
using RookieStation.Extension;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
|
||
namespace RookieStation.Utils
|
||
{
|
||
internal static class RsRevitUtils
|
||
{
|
||
/// <summary>
|
||
/// 英尺转米
|
||
/// </summary>
|
||
/// <param name="valueToConvert"></param>
|
||
/// <returns></returns>
|
||
public static double ConvertFeetToMetre(double valueToConvert)
|
||
{
|
||
return UnitUtils.ConvertFromInternalUnits(valueToConvert, DisplayUnitType.DUT_METERS);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 平方英尺转平方米
|
||
/// </summary>
|
||
/// <param name="valueToConvert"></param>
|
||
/// <returns></returns>
|
||
public static double ConvertSquareFeetToSquareMetre(double valueToConvert)
|
||
{
|
||
return UnitUtils.ConvertFromInternalUnits(valueToConvert, DisplayUnitType.DUT_SQUARE_METERS);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 英尺转换成毫米单位
|
||
/// </summary>
|
||
/// <param name="valueToConvert"></param>
|
||
/// <returns></returns>
|
||
public static double ConvertFeetToMillimetre(double valueToConvert)
|
||
{
|
||
return UnitUtils.ConvertFromInternalUnits(valueToConvert, DisplayUnitType.DUT_MILLIMETERS);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过名称获取默认的墙类型完整厚度
|
||
/// </summary>
|
||
/// <param name="wallTypeName">墙类型包含的字符串</param>
|
||
/// <returns></returns>
|
||
public static double GetWallWidthByWallTypeName(Document doc, string wallTypeName, out WallType wallType)
|
||
{
|
||
double thickness = 0.0;
|
||
var walltypelist = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).OfClass(typeof(WallType)).Cast<WallType>();
|
||
wallType = walltypelist.FirstOrDefault(t => t.Name.Contains(wallTypeName));
|
||
if (wallType != null)
|
||
{
|
||
thickness = wallType.Width;
|
||
//var compounds = walltype.GetCompoundStructure();
|
||
//for (int i = 0; i < compounds.LayerCount; i++)
|
||
//{
|
||
// thickness += compounds.GetWidth();
|
||
//}
|
||
}
|
||
return thickness;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取元素定位点(仅以点定位的元素)
|
||
/// </summary>
|
||
/// <param name="instance"></param>
|
||
/// <returns></returns>
|
||
public static XYZ GetLocationPointByElement(Element instance)
|
||
{
|
||
return instance.Location is LocationPoint lp ? lp.Point : null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 调整族实例位置
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="instances">需要偏移的族实例</param>
|
||
/// <param name="referLine">用于调整偏移和角度的参考线</param>
|
||
/// <param name="offest">偏移量</param>
|
||
public static void AdjustInstances(Document doc, List<FamilyInstance> instances, Line referLine, double offest)
|
||
{
|
||
XYZ zdir = XYZ.BasisZ;
|
||
|
||
//通过第三点垂直于直线的单位向量(无论左右侧)*偏移距离(一半的闸机长度)
|
||
XYZ offestVector = zdir.CrossProduct(referLine.Direction).Normalize() * offest;
|
||
//旋转角度
|
||
double angle = XYZ.BasisY.AngleTo(offestVector);
|
||
//判断相对于Y轴是正向角度(逆时针)还是逆向角度(顺时针)
|
||
XYZ z = offestVector.CrossProduct(XYZ.BasisY).Normalize();
|
||
if (z.IsAlmostEqualTo(XYZ.BasisZ))
|
||
{
|
||
//逆向旋转,角度取负值
|
||
angle = -angle;
|
||
//var ml = doc.Create.NewModelCurve(Line.CreateBound(XYZ.Zero, re), SketchPlane.Create(doc, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, new XYZ())));
|
||
}
|
||
|
||
foreach (FamilyInstance instance in instances)
|
||
{
|
||
XYZ p = GetLocationPointByElement(instance);
|
||
Line l = Line.CreateUnbound(p, XYZ.BasisZ);
|
||
//旋转,移动
|
||
ElementTransformUtils.RotateElement(doc, instance.Id, l, angle);
|
||
ElementTransformUtils.MoveElement(doc, instance.Id, offestVector);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 朝着向量方向左侧偏移并调整角度对齐直线
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="fi"></param>
|
||
/// <param name="referLine"></param>
|
||
/// <param name="offest"></param>
|
||
public static void AdjustInstance(Document doc, FamilyInstance fi, Line referLine, double offest)
|
||
{
|
||
//朝着向量方向左侧偏移
|
||
XYZ zdir = XYZ.BasisZ;
|
||
|
||
//通过第三点垂直于直线的单位向量(无论左右侧)*偏移距离(一半的闸机长度)
|
||
XYZ offestVector = zdir.CrossProduct(referLine.Direction).Normalize() * offest;
|
||
//旋转角度
|
||
double angle = XYZ.BasisY.AngleTo(offestVector);
|
||
//判断相对于Y轴是正向角度(逆时针)还是逆向角度(顺时针)
|
||
XYZ z = offestVector.CrossProduct(XYZ.BasisY).Normalize();
|
||
if (z.IsAlmostEqualTo(XYZ.BasisZ))
|
||
{
|
||
//逆向旋转,角度取负值
|
||
angle = -angle;
|
||
}
|
||
|
||
XYZ p = GetLocationPointByElement(fi);
|
||
Line l = Line.CreateUnbound(p, XYZ.BasisZ);
|
||
//旋转,移动
|
||
ElementTransformUtils.RotateElement(doc, fi.Id, l, angle + Math.PI);
|
||
ElementTransformUtils.MoveElement(doc, fi.Id, offestVector);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加项目样板
|
||
/// </summary>
|
||
public static void AddProjectTemplate()
|
||
{
|
||
//Autodesk.Revit.ApplicationServices.Application.CurrentUsersDataFolderPath
|
||
string oriDateFilePath = @"" + Environment.GetEnvironmentVariable("appdata") + @"\Autodesk\Revit\Autodesk Revit 2020\Revit.ini";
|
||
string tmpDateFilePath = UserConstant.FamilyLibraryDirectory + "\\Rs.ini";
|
||
|
||
if (System.IO.File.Exists(oriDateFilePath))
|
||
{
|
||
using (StreamReader sr = new StreamReader(oriDateFilePath, Encoding.Unicode))
|
||
{
|
||
StreamWriter sw = new StreamWriter(tmpDateFilePath, false, Encoding.Unicode);
|
||
string inputLine = "";
|
||
|
||
while ((inputLine = sr.ReadLine()) != null)
|
||
{
|
||
if (inputLine.StartsWith("DefaultTemplate="))
|
||
{
|
||
inputLine.Insert(16, UserConstant.FamilyLibraryDirectory + "\\菜鸟驿站.rte,");
|
||
//if (inputLine.Contains("Example_SCHEMA.rte"))
|
||
//{
|
||
//}
|
||
//else
|
||
//{
|
||
// inputLine = inputLine + @", Example_SCHEMA=C:\temp\Example_SCHEMA.rte";
|
||
//}
|
||
}
|
||
sw.WriteLine(inputLine);
|
||
}
|
||
sw.Close();
|
||
}
|
||
|
||
System.IO.File.Replace(tmpDateFilePath, oriDateFilePath, null);
|
||
}
|
||
}
|
||
|
||
public static FamilySymbol GetGuideSymbol(Document doc)
|
||
{
|
||
FamilySymbol lineSymbol = null;
|
||
doc.Invoke(ts =>
|
||
{
|
||
Family lineFamily = GetLoadedFamily(doc, UserConstant.FamilyLibraryDirectory + "定位线.rfa");
|
||
lineSymbol = doc.GetElement(lineFamily.GetFamilySymbolIds().FirstOrDefault()) as FamilySymbol;
|
||
}, "载入定位线并布置");
|
||
|
||
return lineSymbol;
|
||
}
|
||
|
||
public static Line GetGuideGeometryAndDeleteGuide(Document doc, List<ElementId> eleIdsAdded)
|
||
{
|
||
ElementId referLineId = eleIdsAdded.FirstOrDefault();
|
||
FamilyInstance guideLine = doc.GetElement(referLineId) as FamilyInstance;
|
||
LocationCurve lc = guideLine.Location as LocationCurve;
|
||
Line line = lc.Curve as Line;
|
||
doc.Invoke(ts =>
|
||
{
|
||
doc.Delete(referLineId);
|
||
}, "删除参考线");
|
||
|
||
return line;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 元素的所有面
|
||
/// </summary>
|
||
/// <param name="item">元素</param>
|
||
/// <param name="options">打开方式</param>
|
||
/// <returns>所有的面</returns>
|
||
public static List<Face> GetFaceByElement(Element item, Options options)
|
||
{
|
||
List<Face> faces = new List<Face>();
|
||
//根据打开的方式得到几何信息
|
||
GeometryElement geometry = item.get_Geometry(options);
|
||
foreach (GeometryObject geomObj in geometry)
|
||
{
|
||
//geomObj为几何实例
|
||
GeometryInstance geomInstance = geomObj as GeometryInstance;
|
||
if (geomInstance != null)
|
||
{
|
||
//从实例中找到实例的几何体
|
||
foreach (GeometryObject instObj in geomInstance.GetInstanceGeometry())
|
||
{
|
||
//三维的实体
|
||
Solid instSolid = instObj as Solid;
|
||
if (instSolid == null || instSolid.Faces.Size == 0 || instSolid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
foreach (Face face in instSolid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
//geomObj为几何体
|
||
Solid solid = geomObj as Solid;
|
||
if (solid != null)
|
||
{
|
||
if (solid.Faces.Size == 0 || solid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
foreach (Face face in solid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return faces;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取族实例所有面(实际为族类型的所有面)
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <returns></returns>
|
||
public static List<Face> GetFacesByFamilyInstance(FamilyInstance instance, Options options)
|
||
{
|
||
List<Face> faces = new List<Face>();
|
||
//根据打开的方式得到几何信息
|
||
GeometryElement geometry = instance.get_Geometry(options);
|
||
foreach (GeometryObject geomObj in geometry)
|
||
{
|
||
//geomObj为几何实例
|
||
GeometryInstance geomInstance = geomObj as GeometryInstance;
|
||
//族实例未修改过(连接,剪切,复制,扩展)
|
||
bool usesSymbolGeometry = (instance is FamilyInstance) && !(instance as FamilyInstance).HasModifiedGeometry();
|
||
var bo = instance.HasModifiedGeometry();
|
||
GeometryElement instanceGeometry = usesSymbolGeometry ? geomInstance.GetSymbolGeometry() : geomInstance.GetInstanceGeometry();
|
||
|
||
if (instanceGeometry != null)
|
||
{
|
||
//instanceGeometry.GetTransformed();
|
||
//从实例中找到实例的几何体
|
||
foreach (GeometryObject instObj in instanceGeometry)
|
||
{
|
||
//三维的实体
|
||
Solid instSolid = instObj as Solid;
|
||
if (instSolid == null || instSolid.Faces.Size == 0 || instSolid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
foreach (Face face in instSolid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
//geomObj为几何体
|
||
Solid solid = geomObj as Solid;
|
||
if (solid != null)
|
||
{
|
||
if (solid.Faces.Size == 0 || solid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
foreach (Face face in solid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return faces;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取族实例所有面(无法用于尺寸标注)
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <returns></returns>
|
||
public static List<Face> GetFamilyInstanceFaces(FamilyInstance instance, Options options)
|
||
{
|
||
List<Face> faces = new List<Face>();
|
||
//根据打开的方式得到几何信息
|
||
GeometryElement geometry = instance.get_Geometry(options);
|
||
|
||
foreach (GeometryObject geomObj in geometry)
|
||
{
|
||
//geomObj为几何实例
|
||
GeometryInstance geomInstance = geomObj as GeometryInstance;
|
||
var ins = geomInstance.GetInstanceGeometry();
|
||
if (geomInstance != null)
|
||
{
|
||
//instanceGeometry.GetTransformed();
|
||
//从实例中找到实例的几何体
|
||
foreach (GeometryObject instObj in geomInstance.GetInstanceGeometry())
|
||
{
|
||
//三维的实体
|
||
Solid instSolid = instObj as Solid;
|
||
if (instSolid == null || instSolid.Faces.Size == 0 || instSolid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
foreach (Face face in instSolid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
//geomObj为几何体
|
||
Solid solid = geomObj as Solid;
|
||
if (solid != null)
|
||
{
|
||
if (solid.Faces.Size == 0 || solid.Edges.Size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
foreach (Face face in solid.Faces)
|
||
{
|
||
faces.Add(face);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return faces;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 找到嵌套族的默认面参照(仅针对只有一种嵌套族)
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="familyInstances"></param>
|
||
/// <returns></returns>
|
||
public static List<Face> GetFaceReferences(Document doc, FamilyInstance familyInstance)
|
||
{
|
||
//List<Reference> references = new List<Reference>();
|
||
var instance = familyInstance.GetSubComponentIds()
|
||
.Select(a => doc.GetElement(a))
|
||
.ToList();
|
||
var ops = new Options();
|
||
ops.ComputeReferences = true;//计算参照,为true时才能进行得到参照
|
||
List<Face> faces = GetFaceByElement(instance.FirstOrDefault(), ops);
|
||
//List<Element> listFamilyInstances = new FilteredElementCollector(doc, doc.ActiveView.Id)
|
||
// .OfClass(typeof(FamilyInstance))
|
||
// .Cast<FamilyInstance>()
|
||
// .Where(a => a.SuperComponent == null)
|
||
// .SelectMany(a => a.GetSubComponentIds())
|
||
// .Select(a => doc.GetElement(a))
|
||
// .ToList();
|
||
//foreach (var face in faces)
|
||
//{
|
||
// //face.GetSurface().
|
||
// references.Add(face.Reference);
|
||
//}
|
||
return faces;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取已载入同名族,若无,则载入
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="familyName"></param>
|
||
/// <returns></returns>
|
||
internal static Family GetLoadedFamily(Document doc, string familyName)
|
||
{
|
||
Family family;
|
||
|
||
family = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(Family))
|
||
.Cast<Family>()
|
||
.Where(f => f.Name == Path.GetFileNameWithoutExtension(familyName))
|
||
.FirstOrDefault();
|
||
if (family == null)
|
||
{
|
||
doc.LoadFamily(familyName, new RsFamilyLoadOption(), out family);
|
||
}
|
||
|
||
return family;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取垂直于基准线的最长边
|
||
/// </summary>
|
||
/// <param name="segments"></param>
|
||
/// <param name="baseLine"></param>
|
||
/// <returns></returns>
|
||
public static Line GetLongestSegmentLine(IList<BoundarySegment> segments, Line baseLine)
|
||
{
|
||
Line line = null;
|
||
//var m = doc.GetElement(refer.ElementId);
|
||
foreach (var seg in segments)
|
||
{
|
||
Line tempLine = seg.GetCurve() as Line;
|
||
//判断是否垂直
|
||
double dotp = Math.Abs(tempLine.Direction.DotProduct(baseLine.Direction));
|
||
if (dotp < 0.0001)
|
||
{
|
||
if (line == null || line.Length < tempLine.Length)
|
||
{
|
||
line = tempLine;
|
||
}
|
||
}
|
||
}
|
||
return line;
|
||
}
|
||
}
|
||
|
||
internal class RsFamilyLoadOption : IFamilyLoadOptions
|
||
{
|
||
bool IFamilyLoadOptions.OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
|
||
{
|
||
overwriteParameterValues = false;
|
||
return true;
|
||
}
|
||
|
||
bool IFamilyLoadOptions.OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
|
||
{
|
||
source = FamilySource.Project;
|
||
overwriteParameterValues = true;
|
||
return true;
|
||
}
|
||
};
|
||
} |