Client/Desktop/KMBIM3.0/23.11.03/Utils/Util.cs

3878 lines
133 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
namespace KDCS.Utils
{
public static class Util
{
// predefined constants for common angles
public const double kPi = 3.14159265358979323846;
// TBD: have to use Revit's version of Pi for Ellipse else it will fail!
public const double kRevitPi = 3.14159265358979;
public const double kHalfPi = 3.14159265358979323846 / 2.0;
public const double kTwoPi = 3.14159265358979323846 * 2.0;
public const double kRad0 = 0.0;
public const double kRad45 = 3.14159265358979323846 / 4.0;
public const double kRad90 = 3.14159265358979323846 / 2.0;
public const double kRad135 = (3.14159265358979323846 * 3.0) / 4.0;
public const double kRad180 = 3.14159265358979323846;
public const double kRad270 = 3.14159265358979323846 * 1.5;
public const double kRad360 = 3.14159265358979323846 * 2.0;
public const double _eps = 1.0e-9;
public static bool fuzzyEqual(double a, double b)
{
return Math.Abs(a - b) < _eps;
}
public static bool GT_ET(double a, double b)
{
if (!(a < b))
{
return fuzzyEqual(a, b);
}
return true;
}
public static bool LT_ET(double a, double b)
{
if (!(a > b))
{
return fuzzyEqual(a, b);
}
return true;
}
public static bool LT(double a, double b)
{
if (a < b)
{
bool bEqual = !fuzzyEqual(a, b);
return bEqual;
}
return false;
}
public static bool GT(double a, double b)
{
if (a > b)
{
bool bEqual = !fuzzyEqual(a, b);
return bEqual;
}
return false;
}
public static string GetFileName(string subFolder, string fileName, bool deleteIfExist)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\" + "DCS.CO.KR" + @"\" + "KMBIM";
if (!Directory.Exists(path))
{
string[] strArray = path.Split(new char[] { '\\' });
string str2 = "";
str2 = str2 + strArray[0];
for (int i = 1; i <= (strArray.Length - 1); i++)
{
str2 = str2 + @"\" + strArray[i];
if (!Directory.Exists(str2))
{
Directory.CreateDirectory(str2);
}
}
}
string fullpath = string.Empty;
if (string.IsNullOrEmpty(subFolder) == false) fullpath = path + @"\" + subFolder + @"\" + fileName;
else fullpath = path + @"\" + fileName;
if (File.Exists(fullpath) && deleteIfExist)
{
File.Delete(fullpath);
}
return fullpath;
}
public static KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType GetKMBIMMEPCurveType(Autodesk.Revit.DB.Connector A_0)
{
if (A_0.Shape == Autodesk.Revit.DB.ConnectorProfileType.Rectangular)
{
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.RectDuct;
}
if (A_0.Shape == Autodesk.Revit.DB.ConnectorProfileType.Round)
{
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.RoundDuct;
}
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.OvalDuct;
}
public static T DeepClone<T>(this T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
static ElementId GetNamedElementId(FilteredElementCollector a, string name)
{
IList<Element> elements = a
.Where(x => x.Name.Equals(name))
.Cast<Element>()
.ToList();
return 0 < elements.Count ? elements[0].Id : ElementId.InvalidElementId;
}
public static ElementId FindLevelId(Document doc, string name)
{
FilteredElementCollector a = new FilteredElementCollector(doc).OfClass(typeof(Level));
return GetNamedElementId(a, name);
}
public static ElementId FindCableTrayTypeId(Document doc, string name)
{
FilteredElementCollector a = new FilteredElementCollector(doc).OfClass(typeof(CableTrayType));
return GetNamedElementId(a, name);
}
public static XYZ makeXYZ(XYZ pt)
{
return new XYZ(pt.X, pt.Y, pt.Z);
}
public static Line CreateBound(Document A_0, Autodesk.Revit.DB.XYZ A_1, Autodesk.Revit.DB.XYZ A_2)
{
return Line.CreateBound(A_1, A_2);
}
/// <summary>
/// 주어진 Z축으로 나머지 X,Y축을 구한다.
/// </summary>
/// <param name="axisZ"></param>
/// <param name="axisX"></param>
/// <param name="axisY"></param>
public static void AxesXY(XYZ axisZ, ref XYZ axisX, ref XYZ axisY)
{
Plane plane = Plane.CreateByNormalAndOrigin(axisZ, Autodesk.Revit.DB.XYZ.Zero);
Arc arc = Arc.Create(plane, 1.0, 0, 6.28);
axisX = arc.XDirection;
axisY = arc.YDirection;
// Y축 방향 확인
if (axisZ.Z < 0.9)
{
if (axisY.Z < 0)
{
axisY = axisY.Negate();
axisX = axisY.CrossProduct(axisZ);
}
}
}
public static ConnectorProfileType GetShape(Duct duct)
{
ConnectorProfileType ductShape
= ConnectorProfileType.Invalid;
foreach (Connector c in duct.ConnectorManager.Connectors)
{
if (c.ConnectorType == ConnectorType.End)
{
ductShape = c.Shape;
break;
}
}
return ductShape;
}
public static void JoinGeometry2(this Document doc, Element firstElement, Element secondElement)
{
List<Type> ls = doc.GetType().Assembly
.GetTypes().Where(a => a.IsClass && a
.Name == "JoinGeometryUtils").ToList();
object[] parametros = new object[] { doc,
firstElement, secondElement };
Type[] tipos = parametros.Select(a => a
.GetType()).ToArray();
if (ls.Count > 0)
{
Type t = ls[0];
MethodInfo met = t
.GetMethod("JoinGeometry", tipos);
met.Invoke(null, parametros);
}
}
public static bool IsJoined2(this Document doc, Element firstElement, Element secondElement)
{
bool value = false;
List<Type> ls = doc.GetType().Assembly
.GetTypes().Where(a => a.IsClass && a
.Name == "JoinGeometryUtils").ToList();
object[] parametros = new object[] { doc,
firstElement, secondElement };
Type[] tipos = parametros.Select(a => a
.GetType()).ToArray();
if (ls.Count > 0)
{
Type t = ls[0];
MethodInfo met = t
.GetMethod("AreElementsJoined", tipos);
value = (bool)met.Invoke(null,
parametros);
}
return value;
}
public static void Delete2(this Document doc, Element ele)
{
object obj = doc;
MethodInfo met = obj.GetType().GetMethod("Delete", new Type[] { typeof(Element) });
if (met != null)
{
met.Invoke(obj, new object[] { ele });
}
else
{
met = obj.GetType().GetMethod("Delete", new Type[] { typeof(ElementId) });
met.Invoke(obj, new object[] { ele.Id });
}
}
public static void JoinGeometry(this Document doc, Element firstElement, Element secondElement)
{
List<Type> ls = doc.GetType().Assembly
.GetTypes().Where(a => a.IsClass && a
.Name == "JoinGeometryUtils").ToList();
object[] parametros = new object[] { doc,
firstElement, secondElement };
Type[] tipos = parametros.Select(a => a
.GetType()).ToArray();
if (ls.Count > 0)
{
Type t = ls[0];
MethodInfo met = t
.GetMethod("JoinGeometry", tipos);
met.Invoke(null, parametros);
}
}
public static bool IsJoined(this Document doc, Element firstElement, Element secondElement)
{
bool value = false;
List<Type> ls = doc.GetType().Assembly
.GetTypes().Where(a => a.IsClass && a
.Name == "JoinGeometryUtils").ToList();
object[] parametros = new object[] { doc,
firstElement, secondElement };
Type[] tipos = parametros.Select(a => a
.GetType()).ToArray();
if (ls.Count > 0)
{
Type t = ls[0];
MethodInfo met = t
.GetMethod("AreElementsJoined", tipos);
value = (bool)met.Invoke(null,
parametros);
}
return value;
}
public static void ShortenCurve(Element elm)
{
LocationCurve lineLoc1 = null;
if (elm.GetType() == typeof(Duct))
{
Duct duct = elm as Duct;
lineLoc1 = duct.Location as LocationCurve;
}
else if (elm.GetType() == typeof(Pipe))
{
Pipe pipe = elm as Pipe;
lineLoc1 = pipe.Location as LocationCurve;
}
else if (elm.GetType() == typeof(Conduit))
{
Conduit conduit = elm as Conduit;
lineLoc1 = conduit.Location as LocationCurve;
}
else if (elm.GetType() == typeof(CableTray))
{
CableTray cableTray = elm as CableTray;
lineLoc1 = cableTray.Location as LocationCurve;
}
Line c1 = lineLoc1.Curve as Line;
XYZ p1 = c1.GetEndPoint(0);
XYZ p2 = c1.GetEndPoint(1);
XYZ v1 = p2 - p1; // 벡터
XYZ mp = p1 + v1 * 0.5;
XYZ v2 = v1.Normalize();
p2 = mp + v2 * 0.03280839895013123; // 1cm = 0.03280839895013123 ft
p1 = mp - v2 * 0.03280839895013123; // 1cm = 0.03280839895013123 ft
lineLoc1.Curve = Line.CreateBound(p1, p2);
}
/// <summary>
/// Return signed distance from plane to a given point.
/// </summary>
public static double SignedDistanceTo(Plane plane, XYZ p)
{
XYZ v = p - plane.Origin;
return plane.Normal.DotProduct(v);
}
public static XYZ Project(Plane plane, XYZ p)
{
double d = SignedDistanceTo(plane, p);
XYZ q = p - d * plane.Normal;
return new XYZ(q.X, q.Y, q.Z);
}
//배관 선형 직교점 구하기
public static XYZ PipeProject(Pipe pipe, XYZ dirPt)
{
Line line = (pipe.Location as LocationCurve).Curve as Line;
IntersectionResult interRes = line.Project(dirPt);
if (interRes == null) return null;
return interRes.XYZPoint;
}
/// <summary>
/// 두 점(p,q) 사이의 가운데 점을 넘겨준다.
/// </summary>
/// <param name="p"></param>
/// <param name="q"></param>
/// <returns></returns>
public static XYZ Midpoint(XYZ p, XYZ q)
{
return p + 0.5 * (q - p);
}
public static double DTR(double deg)
{
return deg * Util.kPi / 180d;
}
public static double RTD(double rad)
{
return rad * 180d / Util.kPi;
}
public static Face GetFarthestFace(List<Face> lst_face, XYZ p)
{
Face face = null;
double max_distance = double.MinValue;
double d = 0d;
foreach (Face f in lst_face)
{
PlanarFace pf = f as PlanarFace;
var itr = pf.Project(p);
if (itr != null)
{
d = itr.XYZPoint.DistanceTo(p);
}
if (d > max_distance)
{
face = f;
max_distance = d;
}
}
return face;
}
public static Face GetNearestFace(List<Face> lst_face, XYZ p)
{
Face face = null;
double min_distance = double.MaxValue;
double d = 0d;
foreach (Face f in lst_face)
{
PlanarFace pf = f as PlanarFace;
if (pf == null) continue;
var itr = pf.Project(p);
if (itr != null)
{
d = itr.XYZPoint.DistanceTo(p);
if (d < min_distance)
{
face = f;
min_distance = d;
}
}
}
return face;
}
#region GetFarthestFace
/// <summary>
/// 주어진 점에서 법선벡터 방향에 위치한 벽면 중 가강 멀리 떨어져 있는 벽의 면을 넘겨준다.
/// </summary>
public static Face GetFarthestFace(Element e, XYZ p, XYZ normal, Options opt)
{
Face face = null;
double max_distance = double.MinValue;
GeometryElement geo = e.get_Geometry(opt);
foreach (GeometryObject obj in geo)
{
Solid solid = obj as Solid;
if (solid != null)
{
FaceArray fa = solid.Faces;
foreach (Face f in fa)
{
PlanarFace pf = f as PlanarFace;
if (pf == null) continue;
//Debug.Assert(null != pf, "expected planar wall faces");
if (null != pf && pf.FaceNormal.IsAlmostEqualTo(normal))
{
XYZ v = p - pf.Origin;
double d = v.DotProduct(-pf.FaceNormal);
if (d > max_distance)
{
face = f;
max_distance = d;
}
}
}
}
}
return face;
}
#endregion // GetFarthestFace
public static bool IsParallel(XYZ p, XYZ q)
{
return IsZero(p.CrossProduct(q).GetLength()); // IsZeroLength();
}
public static bool IsCollinear(Line a, Line b)
{
XYZ v = a.Direction;
XYZ w = b.Origin - a.Origin;
return IsParallel(v, b.Direction)
&& IsParallel(v, w);
}
public static bool IsZero(double a, double tolerance = _eps)
{
return Math.Abs(a) < tolerance;
}
public static bool IsEqual(
double a,
double b,
double tolerance = _eps)
{
return IsZero(b - a, tolerance);
}
public static int Compare(
double a,
double b,
double tolerance = _eps)
{
return IsEqual(a, b, tolerance)
? 0
: (a < b ? -1 : 1);
}
public static bool IsHorizontal(XYZ v)
{
return IsZero(v.Z);
}
public static bool IsVertical(XYZ v)
{
return IsZero(v.X) && IsZero(v.Y);
}
public static bool IsVertical(XYZ v, double tolerance)
{
return IsZero(v.X, tolerance)
&& IsZero(v.Y, tolerance);
}
public static bool IsHorizontal(Edge e)
{
XYZ p = e.Evaluate(0);
XYZ q = e.Evaluate(1);
return IsHorizontal(q - p);
}
public static bool IsHorizontal(PlanarFace f)
{
return IsVertical(f.FaceNormal);
}
public static bool IsVertical(PlanarFace f)
{
return IsHorizontal(f.FaceNormal);
}
public static IEnumerable<Face> GetFaces(Element e)
{
Options opt = new Options();
opt.ComputeReferences = true;
IEnumerable<Face> faces = e
.get_Geometry(opt)
.OfType<Solid>()
.First()
.Faces
.OfType<Face>();
return faces;
}
/// <summary>
/// 파이프의 시작점과 끝점을 구한다.
/// </summary>
/// <param name="pipe"></param>
/// <param name="startPoint"></param>
/// <param name="endPoint"></param>
/// <returns></returns>
public static bool GetStartEndPoint(Autodesk.Revit.DB.Plumbing.Pipe pipe, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (pipe == null) return bRC;
LocationCurve lc = pipe.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
/// <summary>
/// 플렉시블 파이프의 시작점과 끝점을 구한다.
/// </summary>
/// <param name="flexPipe"></param>
/// <param name="startPoint"></param>
/// <param name="endPoint"></param>
/// <returns></returns>
public static bool GetStartEndPoint(Autodesk.Revit.DB.Plumbing.FlexPipe flexPipe, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (flexPipe == null) return bRC;
LocationCurve lc = flexPipe.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
/// <summary>
/// 플렉시블 덕트의 시작점과 끝점을 구한다.
/// </summary>
/// <param name="flexPipe"></param>
/// <param name="startPoint"></param>
/// <param name="endPoint"></param>
/// <returns></returns>
public static bool GetStartEndPoint(FlexDuct flexDuct, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (flexDuct == null) return bRC;
LocationCurve lc = flexDuct.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
public static List<Autodesk.Revit.DB.XYZ> PerpendicularDirs(Autodesk.Revit.DB.XYZ dir, int count)
{
List<Autodesk.Revit.DB.XYZ> dirs = new List<Autodesk.Revit.DB.XYZ>();
Plane plane = Plane.CreateByNormalAndOrigin(dir, Autodesk.Revit.DB.XYZ.Zero);
Arc arc = Arc.Create(plane, 1.0, 0, 6.28);
double delta = 1.0 / (double)count;
for (int i = 0; i < count; i++)
{
Autodesk.Revit.DB.XYZ pt = arc.Evaluate(delta * i, true);
dirs.Add(pt);
}
return dirs;
}
public static bool GetStartEndPoint(Autodesk.Revit.DB.Mechanical.Duct duct, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (duct == null) return bRC;
LocationCurve lc = duct.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
public static bool GetStartEndPoint(Autodesk.Revit.DB.Electrical.Conduit conduit, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (conduit == null) return bRC;
LocationCurve lc = conduit.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
public static bool GetStartEndPoint(Autodesk.Revit.DB.Electrical.CableTray cableTray, ref XYZ startPoint, ref XYZ endPoint)
{
bool bRC = false;
if (cableTray == null) return bRC;
LocationCurve lc = cableTray.Location as LocationCurve;
if (lc != null)
{
startPoint = lc.Curve.GetEndPoint(0);
endPoint = lc.Curve.GetEndPoint(1);
bRC = true;
}
return bRC;
}
//파이프 시작 끝 커넥터 구하기
public static bool GetStartEndConnector(Autodesk.Revit.DB.Plumbing.Pipe pipe, ref Connector startConnector, ref Connector endConnector)
{
bool bRC = false;
if (pipe == null) return bRC;
XYZ sp = null, ep = null;
//파이프 시작 끝 점 구하기
GetStartEndPoint(pipe, ref sp, ref ep);
//파이프 커넥터 구하기
List<Connector> PipeCons = GetElementConnectors(pipe);
foreach (Connector con in PipeCons)
{
if (sp.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
startConnector = con;
else if (ep.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
endConnector = con;
}
if (startConnector != null && endConnector != null) bRC = true;
return bRC;
}
//플렉시블 파이프 시작 끝 커넥터 구하기
public static bool GetStartEndConnector(Autodesk.Revit.DB.Plumbing.FlexPipe flexPipe, ref Connector startConnector, ref Connector endConnector)
{
bool bRC = false;
if (flexPipe == null) return bRC;
XYZ sp = null, ep = null;
//파이프 시작 끝 점 구하기
GetStartEndPoint(flexPipe, ref sp, ref ep);
//파이프 커넥터 구하기
List<Connector> PipeCons = GetElementConnectors(flexPipe);
foreach (Connector con in PipeCons)
{
if (sp.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
startConnector = con;
else if (ep.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
endConnector = con;
}
if (startConnector != null && endConnector != null) bRC = true;
return bRC;
}
//덕트 시작 끝 커넥터 구하기
public static bool GetStartEndConnector(Duct duct, ref Connector startConnector, ref Connector endConnector)
{
bool bRC = false;
if (duct == null) return bRC;
XYZ sp = null, ep = null;
//덕트 시작 끝 점 구하기
GetStartEndPoint(duct, ref sp, ref ep);
//덕트 커넥터 구하기
List<Connector> DuctCons = GetElementConnectors(duct);
foreach (Connector con in DuctCons)
{
if (sp.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
startConnector = con;
else if (ep.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01)))
endConnector = con;
}
if (startConnector != null && endConnector != null) bRC = true;
return bRC;
}
public static SketchPlane NewSketchPlane(Document doc, XYZ norm, XYZ p)
{
Plane plane = plane = Plane.CreateByNormalAndOrigin(norm, p);
return SketchPlane.Create(doc, plane);
}
public static SketchPlane NewSketchPlaneByLine(Document doc, Line line)
{
XYZ p = line.GetEndPoint(0);
XYZ q = line.GetEndPoint(1);
XYZ v1 = p - q;
XYZ norm = null;
if (p.X == q.X && p.Y == q.Y) norm = XYZ.BasisX;
else if (p.X == q.X) norm = XYZ.BasisX;
else if (p.Y == q.Y) norm = XYZ.BasisY;
else norm = new XYZ(v1.Y, -v1.X, 0.0);
norm = norm.Normalize();
if (norm.IsZeroLength()) return null;
return NewSketchPlane(doc, norm, p);
}
/// <summary>
/// Return the given element's connector manager,
/// using either the family instance MEPModel or
/// directly from the MEPCurve connector manager
/// for ducts and pipes.
/// </summary>
public static ConnectorManager GetConnectorManager(Element e)
{
ConnectorManager con_man = null;
MEPCurve mc = e as MEPCurve;
FamilyInstance fi = e as FamilyInstance;
if (null == mc && null == fi)
{
return null;
}
if (fi != null)
{
con_man = fi.MEPModel != null ? fi.MEPModel.ConnectorManager : null;
}
else if (mc != null)
{
con_man = mc.ConnectorManager;
}
return con_man;
}
public static void Pyosi(Document doc, XYZ pt, bool bTransMode, Color clr = null)
{
if (pt == null) return;
if (clr == null) clr = new Color(255, 0, 0);
XYZ pt1 = new XYZ(pt.X - 0.328084, pt.Y + 0.328084, pt.Z);
XYZ pt2 = new XYZ(pt.X + Unit.MMToFeet(100), pt.Y + Unit.MMToFeet(100), pt.Z);
XYZ pt3 = new XYZ(pt.X + 0.328084, pt.Y - 0.328084, pt.Z);
XYZ pt4 = new XYZ(pt.X - 0.328084, pt.Y - 0.328084, pt.Z);
if (bTransMode == false)
{
CreateModelLine(doc, pt2, pt4, clr);
CreateModelLine(doc, pt1, pt3, clr);
}
else
{
using (Transaction transaction = new Transaction(doc))
{
transaction.Start("Start Pyosi");
CreateModelLine(doc, pt2, pt4, clr);
CreateModelLine(doc, pt1, pt3, clr);
transaction.Commit();
}
}
}
public static ModelCurve CreateModelLine(Document doc, Autodesk.Revit.DB.XYZ p, Autodesk.Revit.DB.XYZ q, Color clr = null)
{
if (clr == null) clr = new Color(255, 0, 0);
ModelCurve mCurve = null;
if (p.IsAlmostEqualTo(q))
{
throw new System.ArgumentException("Expected two different points.");
}
Line line = Line.CreateBound(p, q);
if (null == line)
{
throw new Exception("Geometry line creation failed.");
}
SketchPlane skpln = NewSketchPlaneByLine(doc, line);
if (skpln != null)
{
mCurve = doc.Create.NewModelCurve(line, skpln);
if (mCurve != null)
{
GraphicsStyle gs = mCurve.LineStyle as GraphicsStyle;
gs.GraphicsStyleCategory.LineColor = clr;
}
}
return mCurve;
}
internal static void Project(Plane plane, XYZ ptMidSection, ref XYZ ptOnDuct)
{
throw new NotImplementedException();
}
/// 정의 된 선을 통과하는 스케치 평면을 만듭니다.
/// 정의 된 줄은 BoundingBox 프로필 중 하나 여야합니다
public static SketchPlane NewSketchPlanePassLine(Line aline, UIApplication app)
{
Autodesk.Revit.DB.XYZ norm;
if (aline.GetEndPoint(0).X == aline.GetEndPoint(1).X)
{
norm = new XYZ(1, 0, 0);
}
else if (aline.GetEndPoint(0).Y == aline.GetEndPoint(1).Y)
{
norm = new XYZ(0, 1, 0);
}
else
{
norm = new XYZ(0, 0, 1);
}
//끝점
XYZ pt = aline.GetEndPoint(0);
// app.Application.Create.NewPlane-> Plane.CreateByNormalAndOrigin 변경
Plane plane = Plane.CreateByNormalAndOrigin(norm, pt);
SketchPlane sketchPlane = SketchPlane.Create(app.ActiveUIDocument.Document, plane);
return sketchPlane;
}
public static ModelCurve NewModelLine(UIApplication app, Plane plane, XYZ startPt, XYZ endPt)
{
try
{
Autodesk.Revit.Creation.Application creApp = app.Application.Create;
Line line = Line.CreateBound(startPt, endPt);
SketchPlane sketchPlane = NewSketchPlanePassLine(line, app);
return app.ActiveUIDocument.Document.Create.NewModelCurve(line, sketchPlane);
}
catch (Exception)
{
return null;
}
}
//Element 지우기
public static void DeleteElement(Autodesk.Revit.DB.Document doc, List<Element> lstElement)
{
using (Transaction transaction = new Transaction(doc))
{
transaction.Start("Start");
foreach (Element element in lstElement)
{
ElementId elementId = element.Id;
doc.Delete(elementId);
}
transaction.Commit();
}
}
//ElementId 지우기
public static void DeleteElement(Autodesk.Revit.DB.Document doc, List<ElementId> lstElementId)
{
using (Transaction transaction = new Transaction(doc))
{
transaction.Start("Start");
foreach (ElementId elementId in lstElementId)
{
doc.Delete(elementId);
}
transaction.Commit();
}
}
public static bool PickPoint(UIDocument uidoc, string msg, ref XYZ pt)
{
bool bRC = false;
try
{
pt = uidoc.Selection.PickPoint(msg);
bRC = true;
}
catch (OperationCanceledException)
{
}
catch (Exception)
{
}
return bRC;
}
private static UIView GetActiveUiView(UIDocument uidoc)
{
Document doc = uidoc.Document;
Autodesk.Revit.DB.View view = doc.ActiveView;
IList<UIView> uiviews = uidoc.GetOpenUIViews();
UIView uiview = null;
foreach (UIView uv in uiviews)
{
if (uv.ViewId.Equals(view.Id))
{
uiview = uv;
break;
}
}
return uiview;
}
public static XYZ Polar(XYZ posPt, XYZ angSpt, XYZ angEpt, double dist)
{
XYZ vec = (angEpt - angSpt).Normalize();
XYZ resPt = posPt + vec * dist;
return resPt;
}
public static XYZ Polar(XYZ posPt, XYZ vec, double dist)
{
XYZ Nvec = vec.Normalize();
XYZ resPt = posPt + Nvec * dist;
return resPt;
}
public static XYZ RotateVector(XYZ AngSpt, XYZ AngEpt, double rad)
{
XYZ vecPt;
vecPt = (AngEpt - AngSpt).Normalize();
var tranRot = Transform.CreateRotation(XYZ.BasisZ, rad);
vecPt = tranRot.OfVector(vecPt);
return vecPt;
}
public static XYZ RotateVector(XYZ vec, double rad)
{
XYZ vecPt;
vecPt = vec;
var tranRot = Transform.CreateRotation(XYZ.BasisZ, rad);
vecPt = tranRot.OfVector(vecPt);
return vecPt;
}
public static XYZ RotateVectorY(XYZ vec, double rad)
{
XYZ vecPt;
vecPt = vec;
var tranRot = Transform.CreateRotation(XYZ.BasisY, rad);
vecPt = tranRot.OfVector(vecPt);
return vecPt;
}
public static XYZ RotateVectorX(XYZ vec, double rad)
{
XYZ vecPt;
vecPt = vec;
var tranRot = Transform.CreateRotation(XYZ.BasisX, rad);
vecPt = tranRot.OfVector(vecPt);
return vecPt;
}
//점에서 선형까지 가장 가까운점 찾기.
public static XYZ GetPointOnLine(Curve line, XYZ pt)
{
XYZ xyzPt = null;
IntersectionResult res = line.Project(pt);
if ((res != null) && (res.XYZPoint != null))
{
xyzPt = res.XYZPoint;
}
return xyzPt;
}
/// <summary>
/// The status of line-plane intersection
/// </summary>
public enum Plane_Line
{
/// <summary>
/// Line is completely inside the plane
/// </summary>
Subset,
/// <summary>
/// Line is parallel to the plane
/// </summary>
Disjoint,
/// <summary>
/// Line is intersecting with the plane
/// </summary>
Intersecting
}
/// <summary>
/// Compute Plane-Line intersection
/// </summary>
/// <param name="p">This plane</param>
/// <param name="l">Line to intersect with</param>
/// <param name="tolerance">Tolerance</param>
/// <param name="intersectionPoint">The intersection point, Null if it does not exist</param>
/// <param name="parameter">The parameter of the intersection point on the line</param>
/// <returns></returns>
public static Plane_Line Intersect(this Plane p, Line l, double tolerance,
out XYZ intersectionPoint, out double parameter)
{
//compute the dot prodcut and signed distance
double denominator = l.Direction.DotProduct(p.Normal);
double numerator = (p.Origin - l.Origin).DotProduct(p.Normal);
//check if the dot product is almost zero
if (Math.Abs(denominator) < tolerance)
{
// line is parallel to plane (could be inside or outside the plane)
if (Math.Abs(numerator) < tolerance)
{
//line is inside the plane
intersectionPoint = null;
parameter = double.NaN;
return Plane_Line.Subset;
}
else
{
// line is outside the plane
intersectionPoint = null;
parameter = double.NaN;
return Plane_Line.Disjoint;
}
}
else
{
// line is intersecting wih plane
// compute the line paramemer
parameter = numerator / denominator;
intersectionPoint = l.Origin + parameter * l.Direction;
return Plane_Line.Intersecting;
}
}
public static List<Face> GetFacesAll(UIDocument uiDocument, Element element)
{
List<Face> list = new List<Face>();
Options options = uiDocument.Document.Application.Create.NewGeometryOptions();
//Pipe pipe = element as Pipe;
options.View = uiDocument.Document.ActiveView;
options.ComputeReferences = true;
GeometryElement element2 = element.get_Geometry(options);
IEnumerator<GeometryObject> Enum = element2.GetEnumerator();
//GeometryObjectArray gObjects = null;
List<GeometryObject> gObjects = new List<GeometryObject>();
while (Enum.MoveNext())
{
//gObjects.Append(Enum.Current);
gObjects.Add(Enum.Current);
}
// options.DetailLevel = DetailLevels.Fine;
if ((element2 != null) && (gObjects != null))
{
//GeometryObjectArrayIterator iterator = gObjects..ForwardIterator();
for (int i = 0; i < gObjects.Count; i++)
{
if (gObjects[i] is Solid)
{
Solid current = (Solid)gObjects.ElementAt(i);
if (current.Faces != null)
{
FaceArrayIterator iterator = current.Faces.ForwardIterator();
while (iterator.MoveNext())
{
if (iterator.Current is Face)
{
Face item = iterator.Current as Face;
list.Add(item);
}
}//while end
}
}
}
}
return list;
}
public static List<Face> GetInstanceFacesAll(UIDocument uiDocument, Element element)
{
List<Face> list = new List<Face>();
Options options = uiDocument.Document.Application.Create.NewGeometryOptions();
//Pipe pipe = element as Pipe;
options.View = uiDocument.Document.ActiveView;
options.ComputeReferences = true;
FamilyInstance family = element as FamilyInstance;
Transform tr = family.GetTransform();
GeometryElement geo = family.Symbol.get_Geometry(options);
GeometryElement trgeo = geo.GetTransformed(tr);
foreach (var Geo in trgeo)
{
//if (!(Geo is GeometryInstance)) continue;
//GeometryElement gSymbol = (Geo as GeometryInstance).GetSymbolGeometry();
Solid solid = Geo as Solid;
if (solid != null)
{
foreach (Face face in solid.Faces)
{
list.Add(face);
var edges = face.GetEdgesAsCurveLoops();
foreach (var edge in edges)
{
IEnumerator<Curve> curLst = edge.GetEnumerator();
while (curLst.MoveNext())
{
Pyosi(uiDocument.Document, curLst.Current.GetEndPoint(0), true);
}
}
}
}
}
return list;
}
public static XYZ GetFaceNormal(Face face)
{
XYZ normal = null;
PlanarFace pf = face as PlanarFace;
if (pf != null)
{
normal = pf.FaceNormal;
}
return normal;
}
//정렬 된 3 중항의 방향을 찾기
// 0 --> p, q , r이 동일 선상에 있음.
// 1 --> 오른쪽 > 0
// -1 --> 왼쪽 < 0
public static int orientation(XYZ sp, XYZ ep, XYZ tp)
{
XYZ p = sp;
XYZ q = ep;
XYZ r = tp;
double val = (q.Y - p.Y) * (r.X - q.X) - (q.X - p.X) * (r.Y - q.Y);
if (Math.Abs(val) < 0.001) return 0;
return (val > 0) ? 1 : -1;
}
//tp점이 두개의 기준점으로부터 오른쪽인가
public static bool isRightPoint(XYZ tp, XYZ bsp, XYZ bep)
{
bool bRc = false;
int nDir = orientation(bsp, bep, tp);
if (nDir > 0) bRc = true;
return bRc;
}
//객체의 커넥터 구하기.(파이프,덕트,패밀리)
public static List<Connector> GetElementConnectors(Element elem)
{
List<Connector> ConLst = new List<Connector>();
ConnectorSet connectorSet = null;
if (elem is Pipe)
connectorSet = (elem as Pipe).ConnectorManager.Connectors;
else if (elem is FlexPipe)
connectorSet = (elem as FlexPipe).ConnectorManager.Connectors;
else if (elem is Duct)
connectorSet = (elem as Duct).ConnectorManager.Connectors;
else if (elem is FlexDuct)
connectorSet = (elem as FlexDuct).ConnectorManager.Connectors;
else if (elem is FamilyInstance)
connectorSet = (elem as FamilyInstance).MEPModel.ConnectorManager.Connectors;
else if (elem is CableTray)
connectorSet = (elem as CableTray).ConnectorManager.Connectors;
else if (elem is Conduit)
connectorSet = (elem as Conduit).ConnectorManager.Connectors;
if (connectorSet == null) return null;
foreach (Connector con in connectorSet)
{
ConLst.Add(con);
}
return ConLst;
}
/// <summary>
/// 패밀리와 기준 배관으로 분기 커넥터 구하기
/// </summary>
/// <param name="family"></param>T 또는 cross
/// <param name="DirPipe"></param>기준 파이프
/// <returns></returns>
public static List<Connector> GetBranchConnector(FamilyInstance family, Pipe DirPipe)
{
List<Connector> branchConLst = new List<Connector>();
//기준 파이프 시작-끝,끝-시작 방향
Line PipeLine = (DirPipe.Location as LocationCurve).Curve as Line;
XYZ Dir = PipeLine.Direction;
XYZ ReDir = PipeLine.Direction.Negate();
//패밀리 삽입점
XYZ famInsertPt = (family.Location as LocationPoint).Point;
List<Connector> FamConLst = GetElementConnectors(family);
foreach(Connector con in FamConLst)
{
XYZ vec = (con.Origin - famInsertPt).Normalize();
//(삽입점-커넥터)벡터가 (시작-끝)벡터 또는 (끝-시작)벡터와 같으면 넘어감.
if (vec.IsAlmostEqualTo(Dir) || vec.IsAlmostEqualTo(ReDir))
continue;
branchConLst.Add(con);
}
return branchConLst;
}
/// <summary>
/// Tee Cross 가지 커넥터 구하기
/// </summary>
/// <param name="family"></param>
/// <returns></returns>
public static List<Connector> GetBranchConnector(FamilyInstance family)
{
List<Connector> branchConLst = new List<Connector>();
List<Connector> conLst = GetElementConnectors(family);
foreach (Connector con in conLst)
{
if (con.Angle == 0) continue;
branchConLst.Add(con);
}
return branchConLst;
}
/// <summary>
/// 부속류 티 크로스 등 기준커넥터 방향의 반대 커넥터 구하기.
/// </summary>
/// <param name="family"></param>엘보 부속류
/// <param name="StdCon"></param>기준 커넥터
/// <returns></returns>
public static Connector GetDirectionConnector(FamilyInstance family, Connector StdCon)
{
Connector dirCon = null;
if (family == null || StdCon == null) return null;
List<Connector> famConLst = Util.GetElementConnectors(family);
foreach(Connector con in famConLst)
{
//기준 커넥터와 같으면 넘어가고 기준 커넥터와 같은 각도만 찾음.
if (StdCon.Origin.IsAlmostEqualTo(con.Origin)) continue;
if(StdCon.Angle == con.Angle)
{
dirCon = con;
break;
}
}
return dirCon;
}
//패밀리의 타입구분
public static bool GetFamilyPartType(Connector baseCon, PartType partType)
{
if (baseCon.Owner is FamilyInstance)
{
FamilyInstance family = baseCon.Owner as FamilyInstance;
Parameter param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE);
if (partType == (PartType)param.AsInteger())
return true;
else
return false;
}
return false;
}
//패밀리의 타입구분
public static bool GetFamilyPartType(Element element, PartType partType)
{
List<Connector> ConLst = GetElementConnectors(element);
if (ConLst == null || ConLst.Count() <= 0) return false;
Connector baseCon = ConLst.First();
if (baseCon.Owner is FamilyInstance)
{
FamilyInstance family = baseCon.Owner as FamilyInstance;
Parameter param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE);
if (partType == (PartType)param.AsInteger())
return true;
else
return false;
}
return false;
}
//패밀리의 타입구분
public static bool GetFamilyPartType(FamilySymbol Symbol, PartType partType)
{
Parameter param = Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE);
if (param != null)
{
if (partType == (PartType)param.AsInteger())
return true;
else
return false;
}
//if (baseCon.Owner is FamilyInstance)
//{
// FamilyInstance family = baseCon.Owner as FamilyInstance;
// Parameter param = family.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE);
// if (partType == (PartType)param.AsInteger())
// return true;
// else
// return false;
//}
return false;
}
//커넥터에 연결된 다음 객체의 커넥터 구하기.
public static Connector GetNextElementConnector(Connector baseCon)
{
Connector resCon = null;
if (baseCon.IsConnected == true)
{
ConnectorSet ConSet = baseCon.AllRefs;
ConnectorSetIterator csi = ConSet.ForwardIterator();
while (csi.MoveNext())
{
Connector connected = csi.Current as Connector;
if (connected != null && connected.ConnectorType == ConnectorType.End)
{
if (baseCon.Origin.IsAlmostEqualTo(connected.Origin, Unit.MMToFeet(0.001)))
{
if (connected.IsConnected == true)
{
ConnectorSet ConnectedSet = null;
FamilyInstance family = null;
Pipe pipe = null;
Duct duct = null;
FlexDuct flexduct = null;
FlexPipe flexpipe = null;
if (connected.Owner is FamilyInstance)
{
family = connected.Owner as FamilyInstance;
ConnectedSet = family.MEPModel.ConnectorManager.Connectors;
}
else if (connected.Owner is Pipe)
{
pipe = connected.Owner as Pipe;
ConnectedSet = pipe.ConnectorManager.Connectors;
}
else if (connected.Owner is Duct)
{
duct = connected.Owner as Duct;
ConnectedSet = duct.ConnectorManager.Connectors;
}
else if (connected.Owner is FlexDuct)
{
flexduct = connected.Owner as FlexDuct;
ConnectedSet = flexduct.ConnectorManager.Connectors;
}
else if (connected.Owner is FlexPipe)
{
flexpipe = connected.Owner as FlexPipe;
ConnectedSet = flexpipe.ConnectorManager.Connectors;
}
foreach (Connector NextCon in ConnectedSet)
{
if (connected.Origin.IsAlmostEqualTo(NextCon.Origin, Unit.MMToFeet(0.001)))
{
resCon = NextCon;
}
}
}
}
}//while end
}
}
return resCon;
}
//객체의 커넥터가 2개일 경우(파이프,덕트,패밀리) baseCon이 아닌 커넥터 찾기
public static Connector GetOtherConnector(Connector baseCon)
{
Connector resCon = null;
ConnectorSet ConSet = null;
FamilyInstance family = null;
Pipe pipe = null;
Duct duct = null;
FlexPipe flexPipe = null;
FlexDuct flexDuct = null;
CableTray cable = null;
Conduit conduit = null;
if (baseCon.Owner is FamilyInstance)
{
family = baseCon.Owner as FamilyInstance;
ConSet = family.MEPModel.ConnectorManager.Connectors;
}
else if (baseCon.Owner is Pipe)
{
pipe = baseCon.Owner as Pipe;
ConSet = pipe.ConnectorManager.Connectors;
}
else if (baseCon.Owner is Duct)
{
duct = baseCon.Owner as Duct;
ConSet = duct.ConnectorManager.Connectors;
}
else if (baseCon.Owner is FlexPipe)
{
flexPipe = baseCon.Owner as FlexPipe;
ConSet = flexPipe.ConnectorManager.Connectors;
}
else if (baseCon.Owner is FlexDuct)
{
flexDuct = baseCon.Owner as FlexDuct;
ConSet = flexDuct.ConnectorManager.Connectors;
}
else if (baseCon.Owner is CableTray)
{
cable = baseCon.Owner as CableTray;
ConSet = cable.ConnectorManager.Connectors;
}
else if (baseCon.Owner is Conduit)
{
conduit = baseCon.Owner as Conduit;
ConSet = conduit.ConnectorManager.Connectors;
}
foreach (Connector OtherCon in ConSet)
{
if (!(OtherCon.Origin.IsAlmostEqualTo(baseCon.Origin, Unit.MMToFeet(0.01))))
resCon = OtherCon;
}
return resCon;
}
//기준 커넥터에서 FlowVec 방향 커넥터 구하기(Tee 또는 Cross에서 사용)
public static Connector GetClosestConnector(Connector baseCon, XYZ FlowVec, XYZ ReverseVec)
{
Connector resCon = null;
ConnectorSet ConSet = null;
FamilyInstance family = null;
Pipe pipe = null;
if (baseCon.Owner is FamilyInstance)
{
family = baseCon.Owner as FamilyInstance;
ConSet = family.MEPModel.ConnectorManager.Connectors;
}
else if (baseCon.Owner is Pipe)
{
pipe = baseCon.Owner as Pipe;
ConSet = pipe.ConnectorManager.Connectors;
}
foreach (Connector con in ConSet)
{
if (baseCon.Origin.IsAlmostEqualTo(con.Origin, Unit.MMToFeet(0.01))) continue;
XYZ CurVec = (con.Origin - baseCon.Origin).Normalize();
if ((CurVec.IsAlmostEqualTo(FlowVec, Unit.MMToFeet(0.01)) || CurVec.IsAlmostEqualTo(ReverseVec, Unit.MMToFeet(0.01))))
resCon = con;
}
return resCon;
}
public static bool RotateElement(Element elem, double Rad)
{
LocationCurve cur = elem.Location as LocationCurve;
if (cur != null)
{
Curve line = cur.Curve;
XYZ aa = line.GetEndPoint(0);
XYZ cc = new XYZ(aa.X, aa.Y, aa.Z + 10);
Line axis = Line.CreateBound(aa, cc);
cur.Rotate(axis, Rad);
return true;
}
return false;
}
public static bool RotateElementY(Element elem, double Rad)
{
LocationCurve cur = elem.Location as LocationCurve;
if (cur != null)
{
Curve line = cur.Curve;
XYZ aa = line.GetEndPoint(0);
XYZ cc = new XYZ(aa.X, aa.Y, aa.Z + 10);
Line axis = Line.CreateBound(aa, cc);
cur.Rotate(axis, Rad);
return true;
}
return false;
}
public static bool RotateElementZ(Element elem, double Rad)
{
LocationCurve cur = elem.Location as LocationCurve;
if (cur != null)
{
Curve line = cur.Curve;
XYZ aa = line.GetEndPoint(0);
XYZ cc = new XYZ(aa.X, aa.Y + 10, aa.Z);
Line axis = Line.CreateBound(aa, cc);
cur.Rotate(axis, Rad);
return true;
}
return false;
}
public static double Angle2D(XYZ spt, XYZ ept)
{
double degree = 0;
XYZ vec;
vec = (ept - spt).Normalize();
degree = System.Math.Round(Util.RTD(vec.AngleTo(XYZ.BasisX)), 3);
return degree;
}
/// <summary>
/// 파이프에 라우팅된 심볼 구하기.
/// </summary>
/// <param name="doc"></param>
/// <param name="pipeType"></param>라우팅 심볼 가져올 파이프의 pipeType
/// <param name="routingType"></param>라우팅 패밀리 유형
/// <returns></returns>
public static FamilySymbol GetSymbol_RoutingPreference(Document doc, PipeType pipeType, RoutingPreferenceRuleGroupType routingType)
{
if (pipeType == null) return null;
RoutingPreferenceManager rpm = pipeType.RoutingPreferenceManager;
RoutingPreferenceRule rpr = rpm.GetRule(routingType, 0);
if (rpr == null) return null;
FamilySymbol routingSymbol = doc.GetElement(rpr.MEPPartId) as FamilySymbol;
if (routingSymbol == null) return null;
return routingSymbol;
}
//맞닿은 두 객체가 방향이 맞지 않을 때 돌려주기
//(두 객체의 커넥터는 맞닿아 있으나 Sub객체가 돌아가 커넥터가 연결이 되지 않을 때 사용)
public static void MatchingRotateElement(Document doc, Element MainElem, Element SubElem)
{
//수평
List<Connector> MainConLst = Util.GetElementConnectors(MainElem);
List<Connector> SubConLst = Util.GetElementConnectors(SubElem);
//맞닿은 커넥터 찾기
Connector MainCon = null, SubCon = null;
foreach (Connector con1 in MainConLst)
{
foreach (Connector con2 in SubConLst)
{
if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.001)))
{
MainCon = con1;
SubCon = con2;
}
}
}
//메인 객체의 벡터방향구하기.
Connector MainOtherCon = Util.GetOtherConnector(MainCon);
XYZ dir = (MainOtherCon.Origin - MainCon.Origin).Normalize();
XYZ HorizonDir = new XYZ(dir.X, dir.Y, 0.0).Normalize();
XYZ connectorDirection = SubCon.CoordinateSystem.BasisZ;
double zRotAng = HorizonDir.AngleTo(connectorDirection);
Transform trf = Transform.CreateRotationAtPoint(XYZ.BasisZ, zRotAng, SubCon.Origin);
XYZ tRot = trf.OfVector(connectorDirection).Normalize();
if (Math.Abs(tRot.DotProduct(HorizonDir) - 1) > 0.00001)
zRotAng = -zRotAng;
Line axis = Line.CreateBound(SubCon.Origin, SubCon.Origin + XYZ.BasisZ);
ElementTransformUtils.RotateElement(doc, SubElem.Id, axis, zRotAng);
//수직
if (Math.Abs(dir.DotProduct(XYZ.BasisZ)) > 0.000001)
{
if (dir.X == 0 && dir.Y == 0 && dir.Z != 0)
{
XYZ yaxis = new XYZ(0.0, 1.0, 0.0);
double rotAng = dir.AngleTo(yaxis);
if (dir.Z == 1)
rotAng = -rotAng;
axis = Line.CreateBound(SubCon.Origin, yaxis);
ElementTransformUtils.RotateElement(doc, SubElem.Id, axis, rotAng);
}
else
{
double rotAng = dir.AngleTo(HorizonDir);
XYZ normal = HorizonDir.CrossProduct(XYZ.BasisZ);
trf = Transform.CreateRotationAtPoint(normal, rotAng, SubCon.Origin);
tRot = trf.OfVector(dir).Normalize();
if (Math.Abs(tRot.DotProduct(HorizonDir) - 1) < 0.00001)
rotAng = -rotAng;
axis = Line.CreateBound(SubCon.Origin, SubCon.Origin + normal);
ElementTransformUtils.RotateElement(doc, SubElem.Id, axis, rotAng);
}
}
doc.Regenerate();
SubCon.ConnectTo(MainCon);
}
//엘보 피팅(파이프,덕트)
public static FamilyInstance ElbowFitting(Document doc, Connector connector1, Connector connector2)
{
FamilyInstance fitting = null;
try
{
fitting = doc.Create.NewElbowFitting(connector1, connector2);
}
catch
{
}
return fitting;
}
//파이프 T 작도
public static FamilyInstance CreateTee(Autodesk.Revit.Creation.Document CreDoc, Connector MainCon1, Connector MainCon2, Connector SubCon1)
{
FamilyInstance fitting = null;
try
{
fitting = CreDoc.NewTeeFitting(MainCon1, MainCon2, SubCon1);
}
catch
{
}
return fitting;
}
//파이프 T 작도 (메인 파이프 자르고 서브커넥터와 T연결하는 방식)
public static FamilyInstance CreateTee(Document doc, Autodesk.Revit.Creation.Document CreDoc, Pipe MainPipe, Connector SubCon1)
{
FamilyInstance fitting = null;
Line pipeline = (MainPipe.Location as LocationCurve).Curve as Line;
XYZ DividePt = Util.GetPointOnLine(pipeline, SubCon1.Origin);
ElementId DivideID = PlumbingUtils.BreakCurve(doc, MainPipe.Id, DividePt);
if (DivideID != null)
{
Connector mainCon1 = null, mainCon2 = null;
//나뉜 파이프의 겹치는 커넥터 구하기(T커넥터)
List<Connector> MainCon1Lst = Util.GetElementConnectors(doc.GetElement(DivideID));
List<Connector> MainCon2Lst = Util.GetElementConnectors(MainPipe);
foreach (Connector con1 in MainCon1Lst)
{
foreach (Connector con2 in MainCon2Lst)
{
if (con1.Origin.IsAlmostEqualTo(con2.Origin, Unit.MMToFeet(0.01)))
{
mainCon1 = con1; mainCon2 = con2;
}
}
}
if (mainCon1 != null && mainCon2 != null && SubCon1 != null)
{
fitting = CreDoc.NewTeeFitting(mainCon1, mainCon2, SubCon1);
}
}
return fitting;
}
public static List<Pipe> CreatePipe(UIApplication uiapp, Document document, List<XYZ> pts, PipeType pipeType)
{
Autodesk.Revit.DB.View view = document.ActiveView;
Level level = document.ActiveView.GenLevel;
FilteredElementCollector sysCollector = new FilteredElementCollector(document);
//sysCollector.OfClass(typeof(PipingSystemType));
sysCollector.OfCategory(BuiltInCategory.OST_PipingSystem);
ElementId pipeSysTypeId = sysCollector.FirstElementId();
Pipe newpipe = null;
List<Pipe> pipes = new List<Pipe>();
List<Curve> newLineLst = new List<Curve>();
List<Element> ElemLst = new List<Element>();
for (int i = 0; i < pts.Count() - 1; i++)
{
ModelLine newLine = Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pts[i], pts[i + 1]) as ModelLine;
//document.Regenerate();
Curve cur = newLine.GeometryCurve;
newLineLst.Add(cur);
ElemLst.Add(newLine);
}
try
{
List<Element> elePipe = new List<Element>();
int cnt = 0;
foreach (Curve cur in newLineLst)
{
XYZ start = cur.GetEndPoint(0);
XYZ end = cur.GetEndPoint(1);
if (pipeType != null)
{
newpipe = Pipe.Create(document, pipeSysTypeId, pipeType.Id, level.Id, start, end);
//MessageBox.Show("1");
Element element = document.GetElement(newpipe.Id as ElementId);
elePipe.Add(element);
// 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
ElementId elementId = newpipe.Id as ElementId;
//Parameter parameter = element.LookupParameter("지름");
newpipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(Unit.MMToFeet(25));
pipes.Add(newpipe);
}
}
document.Regenerate();
for (int i = 0; i < pipes.Count() - 1; i++)
{
ConnectorManager pipe_connectorManager1 = pipes.ElementAt(i).ConnectorManager;
ConnectorSet pipe_connectorSet1 = pipe_connectorManager1.Connectors;
ConnectorManager pipe_connectorManager2 = pipes.ElementAt(i + 1).ConnectorManager;
ConnectorSet pipe_connectorSet2 = pipe_connectorManager2.Connectors;
// 2-3) 파이프가 가지고 있는 connectors 에서 연결시킬 connector 뽑아내기
Connector pipe_connector1 = null;
Connector pipe_connector2 = null;
double minDist = double.MaxValue;
foreach (Connector connector1 in pipe_connectorSet1)
{
foreach (Connector connector2 in pipe_connectorSet2)
{
double d = connector1.Origin.DistanceTo(connector2.Origin);
if (d < minDist)
{
pipe_connector1 = connector1;
pipe_connector2 = connector2;
minDist = d;
}
}
}
// 2-4) 2개의 파이프 연결시키기
try
{
FamilyInstance fitting = document.Create.NewElbowFitting(pipe_connector1, pipe_connector2);
}
catch (Exception e)
{
//MessageBox.Show("" + e);
}
}
// pipe와 겹치는 line 삭제하기
foreach (Element element in ElemLst)
{
if (element == null) continue;
ElementId elementId = element.Id;
document.Delete(elementId);
}
return pipes;
}
catch (Exception e)
{
}
return pipes;
}
/// <summary>
/// 모델라인 작도 후 파이프 그리면 세로로 그리기 안되서 Line.CreateBound로 라인그림
/// </summary>
/// <param name="uiapp"></param>
/// <param name="document"></param>
/// <param name="pts"></param>파이프 점들
/// <param name="SystemTypeId"></param>파이프 시스템타입
/// <param name="pipeTypeId"></param>파이프 타입
/// <param name="DrawLevel"></param>작도 레벨
/// <returns></returns>
public static List<Pipe> CreatePipe2(UIApplication uiapp, Document document, List<XYZ> pts, double PipeDia, ElementId SystemTypeId, ElementId pipeTypeId, ElementId DrawLevel)
{
Autodesk.Revit.DB.View view = document.ActiveView;
//Level level = document.ActiveView.GenLevel;
FilteredElementCollector sysCollector = new FilteredElementCollector(document);
//sysCollector.OfClass(typeof(PipingSystemType));
sysCollector.OfCategory(BuiltInCategory.OST_PipingSystem);
Pipe newpipe = null;
List<Pipe> pipes = new List<Pipe>();
List<Curve> newLineLst = new List<Curve>();
for (int i = 0; i < pts.Count() - 1; i++)
{
//ModelLine newLine = Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pts[i], pts[i + 1]) as ModelLine;
Line newLine = Line.CreateBound(pts[i], pts[i + 1]);
Curve cur = newLine as Curve;
document.Regenerate();
//Curve cur = newLine.GeometryCurve;
newLineLst.Add(cur);
//ElemLst.Add(newLine);
}
try
{
List<Element> elePipe = new List<Element>();
int cnt = 0;
foreach (Curve cur in newLineLst)
{
XYZ start = cur.GetEndPoint(0);
XYZ end = cur.GetEndPoint(1);
if (pipeTypeId != null)
{
newpipe = Pipe.Create(document, SystemTypeId, pipeTypeId, DrawLevel, start, end);
//MessageBox.Show("1");
Element element = document.GetElement(newpipe.Id as ElementId);
elePipe.Add(element);
// 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
ElementId elementId = newpipe.Id as ElementId;
//Parameter parameter = element.LookupParameter("지름");
newpipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(PipeDia);
pipes.Add(newpipe);
}
}
document.Regenerate();
for (int i = 0; i < pipes.Count() - 1; i++)
{
ConnectorManager pipe_connectorManager1 = pipes.ElementAt(i).ConnectorManager;
ConnectorSet pipe_connectorSet1 = pipe_connectorManager1.Connectors;
ConnectorManager pipe_connectorManager2 = pipes.ElementAt(i + 1).ConnectorManager;
ConnectorSet pipe_connectorSet2 = pipe_connectorManager2.Connectors;
// 2-3) 파이프가 가지고 있는 connectors 에서 연결시킬 connector 뽑아내기
Connector pipe_connector1 = null;
Connector pipe_connector2 = null;
double minDist = double.MaxValue;
foreach (Connector connector1 in pipe_connectorSet1)
{
foreach (Connector connector2 in pipe_connectorSet2)
{
double d = connector1.Origin.DistanceTo(connector2.Origin);
if (d < minDist)
{
pipe_connector1 = connector1;
pipe_connector2 = connector2;
minDist = d;
}
}
}
// 2-4) 2개의 파이프 연결시키기
try
{
FamilyInstance fitting = document.Create.NewElbowFitting(pipe_connector1, pipe_connector2);
}
catch (Exception e)
{
//MessageBox.Show("" + e);
}
}
return pipes;
}
catch (Exception e)
{
}
return pipes;
}
public static Pipe CreatePipe2(UIApplication uiapp, Document document, XYZ spt, XYZ ept, double PipeDia, ElementId SystemTypeId, ElementId pipeTypeId, ElementId DrawLevel)
{
Autodesk.Revit.DB.View view = document.ActiveView;
//Level level = document.ActiveView.GenLevel;
FilteredElementCollector sysCollector = new FilteredElementCollector(document);
//sysCollector.OfClass(typeof(PipingSystemType));
sysCollector.OfCategory(BuiltInCategory.OST_PipingSystem);
Pipe newpipe = null;
//ModelLine newLine = Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pts[i], pts[i + 1]) as ModelLine;
Line newLine = Line.CreateBound(spt, ept);
Curve curve = newLine as Curve;
document.Regenerate();
try
{
if (pipeTypeId != null)
{
newpipe = Pipe.Create(document, SystemTypeId, pipeTypeId, DrawLevel, spt, ept);
Element element = document.GetElement(newpipe.Id as ElementId);
// 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
ElementId elementId = newpipe.Id as ElementId;
//Parameter parameter = element.LookupParameter("지름");
newpipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(PipeDia);
}
document.Regenerate();
return newpipe;
}
catch (Exception e)
{
}
return newpipe;
}
public static List<Pipe> CreatePipe(UIApplication uiapp, Document document, List<XYZ> pts, ElementId SystemTypeId, ElementId pipeTypeId, ElementId DrawLevel)
{
Autodesk.Revit.DB.View view = document.ActiveView;
//Level level = document.ActiveView.GenLevel;
FilteredElementCollector sysCollector = new FilteredElementCollector(document);
//sysCollector.OfClass(typeof(PipingSystemType));
sysCollector.OfCategory(BuiltInCategory.OST_PipingSystem);
Pipe newpipe = null;
List<Pipe> pipes = new List<Pipe>();
List<Curve> newLineLst = new List<Curve>();
List<Element> ElemLst = new List<Element>();
for (int i = 0; i < pts.Count() - 1; i++)
{
ModelLine newLine = Util.NewModelLine(uiapp, view.SketchPlane.GetPlane(), pts[i], pts[i + 1]) as ModelLine;
document.Regenerate();
Curve cur = newLine.GeometryCurve;
newLineLst.Add(cur);
ElemLst.Add(newLine);
}
try
{
List<Element> elePipe = new List<Element>();
int cnt = 0;
foreach (Curve cur in newLineLst)
{
XYZ start = cur.GetEndPoint(0);
XYZ end = cur.GetEndPoint(1);
if (pipeTypeId != null)
{
newpipe = Pipe.Create(document, SystemTypeId, pipeTypeId, DrawLevel, start, end);
//MessageBox.Show("1");
Element element = document.GetElement(newpipe.Id as ElementId);
elePipe.Add(element);
// 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
ElementId elementId = newpipe.Id as ElementId;
//Parameter parameter = element.LookupParameter("지름");
newpipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(Unit.MMToFeet(25));
pipes.Add(newpipe);
}
}
document.Regenerate();
for (int i = 0; i < pipes.Count() - 1; i++)
{
ConnectorManager pipe_connectorManager1 = pipes.ElementAt(i).ConnectorManager;
ConnectorSet pipe_connectorSet1 = pipe_connectorManager1.Connectors;
ConnectorManager pipe_connectorManager2 = pipes.ElementAt(i + 1).ConnectorManager;
ConnectorSet pipe_connectorSet2 = pipe_connectorManager2.Connectors;
// 2-3) 파이프가 가지고 있는 connectors 에서 연결시킬 connector 뽑아내기
Connector pipe_connector1 = null;
Connector pipe_connector2 = null;
double minDist = double.MaxValue;
foreach (Connector connector1 in pipe_connectorSet1)
{
foreach (Connector connector2 in pipe_connectorSet2)
{
double d = connector1.Origin.DistanceTo(connector2.Origin);
if (d < minDist)
{
pipe_connector1 = connector1;
pipe_connector2 = connector2;
minDist = d;
}
}
}
// 2-4) 2개의 파이프 연결시키기
try
{
FamilyInstance fitting = document.Create.NewElbowFitting(pipe_connector1, pipe_connector2);
}
catch (Exception e)
{
//MessageBox.Show("" + e);
}
}
// pipe와 겹치는 line 삭제하기
foreach (Element element in ElemLst)
{
if (element == null) continue;
ElementId elementId = element.Id;
document.Delete(elementId);
}
return pipes;
}
catch (Exception e)
{
}
return pipes;
}
//플렉시블 파이프 생성
public static List<FlexPipe> CreateFlexPipe(UIApplication uiapp, Document document, List<XYZ> pts, ElementId SystemTypeId, ElementId pipeTypeId, ElementId DrawLevel)
{
Autodesk.Revit.DB.View view = document.ActiveView;
//Level level = document.ActiveView.GenLevel;
ICollection<Element> FlexPipeTypeLst = new FilteredElementCollector(document).OfClass(typeof(FlexPipeType)).ToElements();
FlexPipeType fpt = FlexPipeTypeLst.First() as FlexPipeType;
FlexPipe newpipe = null;
List<FlexPipe> pipes = new List<FlexPipe>();
List<Curve> newLineLst = new List<Curve>();
List<Element> ElemLst = new List<Element>();
try
{
List<Element> elePipe = new List<Element>();
int cnt = 0;
if (pipeTypeId != null)
{
newpipe = FlexPipe.Create(document, SystemTypeId, fpt.Id, DrawLevel, pts);
//MessageBox.Show("1");
Element element = document.GetElement(newpipe.Id as ElementId);
elePipe.Add(element);
// 1-6) fitting 할 elbow 굵기에 맞게 pipe 굵기 설정하기
ElementId elementId = newpipe.Id as ElementId;
//Parameter parameter = element.LookupParameter("지름");
newpipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(Unit.MMToFeet(25));
pipes.Add(newpipe);
}
document.Regenerate();
return pipes;
}
catch (Exception e)
{
//MessageBox.Show("" + e);
}
return pipes;
}
//캡 생성
public static void CreateCap(UIApplication uiapp, Document doc, Connector baseCon, string FamilytPath)
{
XYZ pipeSP = baseCon.Origin;
string capFamilyName = null;
if (uiapp.Application.Language == Autodesk.Revit.ApplicationServices.LanguageType.English_USA)
capFamilyName = "M_Cap - Generic";
else
capFamilyName = "M_캡 - 일반";
List<FamilySymbol> symbols = new List<FamilySymbol>(new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_PipeFitting)
.OfClass(typeof(FamilySymbol))
.OfType<FamilySymbol>()
.Where<FamilySymbol>(
s => s.Family.Name.Equals(capFamilyName)));
FamilySymbol capSymbol = null;
using (Transaction trans = new Transaction(doc))
{
trans.Start("1");
if (symbols.Count > 0)
capSymbol = symbols.First();
else
{
doc.LoadFamilySymbol(FamilytPath, capFamilyName, out capSymbol);
}
//Debug.Assert(capSymbol.Family.Name.Equals(capFamilyName), "expected cap pipe fitting to be of family" + capFamilyName);
//캡 생성
FamilyInstance fi = doc.Create.NewFamilyInstance(baseCon.Origin, capSymbol, StructuralType.NonStructural);
doc.Regenerate();
//가지관에 맞게 캡 돌려서 커넥터 연결하기
Util.MatchingRotateElement(doc, baseCon.Owner, fi);
trans.Commit();
}
}
public static List<ElementId> DivideElement(Document doc, Pipe MainPipe, XYZ DirectPt)
{
List<ElementId> DivideElementLst = new List<ElementId>();
Line MainLine = (MainPipe.Location as LocationCurve).Curve as Line;
XYZ DividePt = GetPointOnLine(MainLine, DirectPt);
ElementId DivideID = PlumbingUtils.BreakCurve(doc, MainPipe.Id, DividePt);
if (DivideID != null)
{
XYZ divSp = null, divEp = null, mainSp = null, mainEp = null;
bool b_div = false, b_main = false;
b_div = GetStartEndPoint(doc.GetElement(DivideID) as Pipe, ref divSp, ref divEp);
b_main = GetStartEndPoint(MainPipe, ref mainSp, ref mainEp);
if (b_div && b_main)
{
if (divSp.IsAlmostEqualTo(divEp, Unit.MMToFeet(0.01))
|| mainSp.IsAlmostEqualTo(mainEp, Unit.MMToFeet(0.01)))
{
return DivideElementLst;
}
else
{
DivideElementLst.Add(DivideID);
DivideElementLst.Add(MainPipe.Id);
}
}
}
return DivideElementLst;
}
// 덕트 점 기준으로 자르기 20210217 추가
public static List<ElementId> DivideElement(Document doc, Duct MainDuct, XYZ DirectPt)
{
List<ElementId> DivideElementLst = new List<ElementId>();
Line MainLine = (MainDuct.Location as LocationCurve).Curve as Line;
XYZ DividePt = GetPointOnLine(MainLine, DirectPt);
try
{
ElementId DivideID = MechanicalUtils.BreakCurve(doc, MainDuct.Id, DividePt);
if (DivideID != null)
{
XYZ divSp = null, divEp = null, mainSp = null, mainEp = null;
bool b_div = false, b_main = false;
b_div = GetStartEndPoint(doc.GetElement(DivideID) as Duct, ref divSp, ref divEp);
b_main = GetStartEndPoint(MainDuct, ref mainSp, ref mainEp);
if (b_div && b_main)
{
if (divSp.IsAlmostEqualTo(divEp, Unit.MMToFeet(0.01))
|| mainSp.IsAlmostEqualTo(mainEp, Unit.MMToFeet(0.01)))
{
return DivideElementLst;
}
else
{
DivideElementLst.Add(DivideID);
DivideElementLst.Add(MainDuct.Id);
}
}
}
}
catch
{
}
return DivideElementLst;
}
// 패밀리 위치 이동(패밀리 인스턴스는 Transform 이용해야 해서 만듬)
public static void MoveFamilyInstance(Document doc, FamilyInstance family, XYZ MovePt)
{
try
{
Transform transform = family.GetTransform();
XYZ Translation = MovePt - transform.Origin;
//패밀리 이동
ElementTransformUtils.MoveElement(doc, family.Id, Translation);
//redraw / 트랜잭션 실행문 안에서 할 것.
doc.Regenerate();
}
catch
{
}
}
//교차점 찾기(Z값 = p1.Z)
public static XYZ GetIntersectionPoint(XYZ p1, XYZ p2, XYZ p3, XYZ p4)
{
double d = (p1.X - p2.X) * (p3.Y - p4.Y) - (p1.Y - p2.Y) * (p3.X - p4.X);
if (d == 0) return null;
double pre = (p1.X * p2.Y - p1.Y * p2.X), post = (p3.X * p4.Y - p3.Y * p4.X);
double x = (pre * (p3.X - p4.X) - (p1.X - p2.X) * post) / d;
double y = (pre * (p3.Y - p4.Y) - (p1.Y - p2.Y) * post) / d;
XYZ resPt = new XYZ(x, y, p1.Z);
return resPt;
}
public static XYZ GetCurvesIntersectionPoint(Curve line1, Curve line2)
{
IntersectionResultArray resultArray = null;
line1.Intersect(line2, out resultArray);
if (resultArray != null)
{
foreach (IntersectionResult result in resultArray)
{
if (result.XYZPoint != null)
{
return result.XYZPoint;
}
}
}
return null;
}
//Z값이 0에서 라인 교차점 찾기
public static XYZ GetCurvesIntersectionPointZ0(XYZ lin1Sp, XYZ lin1Ep, XYZ lin2Sp, XYZ lin2Ep)
{
lin1Sp = new XYZ(lin1Sp.X, lin1Sp.Y, 0);
lin1Ep = new XYZ(lin1Ep.X, lin1Ep.Y, 0);
lin2Sp = new XYZ(lin2Sp.X, lin2Sp.Y, 0);
lin2Ep = new XYZ(lin2Ep.X, lin2Ep.Y, 0);
Line linePipe1 = Line.CreateUnbound(lin1Sp, lin1Ep);
Line linePipe2 = Line.CreateUnbound(lin2Sp, lin2Ep);
IntersectionResultArray resultArray = null;
linePipe1.Intersect(linePipe2, out resultArray);
if (resultArray != null)
{
foreach (IntersectionResult result in resultArray)
{
if (result.XYZPoint != null)
{
return result.XYZPoint;
}
}
}
return null;
}
public static Autodesk.Revit.DB.ElementId GetLevelId(Autodesk.Revit.DB.FamilyInstance fi)
{
return fi.LevelId;
}
public static Autodesk.Revit.DB.XYZ GetEndPoint(Curve crv, int index)
{
return crv.GetEndPoint(index);
}
public static Parameter GetParameter(Autodesk.Revit.DB.Element elm, string name)
{
return elm.LookupParameter(name);
}
public static List<Autodesk.Revit.DB.FamilySymbol> GetFamilySymbols(Document doc, Autodesk.Revit.DB.Family family)
{
List<Autodesk.Revit.DB.FamilySymbol> list = new List<Autodesk.Revit.DB.FamilySymbol>();
foreach (Autodesk.Revit.DB.ElementId familySymbolId in family.GetFamilySymbolIds())
{
Autodesk.Revit.DB.FamilySymbol familySymbol = doc.GetElement(familySymbolId) as Autodesk.Revit.DB.FamilySymbol;
if (familySymbol != null)
{
list.Add(familySymbol);
}
}
return list;
}
// 패밀리 존재 여부 검토
public static List<FamilySymbol> getFamily(Document doc, string categori)
{
List<FamilySymbol> familySymbol = new List<FamilySymbol>();
List<Autodesk.Revit.Creation.FamilyInstanceCreationData> fiCreationDatas =
new List<Autodesk.Revit.Creation.FamilyInstanceCreationData>();
ElementSet elementSet = null;
//Try to get a FamilySymbol
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> collection = collector.OfClass(typeof(FamilySymbol)).ToElements();
FamilySymbol Symbol;
foreach (Element e in collection)
{
Symbol = e as FamilySymbol;
if (null != Symbol.Category)
{
if (categori == Symbol.Category.Name)
{
familySymbol.Add(Symbol);
}
}
}
return familySymbol;
}
public static FamilySymbol getFamilySymbol(Document doc, List<FamilySymbol> FamSymbolLst, string symbolPath, string LibrariesName)
{
FamilySymbol symbol = null;
if (FamSymbolLst.Count == 0)
{
string str = symbolPath;
symbol = LoadFamilys(doc, str, LibrariesName);
if (symbol == null)
symbol = getNameByFamily(doc, Path.GetFileNameWithoutExtension(str));
else
{
if (symbol.IsActive == false)
symbol.Activate();
}
}
else if (FamSymbolLst.Count > 0)
{
string str = symbolPath;
symbol = LoadFamilys(doc, str, LibrariesName);
if (symbol == null)
symbol = getNameByFamily(doc, Path.GetFileNameWithoutExtension(str));
else
{
if (symbol.IsActive == false)
symbol.Activate();
}
}
return symbol;
}
public static void Delete(Document doc, Autodesk.Revit.DB.Element element)
{
doc.Delete(element.Id);
}
public static Reference GetEndPointReference(Curve crv, int index)
{
return crv.GetEndPointReference(index);
}
public static void Activate(Autodesk.Revit.DB.FamilySymbol fs)
{
if (!fs.IsActive)
{
fs.Activate();
}
}
public static List<Autodesk.Revit.DB.Element> GetSelectedElements(Autodesk.Revit.UI.UIDocument uidoc)
{
List<Autodesk.Revit.DB.Element> list = new List<Autodesk.Revit.DB.Element>();
Document document = uidoc.Document;
foreach (Autodesk.Revit.DB.ElementId elementId in uidoc.Selection.GetElementIds())
{
list.Add(document.GetElement(elementId));
}
return list;
}
public static Autodesk.Revit.DB.SketchPlane GetSketchPlane(Document doc, Autodesk.Revit.DB.Plane plane)
{
return Autodesk.Revit.DB.SketchPlane.Create(doc, plane);
}
public static Line GetBoundLine(Autodesk.Revit.DB.XYZ sp, Autodesk.Revit.DB.XYZ ep)
{
return Line.CreateBound(sp, ep);
}
public static void SetContextualHelp(PushButton pushButton, string helpPath)
{
pushButton.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, helpPath));
}
public static Autodesk.Revit.DB.Element GetElement(Document doc, Autodesk.Revit.DB.ElementId elementId)
{
return doc.GetElement(elementId);
}
public static KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType GetHangerCurveType(Autodesk.Revit.DB.Connector connector)
{
if (connector.Shape == Autodesk.Revit.DB.ConnectorProfileType.Rectangular)
{
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.RectDuct;
}
if (connector.Shape == Autodesk.Revit.DB.ConnectorProfileType.Round)
{
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.RoundDuct;
}
return KMBIM.Revit.Tools.Cmd.Hanger.MEPCurveType.OvalDuct;
}
public static void SetCategoryHidden(Document doc, View view, BuiltInCategory catagoryId)
{
view.SetCategoryHidden(new Autodesk.Revit.DB.ElementId(catagoryId), false);
}
public static string GetKMBIMLibraryFolder(string subFolder = "")
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "DCS.CO.KR\\KMBIM\\" + subFolder);
}
public static Parameter LookupParameter(Autodesk.Revit.DB.Element element, string name)
{
return element.LookupParameter(name);
}
// 행거 라이브러리
public static List<string> GetLibrary(string subFolder, bool withExtension = false)
{
List<string> list = new List<string>();
string libraryFolder = Util.GetKMBIMLibraryFolder(subFolder);
if (!Directory.Exists(libraryFolder))
{
return list;
}
foreach (string item in Directory.EnumerateFiles(libraryFolder, "*.rfa"))
{
string text = Path.GetFileName(item);
if (!withExtension)
{
text = text.Substring(0, text.Length - 4);
}
list.Add(text);
}
return list;
}
public static string GetParameterValueAsString(Autodesk.Revit.DB.Parameter parameter)
{
string value = "";
switch (parameter.StorageType)
{
case Autodesk.Revit.DB.StorageType.Double:
value = parameter.AsDouble().ToString();
break;
case Autodesk.Revit.DB.StorageType.ElementId:
value = parameter.AsElementId().IntegerValue.ToString();
break;
case Autodesk.Revit.DB.StorageType.String:
value = parameter.AsString();
break;
case Autodesk.Revit.DB.StorageType.Integer:
value = parameter.AsInteger().ToString();
break;
}
return value;
}
public static object GetParameterValue(Autodesk.Revit.DB.Parameter parameter)
{
object value = null;
switch (parameter.StorageType)
{
case Autodesk.Revit.DB.StorageType.Double:
value = parameter.AsDouble();
break;
case Autodesk.Revit.DB.StorageType.ElementId:
value = parameter.AsElementId().IntegerValue;
break;
case Autodesk.Revit.DB.StorageType.String:
value = parameter.AsString();
break;
case Autodesk.Revit.DB.StorageType.Integer:
value = parameter.AsInteger();
break;
}
return value;
}
public static void SetParameterValue(Autodesk.Revit.DB.Parameter parameter, object value)
{
// get the parameter value
switch (parameter.StorageType)
{
case StorageType.Double:
parameter.Set((double)value);
break;
case StorageType.Integer:
parameter.Set((int)value);
break;
case StorageType.ElementId:
Autodesk.Revit.DB.ElementId Id = (Autodesk.Revit.DB.ElementId)value;
parameter.Set(Id);
break;
case StorageType.String:
parameter.Set(value as string);
break;
case StorageType.None:
parameter.SetValueString(value as string);
break;
default:
break;
}
}
public static void Swap<T>(this List<T> list, int index1, int index2)
{
T temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
// 주어진 점에 가까운점을 주어진 점으로 설정한다.
public static void SetPipeEnd(Pipe pipe, XYZ pt)
{
LocationCurve lc = pipe.Location as LocationCurve;
if (lc != null)
{
Line line1 = lc.Curve as Line;
XYZ sp = line1.GetEndPoint(0);
XYZ ep = line1.GetEndPoint(1);
if (pt.DistanceTo(sp) < pt.DistanceTo(ep)) lc.Curve = Line.CreateBound(pt, ep);
else lc.Curve = Line.CreateBound(sp, pt);
}
}
//파이프 세그먼트 관경들 구하기.
public static List<double> GetPipeSegmentSizes(Document doc, string pipeTypeName)
{
List<double> m_pipeDiaList = new List<double>();
ICollection<Element> pipeTypes = new FilteredElementCollector(doc).OfClass(typeof(PipeType)).ToElements();
foreach (Element elem in pipeTypes)
{
if (elem is PipeType)
{
PipeType pipeType = elem as PipeType;
//파이프 유형이름이 다르면 loop
if (pipeType.Name != pipeTypeName) continue;
RoutingPreferenceManager rpm = pipeType.RoutingPreferenceManager;
int segmentCnt = rpm.GetNumberOfRules(RoutingPreferenceRuleGroupType.Segments);
for (int i = 0; i != segmentCnt; i++)
{
RoutingPreferenceRule segmentRule = rpm.GetRule(RoutingPreferenceRuleGroupType.Segments, i);
Segment segment = doc.GetElement(segmentRule.MEPPartId) as Segment;
foreach (MEPSize size in segment.GetSizes())
{
var item = m_pipeDiaList.Find(v => v.Equals(size.NominalDiameter));
if (item == 0)
m_pipeDiaList.Add(Unit.FeetToMM(size.NominalDiameter));
}
}
m_pipeDiaList.Sort();
return m_pipeDiaList;
}
}
return null;
}
/// <summary>
/// 파이프 단열제 두께 구하기
/// </summary>
/// <param name="pipe"></param>
/// <returns></returns>
public static double GetPipeInsulationThickness(Document doc, Pipe pipe)
{
double insulThk = 0;
ICollection<ElementId> elementIds = InsulationLiningBase.GetInsulationIds(doc, pipe.Id);
foreach (ElementId elementId in elementIds)
{
Element insEl = doc.GetElement(elementId);
PipeInsulation insulation = insEl as PipeInsulation;
if (insulation != null)
{
insulThk += insulation.Thickness;
}
}
return insulThk;
}
/// <summary>
/// 파이프 단열재 두께 바꾸기
/// </summary>
/// <param name="doc"></param>
/// <param name="pipe"></param>
/// <param name="thickness"></param>
/// <returns></returns>
public static void SetPipeInsulationThickness(Document doc, Pipe pipe, double thickness)
{
ICollection<ElementId> Insulids = InsulationLiningBase.GetInsulationIds(doc, pipe.Id);
//기존 단열재가 있을 경우
if (Insulids.Count > 0)
{
foreach (ElementId elementId in Insulids)
{
Element insEl = doc.GetElement(elementId);
PipeInsulation insulation = insEl as PipeInsulation;
if (insulation != null)
{
insulation.Thickness = thickness;
}
}
}
else//기존 단열재가 없을 경우 새로 생성
{
string category = KDCS.Utils.Reg.getReg("kdcsInsulationDefaultType");
List<PipeInsulationType> PipeinsulationCollection = new FilteredElementCollector(doc)
.OfClass(typeof(PipeInsulationType))
.OfType<PipeInsulationType>()
.ToList();
//단열재 생셩
PipeInsulation.Create(doc, pipe.Id, PipeinsulationCollection.First().Id, thickness);
}
}
/// <summary>
/// string으로 레벨 찾기
/// </summary>
/// <param name="doc"></param>
/// <param name="LevelName"></param>
/// <returns></returns>
public static Level GetLevel(Document doc, string LevelName)
{
Level resLevel = null;
FilteredElementCollector lvlCollector = new FilteredElementCollector(doc);
ICollection<Element> lvlCollection = lvlCollector.OfClass(typeof(Level)).ToElements();
foreach (Element l in lvlCollection)
{
Level lvl = l as Level;
if (lvl.Name == LevelName)
{
resLevel = lvl;
break;
}
//MessageBox.Show("" + lvl.Name);
}
return resLevel;
}
/// <summary>
/// 간격띄우기 값으로 레벨 찾기.
/// </summary>
/// <param name="doc"></param>
/// <param name="elevatiopn"></param>
/// <returns></returns>
public static Level GetLevel(Document doc, double elevatiopn)
{
Level resLevel = null;
FilteredElementCollector lvlCollector = new FilteredElementCollector(doc);
var lstLevel = lvlCollector.OfClass(typeof(Level)).ToElements().Cast<Level>().ToList();
var sortedLevels = lstLevel.OrderByDescending(el => el.Elevation);
foreach (Level lvl in sortedLevels)
{
if (lvl.Elevation <= elevatiopn)
{
resLevel = lvl;
break;
}
}
return resLevel;
}
/// <summary>
/// 간격띄우기 값이 주어진 허용오차 이내에 있는 레벨 찾기.
/// </summary>
/// <param name="doc"></param>
/// <param name="elevatiopn"></param>
/// <returns></returns>
public static Level GetLevel(Document doc, double elevatiopn, double mmTol)
{
Level resLevel = null;
FilteredElementCollector lvlCollector = new FilteredElementCollector(doc);
var lstLevel = lvlCollector.OfClass(typeof(Level)).ToElements().Cast<Level>().ToList();
var sortedLevels = lstLevel.OrderByDescending(el => el.Elevation);
double tolFt = Geo.MmToFoot(mmTol);
foreach (Level lvl in sortedLevels)
{
if (elevatiopn <= lvl.Elevation+tolFt && elevatiopn >= lvl.Elevation-tolFt)
{
resLevel = lvl;
break;
}
}
return resLevel;
}
/// <summary>
/// 패밀리 로드
/// </summary>
/// <param name="famroot"></param>
/// <returns></returns>
public static FamilySymbol LoadFamilys(Document doc, string FamPath, string LibrariesName)
{
string versionNumber = doc.Application.VersionNumber.ToString();
//string Tmp = System.Reflection.Assembly.GetExecutingAssembly().Location;
//Tmp = Tmp.Replace("\\KMBIM2019.dll", "");
string Tmp = Util.GetKMBIMLibraryFolder("Libraries\\" + LibrariesName);
// get the active view's level for beam creation
Level level = doc.GetElement(doc.ActiveView.LevelId) as Level;
// load a family symbol from file
FamilySymbol gotSymbol = null;
String fileName = Tmp + "\\" + versionNumber + "\\" + FamPath;
// 패밀리를 로드한다.
Family fam = null;
//m_document.Document.LoadFamilySymbol(fileName, "", out gotSymbol);
bool sw = false;
using (Transaction trans = new Transaction(doc))
{
trans.Start("LoadFamily");
sw = doc.LoadFamily(fileName, out fam);
trans.Commit();
}
if (sw == true)
{
ISet<ElementId> fam_ids = fam.GetFamilySymbolIds();
List<string> fam_sym_names = new List<string>();
if (fam_ids.Count() == 0) return null;
gotSymbol = (FamilySymbol)doc.GetElement(fam_ids.ElementAt(0));
}
return gotSymbol;
}
/// <summary>
/// 패밀리 로드
/// </summary>
/// <param name="FamilyPath"></param>
/// <returns></returns>
public static FamilySymbol LoadFamilys(Document doc, string FamilyPath)
{
// get the active view's level for beam creation
Level level = doc.GetElement(doc.ActiveView.LevelId) as Level;
// load a family symbol from file
FamilySymbol gotSymbol = null;
// 패밀리를 로드한다.
Family fam = null;
bool sw = doc.LoadFamily(FamilyPath, out fam);
if (sw == true)
{
ISet<ElementId> fam_ids = fam.GetFamilySymbolIds();
List<string> fam_sym_names = new List<string>();
if (fam_ids.Count() == 0) return null;
gotSymbol = (FamilySymbol)doc.GetElement(fam_ids.ElementAt(0));
}
return gotSymbol;
}
/// <summary>
/// 패밀리 존재 여부 검토
/// </summary>
/// <param name="doc"></param>
/// <param name="name"></param>
/// <returns></returns>
public static FamilySymbol getNameByFamily(Document doc, string name)
{
List<Autodesk.Revit.Creation.FamilyInstanceCreationData> fiCreationDatas
= new List<Autodesk.Revit.Creation.FamilyInstanceCreationData>();
//Try to get a FamilySymbol
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> collection = collector.OfClass(typeof(FamilySymbol)).ToElements();
FamilySymbol Symbol;
FamilySymbol target = null;
foreach (Element e in collection)
{
Symbol = e as FamilySymbol;
if (null != Symbol.Category)
{
if (name == Symbol.Family.Name)
{
// MessageBox.Show(Symbol.Family.Name);
target = Symbol;
break;
}
}
}
return target;
}
//포인트 z값 0으로 변환
public static XYZ PointZ0(XYZ pt)
{
XYZ ptZ0 = new XYZ(pt.X, pt.Y, 0);
return ptZ0;
}
/// <summary>
/// 매개 변수 정의를 반환합니다.
/// 주어진 요소와 매개 변수 이름.
/// </summary>
public static Definition GetDefinition(Element elem, string parameter_name)
{
IList<Parameter> ps = elem.GetParameters(parameter_name);
int n = ps.Count;
//Debug.Assert(1 >= n, "expected maximum one shared parameters" + "named " + parameter_name);
Definition d = (0 == n) ? null
: ps[0].Definition;
return d;
}
}
public static class Geo
{
#region Geometrical Comparison
public const double _eps = 1.0e-9;
public static double Eps
{
get
{
return _eps;
}
}
public static double MinLineLength
{
get
{
return _eps;
}
}
public static double TolPointOnPlane
{
get
{
return _eps;
}
}
public static bool IsZero(
double a,
double tolerance = _eps)
{
return tolerance > Math.Abs(a);
}
public static bool IsEqual(
double a,
double b,
double tolerance = _eps)
{
return IsZero(b - a, tolerance);
}
public static int Compare(
double a,
double b,
double tolerance = _eps)
{
return IsEqual(a, b, tolerance)
? 0
: (a < b ? -1 : 1);
}
public static int Compare(
XYZ p,
XYZ q,
double tolerance = _eps)
{
int d = Compare(p.X, q.X, tolerance);
if (0 == d)
{
d = Compare(p.Y, q.Y, tolerance);
if (0 == d)
{
d = Compare(p.Z, q.Z, tolerance);
}
}
return d;
}
/// <summary>
/// Implement a comparison operator for lines
/// in the XY plane useful for sorting into
/// groups of parallel lines.
/// </summary>
public static int Compare(Line a, Line b)
{
XYZ pa = a.GetEndPoint(0);
XYZ qa = a.GetEndPoint(1);
XYZ pb = b.GetEndPoint(0);
XYZ qb = b.GetEndPoint(1);
XYZ va = qa - pa;
XYZ vb = qb - pb;
// Compare angle in the XY plane
double ang_a = Math.Atan2(va.Y, va.X);
double ang_b = Math.Atan2(vb.Y, vb.X);
int d = Compare(ang_a, ang_b);
if (0 == d)
{
// Compare distance of unbounded line to origin
double da = (qa.X * pa.Y - qa.Y * pa.Y)
/ va.GetLength();
double db = (qb.X * pb.Y - qb.Y * pb.Y)
/ vb.GetLength();
d = Compare(da, db);
if (0 == d)
{
// Compare distance of start point to origin
d = Compare(pa.GetLength(), pb.GetLength());
if (0 == d)
{
// Compare distance of end point to origin
d = Compare(qa.GetLength(), qb.GetLength());
}
}
}
return d;
}
/// <summary>
/// Predicate to test whewther two points or
/// vectors can be considered equal with the
/// given tolerance.
/// </summary>
public static bool IsEqual(
XYZ p,
XYZ q,
double tolerance = _eps)
{
return 0 == Compare(p, q, tolerance);
}
/// <summary>
/// Return true if the given bounding box bb
/// contains the given point p in its interior.
/// </summary>
public static bool BoundingBoxXyzContains(
BoundingBoxXYZ bb,
XYZ p)
{
return 0 < Compare(bb.Min, p)
&& 0 < Compare(p, bb.Max);
}
/// <summary>
/// Return true if the vectors v and w
/// are non-zero and perpendicular.
/// </summary>
public static bool IsPerpendicular(XYZ v, XYZ w)
{
double a = v.GetLength();
double b = v.GetLength();
double c = Math.Abs(v.DotProduct(w));
return _eps < a
&& _eps < b
&& _eps > c;
// c * c < _eps * a * b
}
public static bool IsParallel(XYZ p, XYZ q)
{
return p.CrossProduct(q).IsZeroLength();
}
public static bool IsCollinear(Line a, Line b)
{
XYZ v = a.Direction;
XYZ w = b.Origin - a.Origin;
return IsParallel(v, b.Direction)
&& IsParallel(v, w);
}
public static bool IsHorizontal(XYZ v)
{
return IsZero(v.Z);
}
public static bool IsVertical(XYZ v)
{
return IsZero(v.X) && IsZero(v.Y);
}
public static bool IsVertical(XYZ v, double tolerance)
{
return IsZero(v.X, tolerance)
&& IsZero(v.Y, tolerance);
}
public static bool IsHorizontal(Edge e)
{
XYZ p = e.Evaluate(0);
XYZ q = e.Evaluate(1);
return IsHorizontal(q - p);
}
public static bool IsHorizontal(PlanarFace f)
{
return IsVertical(f.FaceNormal);
}
public static bool IsVertical(PlanarFace f)
{
return IsHorizontal(f.FaceNormal);
}
public static bool IsVertical(CylindricalFace f)
{
return IsVertical(f.Axis);
}
/// <summary>
/// Minimum slope for a vector to be considered
/// to be pointing upwards. Slope is simply the
/// relationship between the vertical and
/// horizontal components.
/// </summary>
const double _minimumSlope = 0.3;
/// <summary>
/// Return true if the Z coordinate of the
/// given vector is positive and the slope
/// is larger than the minimum limit.
/// </summary>
public static bool PointsUpwards(XYZ v)
{
double horizontalLength = v.X * v.X + v.Y * v.Y;
double verticalLength = v.Z * v.Z;
return 0 < v.Z
&& _minimumSlope
< verticalLength / horizontalLength;
//return _eps < v.Normalize().Z;
//return _eps < v.Normalize().Z && IsVertical( v.Normalize(), tolerance );
}
/// <summary>
/// Return the maximum value from an array of real numbers.
/// </summary>
public static double Max(double[] a)
{
Debug.Assert(1 == a.Rank, "expected one-dimensional array");
Debug.Assert(0 == a.GetLowerBound(0), "expected zero-based array");
Debug.Assert(0 < a.GetUpperBound(0), "expected non-empty array");
double max = a[0];
for (int i = 1; i <= a.GetUpperBound(0); ++i)
{
if (max < a[i])
{
max = a[i];
}
}
return max;
}
#endregion // Geometrical Comparison
#region Unit Handling
/// <summary>
/// Base units currently used internally by Revit.
/// </summary>
enum BaseUnit
{
BU_Length = 0, // length, feet (ft)
BU_Angle, // angle, radian (rad)
BU_Mass, // mass, kilogram (kg)
BU_Time, // time, second (s)
BU_Electric_Current, // electric current, ampere (A)
BU_Temperature, // temperature, kelvin (K)
BU_Luminous_Intensity, // luminous intensity, candela (cd)
BU_Solid_Angle, // solid angle, steradian (sr)
NumBaseUnits
};
const double _inchToMm = 25.4;
const double _footToMm = 12 * _inchToMm;
const double _footToMeter = _footToMm * 0.001;
const double _sqfToSqm = _footToMeter * _footToMeter;
const double _cubicFootToCubicMeter = _footToMeter * _sqfToSqm;
/// <summary>
/// Convert a given length in feet to millimetres.
/// </summary>
public static double FootToMm(double length)
{
return length * _footToMm;
}
/// <summary>
/// Convert a given length in feet to millimetres,
/// rounded to the closest millimetre.
/// </summary>
public static int FootToMmInt(double length)
{
//return (int) ( _feet_to_mm * d + 0.5 );
return (int)Math.Round(_footToMm * length,
MidpointRounding.AwayFromZero);
}
/// <summary>
/// Convert a given length in feet to metres.
/// </summary>
public static double FootToMetre(double length)
{
return length * _footToMeter;
}
/// <summary>
/// Convert a given length in millimetres to feet.
/// </summary>
public static double MmToFoot(double length)
{
return length / _footToMm;
}
/// <summary>
/// Convert a given point or vector from millimetres to feet.
/// </summary>
public static XYZ MmToFoot(XYZ v)
{
return v.Divide(_footToMm);
}
/// <summary>
/// Convert a given volume in feet to cubic meters.
/// </summary>
public static double CubicFootToCubicMeter(double volume)
{
return volume * _cubicFootToCubicMeter;
}
/// <summary>
/// Hard coded abbreviations for the first 26
/// DisplayUnitType enumeration values.
/// </summary>
public static string[] DisplayUnitTypeAbbreviation
= new string[] {
"m", // DUT_METERS = 0,
"cm", // DUT_CENTIMETERS = 1,
"mm", // DUT_MILLIMETERS = 2,
"ft", // DUT_DECIMAL_FEET = 3,
"N/A", // DUT_FEET_FRACTIONAL_INCHES = 4,
"N/A", // DUT_FRACTIONAL_INCHES = 5,
"in", // DUT_DECIMAL_INCHES = 6,
"ac", // DUT_ACRES = 7,
"ha", // DUT_HECTARES = 8,
"N/A", // DUT_METERS_CENTIMETERS = 9,
"y^3", // DUT_CUBIC_YARDS = 10,
"ft^2", // DUT_SQUARE_FEET = 11,
"m^2", // DUT_SQUARE_METERS = 12,
"ft^3", // DUT_CUBIC_FEET = 13,
"m^3", // DUT_CUBIC_METERS = 14,
"deg", // DUT_DECIMAL_DEGREES = 15,
"N/A", // DUT_DEGREES_AND_MINUTES = 16,
"N/A", // DUT_GENERAL = 17,
"N/A", // DUT_FIXED = 18,
"%", // DUT_PERCENTAGE = 19,
"in^2", // DUT_SQUARE_INCHES = 20,
"cm^2", // DUT_SQUARE_CENTIMETERS = 21,
"mm^2", // DUT_SQUARE_MILLIMETERS = 22,
"in^3", // DUT_CUBIC_INCHES = 23,
"cm^3", // DUT_CUBIC_CENTIMETERS = 24,
"mm^3", // DUT_CUBIC_MILLIMETERS = 25,
"l" // DUT_LITERS = 26,
};
#endregion // Unit Handling
#region Formatting
/// <summary>
/// Return an English plural suffix for the given
/// number of items, i.e. 's' for zero or more
/// than one, and nothing for exactly one.
/// </summary>
public static string PluralSuffix(int n)
{
return 1 == n ? "" : "s";
}
/// <summary>
/// Return an English plural suffix 'ies' or
/// 'y' for the given number of items.
/// </summary>
public static string PluralSuffixY(int n)
{
return 1 == n ? "y" : "ies";
}
/// <summary>
/// Return a dot (full stop) for zero
/// or a colon for more than zero.
/// </summary>
public static string DotOrColon(int n)
{
return 0 < n ? ":" : ".";
}
/// <summary>
/// Return a string for a real number
/// formatted to two decimal places.
/// </summary>
public static string RealString(double a)
{
return a.ToString("0.##");
}
/// <summary>
/// Return a hash string for a real number
/// formatted to nine decimal places.
/// </summary>
public static string HashString(double a)
{
return a.ToString("0.#########");
}
/// <summary>
/// Return a string representation in degrees
/// for an angle given in radians.
/// </summary>
public static string AngleString(double angle)
{
return RealString(angle * 180 / Math.PI)
+ " degrees";
}
/// <summary>
/// Return a string for a length in millimetres
/// formatted as an integer value.
/// </summary>
public static string MmString(double length)
{
//return RealString( FootToMm( length ) ) + " mm";
return Math.Round(FootToMm(length))
.ToString() + " mm";
}
/// <summary>
/// Return a string for a UV point
/// or vector with its coordinates
/// formatted to two decimal places.
/// </summary>
public static string PointString(
UV p,
bool onlySpaceSeparator = false)
{
string format_string = onlySpaceSeparator
? "{0} {1}"
: "({0},{1})";
return string.Format(format_string,
RealString(p.U),
RealString(p.V));
}
/// <summary>
/// Return a string for an XYZ point
/// or vector with its coordinates
/// formatted to two decimal places.
/// </summary>
public static string PointString(
XYZ p,
bool onlySpaceSeparator = false)
{
string format_string = onlySpaceSeparator
? "{0} {1} {2}"
: "({0},{1},{2})";
return string.Format(format_string,
RealString(p.X),
RealString(p.Y),
RealString(p.Z));
}
/// <summary>
/// Return a hash string for an XYZ point
/// or vector with its coordinates
/// formatted to nine decimal places.
/// </summary>
public static string HashString(XYZ p)
{
return string.Format("({0},{1},{2})",
HashString(p.X),
HashString(p.Y),
HashString(p.Z));
}
/// <summary>
/// Return a string for this bounding box
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string BoundingBoxString(
BoundingBoxUV bb,
bool onlySpaceSeparator = false)
{
string format_string = onlySpaceSeparator
? "{0} {1}"
: "({0},{1})";
return string.Format(format_string,
PointString(bb.Min, onlySpaceSeparator),
PointString(bb.Max, onlySpaceSeparator));
}
/// Return a string for this bounding box
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string BoundingBoxString(
BoundingBoxXYZ bb,
bool onlySpaceSeparator = false)
{
string format_string = onlySpaceSeparator
? "{0} {1}"
: "({0},{1})";
return string.Format(format_string,
PointString(bb.Min, onlySpaceSeparator),
PointString(bb.Max, onlySpaceSeparator));
}
/// <summary>
/// Return a string for this plane
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string PlaneString(Plane p)
{
return string.Format("plane origin {0}, plane normal {1}",
PointString(p.Origin),
PointString(p.Normal));
}
/// <summary>
/// Return a string for this transformation
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string TransformString(Transform t)
{
return string.Format("({0},{1},{2},{3})", PointString(t.Origin),
PointString(t.BasisX), PointString(t.BasisY), PointString(t.BasisZ));
}
/// <summary>
/// Return a string for a list of doubles
/// formatted to two decimal places.
/// </summary>
public static string DoubleArrayString(
IEnumerable<double> a,
bool onlySpaceSeparator = false)
{
string separator = onlySpaceSeparator
? " "
: ", ";
return string.Join(separator,
a.Select<double, string>(
x => RealString(x)));
}
/// <summary>
/// Return a string for this point array
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string PointArrayString(
IEnumerable<UV> pts,
bool onlySpaceSeparator = false)
{
string separator = onlySpaceSeparator
? " "
: ", ";
return string.Join(separator,
pts.Select<UV, string>(p
=> PointString(p, onlySpaceSeparator)));
}
/// <summary>
/// Return a string for this point array
/// with its coordinates formatted to two
/// decimal places.
/// </summary>
public static string PointArrayString(
IEnumerable<XYZ> pts,
bool onlySpaceSeparator = false)
{
string separator = onlySpaceSeparator
? " "
: ", ";
return string.Join(separator,
pts.Select<XYZ, string>(p
=> PointString(p, onlySpaceSeparator)));
}
/// <summary>
/// Return a string representing the data of a
/// curve. Currently includes detailed data of
/// line and arc elements only.
/// </summary>
public static string CurveString(Curve c)
{
string s = c.GetType().Name.ToLower();
XYZ p = c.GetEndPoint(0);
XYZ q = c.GetEndPoint(1);
s += string.Format(" {0} --> {1}",
PointString(p), PointString(q));
// To list intermediate points or draw an
// approximation using straight line segments,
// we can access the curve tesselation, cf.
// CurveTessellateString:
//foreach( XYZ r in lc.Curve.Tessellate() )
//{
//}
// List arc data:
Arc arc = c as Arc;
if (null != arc)
{
s += string.Format(" center {0} radius {1}",
PointString(arc.Center), arc.Radius);
}
// Todo: add support for other curve types
// besides line and arc.
return s;
}
/// <summary>
/// Return a string for this curve with its
/// tessellated point coordinates formatted
/// to two decimal places.
/// </summary>
public static string CurveTessellateString(
Curve curve)
{
return "curve tessellation "
+ PointArrayString(curve.Tessellate());
}
/// <summary>
/// Convert a UnitSymbolType enumeration value
/// to a brief human readable abbreviation string.
/// </summary>
//public static string UnitSymbolTypeString(
// UnitSymbolType u)
//{
// string s = u.ToString();
//
// Debug.Assert(s.StartsWith("UST_"),
// "expected UnitSymbolType enumeration value "
// + "to begin with 'UST_'");
//
// s = s.Substring(4)
// .Replace("_SUP_", "^")
// .ToLower();
//
// return s;
//}
#endregion // Formatting
#region MEP utilities
/// <summary>
/// Return the given element's connector manager,
/// using either the family instance MEPModel or
/// directly from the MEPCurve connector manager
/// for ducts and pipes.
/// </summary>
static ConnectorManager GetConnectorManager(
Element e)
{
MEPCurve mc = e as MEPCurve;
FamilyInstance fi = e as FamilyInstance;
if (null == mc && null == fi)
{
throw new ArgumentException("Element is neither an MEP curve nor a fitting.");
}
return null == mc ? fi.MEPModel.ConnectorManager : mc.ConnectorManager;
}
/// <summary>
/// Return the element's connector at the given
/// location, and its other connector as well,
/// in case there are exactly two of them.
/// </summary>
/// <param name="e">An element, e.g. duct, pipe or family instance</param>
/// <param name="location">The location of one of its connectors</param>
/// <param name="otherConnector">The other connector, in case there are just two of them</param>
/// <returns>The connector at the given location</returns>
static Connector GetConnectorAt(
Element e,
XYZ location,
out Connector otherConnector)
{
otherConnector = null;
Connector targetConnector = null;
ConnectorManager cm = GetConnectorManager(e);
bool hasTwoConnectors = 2 == cm.Connectors.Size;
foreach (Connector c in cm.Connectors)
{
if (c.Origin.IsAlmostEqualTo(location))
{
targetConnector = c;
if (!hasTwoConnectors)
{
break;
}
}
else if (hasTwoConnectors)
{
otherConnector = c;
}
}
return targetConnector;
}
/// <summary>
/// Return the connector set element
/// closest to the given point.
/// </summary>
static Connector GetConnectorClosestTo(ConnectorSet connectors, XYZ p)
{
Connector targetConnector = null;
double minDist = double.MaxValue;
foreach (Connector c in connectors)
{
double d = c.Origin.DistanceTo(p);
if (d < minDist)
{
targetConnector = c;
minDist = d;
}
}
return targetConnector;
}
/// <summary>
/// Return the connector on the element
/// closest to the given point.
/// </summary>
public static Connector GetConnectorClosestTo(
Element e,
XYZ p)
{
ConnectorManager cm = GetConnectorManager(e);
return null == cm
? null
: GetConnectorClosestTo(cm.Connectors, p);
}
/// <summary>
/// Connect two MEP elements at a given point p.
/// </summary>
/// <exception cref="ArgumentException">Thrown if
/// one of the given elements lacks connectors.
/// </exception>
public static void Connect(
XYZ p,
Element a,
Element b)
{
ConnectorManager cm = GetConnectorManager(a);
if (null == cm)
{
throw new ArgumentException(
"Element a has no connectors.");
}
Connector ca = GetConnectorClosestTo(
cm.Connectors, p);
cm = GetConnectorManager(b);
if (null == cm)
{
throw new ArgumentException(
"Element b has no connectors.");
}
Connector cb = GetConnectorClosestTo(
cm.Connectors, p);
ca.ConnectTo(cb);
//cb.ConnectTo( ca );
}
/// <summary>
/// Compare Connector objects based on their location point.
/// </summary>
public class ConnectorXyzComparer : IEqualityComparer<Connector>
{
public bool Equals(Connector x, Connector y)
{
return null != x
&& null != y
&& IsEqual(x.Origin, y.Origin);
}
public int GetHashCode(Connector x)
{
return HashString(x.Origin).GetHashCode();
}
}
/// <summary>
/// Create HashSet from IEnumerable given selector and comparer.
/// http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/31/c.net-toolbox-adding-a-tohashset-extension-method.aspx
/// </summary>
public static HashSet<TElement> ToHashSet<TSource, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TElement> comparer)
{
if (source == null)
throw new ArgumentNullException("source");
if (elementSelector == null)
throw new ArgumentNullException("elementSelector");
// you can unroll this into a foreach if you want efficiency gain, but for brevity...
return new HashSet<TElement>(
source.Select(elementSelector), comparer);
}
/// <summary>
/// Create a HashSet of TSource from an IEnumerable
/// of TSource using the identity selector and
/// default equality comparer.
/// </summary>
public static HashSet<TSource> ToHashSet<TSource>(
this IEnumerable<TSource> source)
{
// key selector is identity fxn and null is default comparer
return source.ToHashSet<TSource, TSource>(
item => item, null);
}
/// <summary>
/// Get distinct connectors from a set of MEP elements.
/// </summary>
public static HashSet<Connector> GetDistinctConnectors(
List<Connector> cons)
{
return cons.Distinct(new ConnectorXyzComparer()).ToHashSet();
}
#endregion // MEP utilities
}
public class KdcsFailureHandler : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
Document doc = failuresAccessor.GetDocument();
foreach (var failureMessageAccessor in failuresAccessor.GetFailureMessages())
{
FailureDefinitionId failureDefinitionId = failureMessageAccessor.GetFailureDefinitionId();
if (failureDefinitionId == BuiltInFailures.InaccurateFailures.InaccurateLine)
{
failuresAccessor.DeleteWarning(failureMessageAccessor);
}
}
return FailureProcessingResult.Continue;
}
}
}