3878 lines
133 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
}
|