Files
RookieStation/RookieStation/Utils/RsRevitUtils.cs
2021-09-18 14:48:46 +08:00

724 lines
28 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;
using static System.Net.WebRequestMethods;
using Autodesk.Revit.UI;
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="doc"></param>
/// <param name="viewScale"></param>
/// <returns></returns>
public static View CreateNewLegend(Document doc, string legendName, int viewScale)
{
IEnumerable<View> legends = doc.QueryByClassAndBuiltInCategory<View>(BuiltInCategory.OST_Views).Cast<Autodesk.Revit.DB.View>().Where(v => v.ViewType == ViewType.Legend);
Autodesk.Revit.DB.View newLegend = null;
if (legends.Count() == 0)
{
TaskDialog.Show("温馨提示", "请先新建图例");
return newLegend;
}
var legendToCopy = legends.FirstOrDefault();
var newLegendId = legendToCopy.Duplicate(ViewDuplicateOption.Duplicate);
newLegend = doc.GetElement(newLegendId) as Autodesk.Revit.DB.View;
for (int i = 0; i < 100; i++)
{
try
{
newLegend.Name = $"{legendName} {i}";
break;
}
catch (Exception)
{
continue;
}
}
newLegend.Scale = viewScale;
return newLegend;
}
/// <summary>
/// 设置图例位置
/// </summary>
/// <param name="doc"></param>
/// <param name="newLegend"></param>
public static void SetLegendLocation(Document doc, View newLegend, XYZ location)
{
var viewport = Viewport.Create(doc, doc.ActiveView.Id, newLegend.Id, XYZ.Zero);
double l = viewport.GetBoxOutline().MaximumPoint.X - viewport.GetBoxOutline().MinimumPoint.X;
double w = viewport.GetBoxOutline().MaximumPoint.Y - viewport.GetBoxOutline().MinimumPoint.Y;
XYZ c = new XYZ(l / 2, w / 2, 0) + location;//边距均为7mm
viewport.SetBoxCenter(c);
var ele = new FilteredElementCollector(doc).OfClass(typeof(ElementType)).WhereElementIsElementType().FirstOrDefault(x => x.Name.Contains("无"));
viewport.ChangeTypeId(ele.Id);//选择视口-无标题
}
/// <summary>
/// 删除定位点重合的族实例
/// </summary>
/// <param name="doc"></param>
/// <param name="cardInstances"></param>
public static void DeleteOverlapFamilyInstance(Autodesk.Revit.DB.Document doc, List<FamilyInstance> cardInstances)
{
List<ElementId> idsToDelete = new List<ElementId>();
foreach (var ins in cardInstances)
{
var lp = RsRevitUtils.GetLocationPointByElement(ins);
foreach (var card in cardInstances)
{
var lpt = RsRevitUtils.GetLocationPointByElement(card);
if (!card.Id.Equals(ins.Id) && lp.IsAlmostEqualTo(lpt))
{
idsToDelete.Add(ins.Id);
idsToDelete.Add(card.Id);
break;
}
}
}
doc.Delete(idsToDelete);
}
/// <summary>
/// 创建表格
/// </summary>
/// <param name="doc"></param>
/// <param name="rowcount"></param>
/// <param name="columncount"></param>
/// <param name="gridwidth"></param>
/// <param name="gridheight"></param>
public static void CreateTable(Document doc, View legend, int rowcount, int columncount, double gridwidth, double gridheight)
{
CurveArray curveArray = new CurveArray();
for (int i = 0; i <= rowcount; i++)//水平网格
{
Curve l = Line.CreateBound(XYZ.Zero, XYZ.BasisX * gridwidth * columncount).CreateOffset(gridheight * i, -XYZ.BasisZ);
curveArray.Append(l);
}
Curve line = Line.CreateBound(XYZ.Zero, XYZ.BasisY * rowcount * gridheight);
curveArray.Append(line);
for (int i = 0; i <= columncount; i++)//垂直网格
{
line = line.CreateOffset(gridwidth, XYZ.BasisZ);
curveArray.Append(line);
}
doc.Create.NewDetailCurveArray(legend, curveArray);
}
/// <summary>
/// 创建表格
/// </summary>
/// <param name="doc"></param>
/// <param name="legend">图例视图</param>
/// <param name="rowcount">行数</param>
/// <param name="columncount">列数</param>
/// <param name="gridheight">单元格高度</param>
/// <param name="gridwidths">各单元格对应的宽度</param>
public static void CreateTable(Document doc, View legend, int rowcount, int columncount, double gridheight, params double[] gridwidths)
{
if (columncount != gridwidths.Count())
{
return;
}
CurveArray curveArray = new CurveArray();
var width = 0.0;
foreach (var w in gridwidths)
{
width += w;
}
for (int i = 0; i <= rowcount; i++)//水平网格
{
Curve c = Line.CreateBound(XYZ.Zero, XYZ.BasisX * width).CreateOffset(gridheight * i, -XYZ.BasisZ);
curveArray.Append(c);
}
Curve line = Line.CreateBound(XYZ.Zero, XYZ.BasisY * rowcount * gridheight);
curveArray.Append(line);
for (int i = 0; i < columncount; i++)//垂直网格
{
line = line.CreateOffset(gridwidths[i], XYZ.BasisZ);
curveArray.Append(line);
}
doc.Create.NewDetailCurveArray(legend, curveArray);
}
/// <summary>
/// 通过名称获取默认的墙类型完整厚度
/// </summary>
/// <param name="wallTypeName">墙类型包含的字符串</param>
/// <returns></returns>
public static WallType GetWallTypeByName(Document doc, string wallTypeName)
{
var walltypelist = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).OfClass(typeof(WallType)).Cast<WallType>();
return walltypelist.FirstOrDefault(t => t.Name.Contains(wallTypeName));
}
/// <summary>
/// 获取元素定位点
/// </summary>
/// <param name="instance">以点定位的实例</param>
/// <returns></returns>
public static XYZ GetLocationPointByElement(Element instance)
{
return instance.Location is LocationPoint lp ? lp.Point : null;
}
public static Curve GetLocationCurveByElement(Element instance)
{
return instance.Location is LocationCurve lc ? lc.Curve : 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();
//旋转角度
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())));
}
offestVector *= offest;
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");
if (lineFamily != null)
{
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;
if (geomInstance == null)
{
continue;
}
//族实例未修改过(连接,剪切,复制,扩展)
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;
FileInfo info = new FileInfo(familyName);
family = new FilteredElementCollector(doc)
.OfClass(typeof(Family))
.Cast<Family>()
.Where(f => f.Name == Path.GetFileNameWithoutExtension(familyName))
.FirstOrDefault();
if (family == null && info.Exists)
{
doc.LoadFamily(familyName, new RsFamilyLoadOption(), out family);
}
return family;
}
internal static FamilySymbol GetAndActiveDefaultFamilySymbol(Document doc, string file)
{
Family family = RsRevitUtils.GetLoadedFamily(doc, file);
FamilySymbol symbol = null;
if (family != null)
{
ElementId symbolId = family.GetFamilySymbolIds().FirstOrDefault();
symbol = doc.GetElement(symbolId) as FamilySymbol;
if (!symbol.IsActive)
{
symbol.Activate();
}
}
return symbol;
}
/// <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;
}
public static Face GetPlaceFaceOfWall(Wall wall, XYZ normal)
{
Face face = null;
Options geomOptions = new Options();
geomOptions.ComputeReferences = true;
GeometryElement wallGeom = wall.get_Geometry(geomOptions);
foreach (GeometryObject geomObj in wallGeom)
{
Solid geomSolid = geomObj as Solid;
if (null != geomSolid)
{
foreach (Face geomFace in geomSolid.Faces)
{
if (geomFace.ComputeNormal(geomFace.Reference.UVPoint).IsAlmostEqualTo(normal))
{
face = geomFace;
}
break;
}
break;
}
}
return face;
}
/// <summary>
/// 获取元素侧面
/// </summary>
/// <param name="elem"></param>
/// <returns></returns>
public static List<Face> GetSideFacesByElement(Element elem)
{
Options opt = new Options();
opt.ComputeReferences = true;
opt.DetailLevel = ViewDetailLevel.Fine;
GeometryElement ge = elem.get_Geometry(opt);
List<Face> lstpf = new List<Face>();
foreach (GeometryObject obj in ge)
{
Solid solid = obj as Solid;
if (solid != null)
{
foreach (Face face in solid.Faces)
{
PlanarFace pf = face as PlanarFace;
if (pf != null)
{
//点乘即面的法向与Z轴始终垂直
var dotp = pf.FaceNormal.DotProduct(XYZ.BasisZ);
if (dotp < 1.0e-09 && dotp > -1.0e-09)//近似为0
{
lstpf.Add(pf);
}
//if (pf.FaceNormal.CrossProduct(wall.Orientation).IsZeroLength())
//{
// lstpf.Add(pf);
//}
}
var cy = face as CylindricalFace;
if (cy != null)
{
lstpf.Add(cy);
}
}
return lstpf;
}
}
return lstpf;
}
/// <summary>
/// 获取元素默认底面(单个)
/// </summary>
/// <param name="elem"></param>
/// <returns></returns>
public static PlanarFace GetBottomFaceByElement(Element elem)
{
Options opt = new Options();
opt.ComputeReferences = true;
opt.DetailLevel = ViewDetailLevel.Fine;
GeometryElement ge = elem.get_Geometry(opt);
PlanarFace pf = null;
foreach (GeometryObject obj in ge)
{
Solid solid = obj as Solid;
if (solid != null)
{
foreach (Face face in solid.Faces)
{
PlanarFace temppf = face as PlanarFace;
if (temppf != null)
{
if (temppf.FaceNormal.IsAlmostEqualTo(-XYZ.BasisZ))
{
pf = temppf;
break;
}
//if (pf.FaceNormal.CrossProduct(wall.Orientation).IsZeroLength())
//{
// lstpf.Add(pf);
//}
}
}
return pf;
}
}
return null;
}
}
}