Files
RookieStation/RookieStation/Utils/RsRevitUtils.cs
2021-06-24 11:42:33 +08:00

463 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
};
}