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(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 elements = a .Where(x => x.Name.Equals(name)) .Cast() .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); } /// /// 주어진 Z축으로 나머지 X,Y축을 구한다. /// /// /// /// 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 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 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 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 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); } /// /// Return signed distance from plane to a given point. /// 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; } /// /// 두 점(p,q) 사이의 가운데 점을 넘겨준다. /// /// /// /// 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 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 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 /// /// 주어진 점에서 법선벡터 방향에 위치한 벽면 중 가강 멀리 떨어져 있는 벽의 면을 넘겨준다. /// 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 GetFaces(Element e) { Options opt = new Options(); opt.ComputeReferences = true; IEnumerable faces = e .get_Geometry(opt) .OfType() .First() .Faces .OfType(); return faces; } /// /// 파이프의 시작점과 끝점을 구한다. /// /// /// /// /// 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; } /// /// 플렉시블 파이프의 시작점과 끝점을 구한다. /// /// /// /// /// 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; } /// /// 플렉시블 덕트의 시작점과 끝점을 구한다. /// /// /// /// /// 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 PerpendicularDirs(Autodesk.Revit.DB.XYZ dir, int count) { List dirs = new List(); 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 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 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 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); } /// /// Return the given element's connector manager, /// using either the family instance MEPModel or /// directly from the MEPCurve connector manager /// for ducts and pipes. /// 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 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 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 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; } /// /// The status of line-plane intersection /// public enum Plane_Line { /// /// Line is completely inside the plane /// Subset, /// /// Line is parallel to the plane /// Disjoint, /// /// Line is intersecting with the plane /// Intersecting } /// /// Compute Plane-Line intersection /// /// This plane /// Line to intersect with /// Tolerance /// The intersection point, Null if it does not exist /// The parameter of the intersection point on the line /// 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 GetFacesAll(UIDocument uiDocument, Element element) { List list = new List(); 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 Enum = element2.GetEnumerator(); //GeometryObjectArray gObjects = null; List gObjects = new List(); 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 GetInstanceFacesAll(UIDocument uiDocument, Element element) { List list = new List(); 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 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 GetElementConnectors(Element elem) { List ConLst = new List(); 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; } /// /// 패밀리와 기준 배관으로 분기 커넥터 구하기 /// /// T 또는 cross /// 기준 파이프 /// public static List GetBranchConnector(FamilyInstance family, Pipe DirPipe) { List branchConLst = new List(); //기준 파이프 시작-끝,끝-시작 방향 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 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; } /// /// Tee Cross 가지 커넥터 구하기 /// /// /// public static List GetBranchConnector(FamilyInstance family) { List branchConLst = new List(); List conLst = GetElementConnectors(family); foreach (Connector con in conLst) { if (con.Angle == 0) continue; branchConLst.Add(con); } return branchConLst; } /// /// 부속류 티 크로스 등 기준커넥터 방향의 반대 커넥터 구하기. /// /// 엘보 부속류 /// 기준 커넥터 /// public static Connector GetDirectionConnector(FamilyInstance family, Connector StdCon) { Connector dirCon = null; if (family == null || StdCon == null) return null; List 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 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; } /// /// 파이프에 라우팅된 심볼 구하기. /// /// /// 라우팅 심볼 가져올 파이프의 pipeType /// 라우팅 패밀리 유형 /// 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 MainConLst = Util.GetElementConnectors(MainElem); List 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 MainCon1Lst = Util.GetElementConnectors(doc.GetElement(DivideID)); List 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 CreatePipe(UIApplication uiapp, Document document, List 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 pipes = new List(); List newLineLst = new List(); List ElemLst = new List(); 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 elePipe = new List(); 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; } /// /// 모델라인 작도 후 파이프 그리면 세로로 그리기 안되서 Line.CreateBound로 라인그림 /// /// /// /// 파이프 점들 /// 파이프 시스템타입 /// 파이프 타입 /// 작도 레벨 /// public static List CreatePipe2(UIApplication uiapp, Document document, List 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 pipes = new List(); List newLineLst = new List(); 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 elePipe = new List(); 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 CreatePipe(UIApplication uiapp, Document document, List 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 pipes = new List(); List newLineLst = new List(); List ElemLst = new List(); 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 elePipe = new List(); 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 CreateFlexPipe(UIApplication uiapp, Document document, List pts, ElementId SystemTypeId, ElementId pipeTypeId, ElementId DrawLevel) { Autodesk.Revit.DB.View view = document.ActiveView; //Level level = document.ActiveView.GenLevel; ICollection FlexPipeTypeLst = new FilteredElementCollector(document).OfClass(typeof(FlexPipeType)).ToElements(); FlexPipeType fpt = FlexPipeTypeLst.First() as FlexPipeType; FlexPipe newpipe = null; List pipes = new List(); List newLineLst = new List(); List ElemLst = new List(); try { List elePipe = new List(); 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 symbols = new List(new FilteredElementCollector(doc) .OfCategory(BuiltInCategory.OST_PipeFitting) .OfClass(typeof(FamilySymbol)) .OfType() .Where( 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 DivideElement(Document doc, Pipe MainPipe, XYZ DirectPt) { List DivideElementLst = new List(); 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 DivideElement(Document doc, Duct MainDuct, XYZ DirectPt) { List DivideElementLst = new List(); 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 GetFamilySymbols(Document doc, Autodesk.Revit.DB.Family family) { List list = new List(); 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 getFamily(Document doc, string categori) { List familySymbol = new List(); List fiCreationDatas = new List(); ElementSet elementSet = null; //Try to get a FamilySymbol FilteredElementCollector collector = new FilteredElementCollector(doc); ICollection 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 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 GetSelectedElements(Autodesk.Revit.UI.UIDocument uidoc) { List list = new List(); 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 GetLibrary(string subFolder, bool withExtension = false) { List list = new List(); 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(this List list, int index1, int index2) { T temp = list[index1]; list[index1] = list[index2]; list[index2] = temp; } public static void Swap(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 GetPipeSegmentSizes(Document doc, string pipeTypeName) { List m_pipeDiaList = new List(); ICollection 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; } /// /// 파이프 단열제 두께 구하기 /// /// /// public static double GetPipeInsulationThickness(Document doc, Pipe pipe) { double insulThk = 0; ICollection 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; } /// /// 파이프 단열재 두께 바꾸기 /// /// /// /// /// public static void SetPipeInsulationThickness(Document doc, Pipe pipe, double thickness) { ICollection 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 PipeinsulationCollection = new FilteredElementCollector(doc) .OfClass(typeof(PipeInsulationType)) .OfType() .ToList(); //단열재 생셩 PipeInsulation.Create(doc, pipe.Id, PipeinsulationCollection.First().Id, thickness); } } /// /// string으로 레벨 찾기 /// /// /// /// public static Level GetLevel(Document doc, string LevelName) { Level resLevel = null; FilteredElementCollector lvlCollector = new FilteredElementCollector(doc); ICollection 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; } /// /// 간격띄우기 값으로 레벨 찾기. /// /// /// /// public static Level GetLevel(Document doc, double elevatiopn) { Level resLevel = null; FilteredElementCollector lvlCollector = new FilteredElementCollector(doc); var lstLevel = lvlCollector.OfClass(typeof(Level)).ToElements().Cast().ToList(); var sortedLevels = lstLevel.OrderByDescending(el => el.Elevation); foreach (Level lvl in sortedLevels) { if (lvl.Elevation <= elevatiopn) { resLevel = lvl; break; } } return resLevel; } /// /// 간격띄우기 값이 주어진 허용오차 이내에 있는 레벨 찾기. /// /// /// /// 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().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; } /// /// 패밀리 로드 /// /// /// 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 fam_ids = fam.GetFamilySymbolIds(); List fam_sym_names = new List(); if (fam_ids.Count() == 0) return null; gotSymbol = (FamilySymbol)doc.GetElement(fam_ids.ElementAt(0)); } return gotSymbol; } /// /// 패밀리 로드 /// /// /// 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 fam_ids = fam.GetFamilySymbolIds(); List fam_sym_names = new List(); if (fam_ids.Count() == 0) return null; gotSymbol = (FamilySymbol)doc.GetElement(fam_ids.ElementAt(0)); } return gotSymbol; } /// /// 패밀리 존재 여부 검토 /// /// /// /// public static FamilySymbol getNameByFamily(Document doc, string name) { List fiCreationDatas = new List(); //Try to get a FamilySymbol FilteredElementCollector collector = new FilteredElementCollector(doc); ICollection 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; } /// /// 매개 변수 정의를 반환합니다. /// 주어진 요소와 매개 변수 이름. /// public static Definition GetDefinition(Element elem, string parameter_name) { IList 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; } /// /// Implement a comparison operator for lines /// in the XY plane useful for sorting into /// groups of parallel lines. /// 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; } /// /// Predicate to test whewther two points or /// vectors can be considered equal with the /// given tolerance. /// public static bool IsEqual( XYZ p, XYZ q, double tolerance = _eps) { return 0 == Compare(p, q, tolerance); } /// /// Return true if the given bounding box bb /// contains the given point p in its interior. /// public static bool BoundingBoxXyzContains( BoundingBoxXYZ bb, XYZ p) { return 0 < Compare(bb.Min, p) && 0 < Compare(p, bb.Max); } /// /// Return true if the vectors v and w /// are non-zero and perpendicular. /// 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); } /// /// Minimum slope for a vector to be considered /// to be pointing upwards. Slope is simply the /// relationship between the vertical and /// horizontal components. /// const double _minimumSlope = 0.3; /// /// Return true if the Z coordinate of the /// given vector is positive and the slope /// is larger than the minimum limit. /// 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 ); } /// /// Return the maximum value from an array of real numbers. /// 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 /// /// Base units currently used internally by Revit. /// 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; /// /// Convert a given length in feet to millimetres. /// public static double FootToMm(double length) { return length * _footToMm; } /// /// Convert a given length in feet to millimetres, /// rounded to the closest millimetre. /// public static int FootToMmInt(double length) { //return (int) ( _feet_to_mm * d + 0.5 ); return (int)Math.Round(_footToMm * length, MidpointRounding.AwayFromZero); } /// /// Convert a given length in feet to metres. /// public static double FootToMetre(double length) { return length * _footToMeter; } /// /// Convert a given length in millimetres to feet. /// public static double MmToFoot(double length) { return length / _footToMm; } /// /// Convert a given point or vector from millimetres to feet. /// public static XYZ MmToFoot(XYZ v) { return v.Divide(_footToMm); } /// /// Convert a given volume in feet to cubic meters. /// public static double CubicFootToCubicMeter(double volume) { return volume * _cubicFootToCubicMeter; } /// /// Hard coded abbreviations for the first 26 /// DisplayUnitType enumeration values. /// 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 /// /// 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. /// public static string PluralSuffix(int n) { return 1 == n ? "" : "s"; } /// /// Return an English plural suffix 'ies' or /// 'y' for the given number of items. /// public static string PluralSuffixY(int n) { return 1 == n ? "y" : "ies"; } /// /// Return a dot (full stop) for zero /// or a colon for more than zero. /// public static string DotOrColon(int n) { return 0 < n ? ":" : "."; } /// /// Return a string for a real number /// formatted to two decimal places. /// public static string RealString(double a) { return a.ToString("0.##"); } /// /// Return a hash string for a real number /// formatted to nine decimal places. /// public static string HashString(double a) { return a.ToString("0.#########"); } /// /// Return a string representation in degrees /// for an angle given in radians. /// public static string AngleString(double angle) { return RealString(angle * 180 / Math.PI) + " degrees"; } /// /// Return a string for a length in millimetres /// formatted as an integer value. /// public static string MmString(double length) { //return RealString( FootToMm( length ) ) + " mm"; return Math.Round(FootToMm(length)) .ToString() + " mm"; } /// /// Return a string for a UV point /// or vector with its coordinates /// formatted to two decimal places. /// 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)); } /// /// Return a string for an XYZ point /// or vector with its coordinates /// formatted to two decimal places. /// 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)); } /// /// Return a hash string for an XYZ point /// or vector with its coordinates /// formatted to nine decimal places. /// public static string HashString(XYZ p) { return string.Format("({0},{1},{2})", HashString(p.X), HashString(p.Y), HashString(p.Z)); } /// /// Return a string for this bounding box /// with its coordinates formatted to two /// decimal places. /// 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. /// 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)); } /// /// Return a string for this plane /// with its coordinates formatted to two /// decimal places. /// public static string PlaneString(Plane p) { return string.Format("plane origin {0}, plane normal {1}", PointString(p.Origin), PointString(p.Normal)); } /// /// Return a string for this transformation /// with its coordinates formatted to two /// decimal places. /// 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)); } /// /// Return a string for a list of doubles /// formatted to two decimal places. /// public static string DoubleArrayString( IEnumerable a, bool onlySpaceSeparator = false) { string separator = onlySpaceSeparator ? " " : ", "; return string.Join(separator, a.Select( x => RealString(x))); } /// /// Return a string for this point array /// with its coordinates formatted to two /// decimal places. /// public static string PointArrayString( IEnumerable pts, bool onlySpaceSeparator = false) { string separator = onlySpaceSeparator ? " " : ", "; return string.Join(separator, pts.Select(p => PointString(p, onlySpaceSeparator))); } /// /// Return a string for this point array /// with its coordinates formatted to two /// decimal places. /// public static string PointArrayString( IEnumerable pts, bool onlySpaceSeparator = false) { string separator = onlySpaceSeparator ? " " : ", "; return string.Join(separator, pts.Select(p => PointString(p, onlySpaceSeparator))); } /// /// Return a string representing the data of a /// curve. Currently includes detailed data of /// line and arc elements only. /// 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; } /// /// Return a string for this curve with its /// tessellated point coordinates formatted /// to two decimal places. /// public static string CurveTessellateString( Curve curve) { return "curve tessellation " + PointArrayString(curve.Tessellate()); } /// /// Convert a UnitSymbolType enumeration value /// to a brief human readable abbreviation string. /// //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 /// /// Return the given element's connector manager, /// using either the family instance MEPModel or /// directly from the MEPCurve connector manager /// for ducts and pipes. /// 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; } /// /// Return the element's connector at the given /// location, and its other connector as well, /// in case there are exactly two of them. /// /// An element, e.g. duct, pipe or family instance /// The location of one of its connectors /// The other connector, in case there are just two of them /// The connector at the given location 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; } /// /// Return the connector set element /// closest to the given point. /// 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; } /// /// Return the connector on the element /// closest to the given point. /// public static Connector GetConnectorClosestTo( Element e, XYZ p) { ConnectorManager cm = GetConnectorManager(e); return null == cm ? null : GetConnectorClosestTo(cm.Connectors, p); } /// /// Connect two MEP elements at a given point p. /// /// Thrown if /// one of the given elements lacks connectors. /// 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 ); } /// /// Compare Connector objects based on their location point. /// public class ConnectorXyzComparer : IEqualityComparer { 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(); } } /// /// 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 /// public static HashSet ToHashSet( this IEnumerable source, Func elementSelector, IEqualityComparer 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( source.Select(elementSelector), comparer); } /// /// Create a HashSet of TSource from an IEnumerable /// of TSource using the identity selector and /// default equality comparer. /// public static HashSet ToHashSet( this IEnumerable source) { // key selector is identity fxn and null is default comparer return source.ToHashSet( item => item, null); } /// /// Get distinct connectors from a set of MEP elements. /// public static HashSet GetDistinctConnectors( List 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; } } }