using System; using System.Collections.Generic; using System.Linq; using System.Text; using WinForms = System.Windows.Forms; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.UI.Selection; using System.Diagnostics; using System.IO; using Autodesk.Revit.Creation; using Microsoft.Win32; namespace COME4Revit { class Util { //레지스트리 가져오기 public static string getReg(string regKey) { RegistryKey reg = Registry.CurrentUser; reg = reg.OpenSubKey("Software\\DCS_COME\\CO-ME4Revit\\1.0", true); if (reg == null) return ""; else return Convert.ToString(reg.GetValue(regKey)); } //레지스트리 쓰기 public static void setReg(string regKey, string regVal) { RegistryKey reg = Registry.CurrentUser; reg = reg.CreateSubKey("Software\\DCS_COME\\CO-ME4Revit\\1.0", RegistryKeyPermissionCheck.ReadWriteSubTree); reg.SetValue(regKey, regVal, RegistryValueKind.String); reg.Close(); } // 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 static double RTD(double rads) { return rads * (180.0 / kPi); } public static double DTR(double degrees) { return degrees * (kPi / 180.0); } public static XYZ GetMidPoint(XYZ pt1, XYZ pt2) { XYZ ptMid = pt1 + (pt2 - pt1) * 0.5; return ptMid; } public static XYZ GetMiddlePointOfCurve(Curve curve) { return curve.Evaluate(0.5, true); } 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; } public static XYZ GetPointOnLine(Curve line, XYZ point) { XYZ xYZPoint = null; IntersectionResult result = line.Project(point); if ((result != null) && (result.XYZPoint != null)) { xYZPoint = result.XYZPoint; } return xYZPoint; } /// /// 파이프의 시작점 끝점을 넘겨준다. /// /// /// /// /// 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; bRC = GetStartEndPoint(lc, ref startPoint, ref endPoint); return bRC; } /// /// 커브의 시작점과 끝점을 넘겨준다. /// /// /// /// /// public static bool GetStartEndPoint(LocationCurve lc, ref XYZ startPoint, ref XYZ endPoint) { bool bRC = false; if (lc != null) { startPoint = lc.Curve.GetEndPoint(0); endPoint = lc.Curve.GetEndPoint(1); bRC = true; } return bRC; } /// /// 한 점에서 평면에 가장 가까운 점을 구한다. /// /// 평면 /// 한 점 /// public static XYZ PlaneProject(Plane plane, XYZ p ) { // signedDistanceTo( p ); double[,] xform = new double[3, 3]; XYZ normal=plane.Normal; xform[0,0] = 1.0 - normal.X * normal.X; xform[0,1] = -normal.X * normal.Y; xform[0,2] = -normal.X * normal.Z; xform[1,0] = -normal.Y * normal.X; xform[1,1] = 1.0 - normal.Y * normal.Y; xform[1,2] = -normal.Y * normal.Z; xform[2,0] = -normal.Z * normal.X; xform[2,1] = -normal.Z * normal.Y; xform[2,2] = 1.0 - normal.Z * normal.Z; double[] ptTmp = new double[3]; for (int iRow = 0; iRow < 3; iRow++) { ptTmp[iRow] = xform[iRow, 0] * p[0] + xform[iRow, 1] * p[1] + xform[iRow, 2] * p[2]; } return new XYZ(ptTmp[0], ptTmp[1], ptTmp[2]); } public static ModelArc NewModelArc(UIApplication app, SketchPlane plane, Autodesk.Revit.DB.XYZ ptE1, Autodesk.Revit.DB.XYZ ptE2, Autodesk.Revit.DB.XYZ ptOnCurve) { ModelArc arc = null; try { Autodesk.Revit.Creation.Application creApp = app.Application.Create; Arc line = Arc.Create(ptE1, ptE2, ptOnCurve); arc= (ModelArc)app.ActiveUIDocument.Document.Create.NewModelCurve(line, plane); } catch (Exception) { } return arc; } public static DetailCurve NewDetailLine(UIApplication app, Autodesk.Revit.DB.XYZ startPoint, Autodesk.Revit.DB.XYZ endPoint) { try { Autodesk.Revit.DB.Document doc = app.ActiveUIDocument.Document; View view = doc.ActiveView; Autodesk.Revit.Creation.Application creApp = app.Application.Create; XYZ sp = PlaneProject(view.SketchPlane.GetPlane(), startPoint); XYZ ep = PlaneProject(view.SketchPlane.GetPlane(), endPoint); Line line = Line.CreateBound(sp, ep); return doc.Create.NewDetailCurve(view, line); } catch (Exception ex) { string strMsg = ex.Message; return null; } } #region Geometrical Comparison 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) { return tolerance > Math.Abs(a); } public static bool IsZero(double a) { return IsZero(a, _eps); } public static bool IsEqual(double a, double b) { return IsZero(b - a); } public static int Compare(double a, double b) { return IsEqual(a, b) ? 0 : (a < b ? -1 : 1); } public static int Compare(XYZ p, XYZ q) { int diff = Compare(p.X, q.X); if (0 == diff) { diff = Compare(p.Y, q.Y); if (0 == diff) { diff = Compare(p.Z, q.Z); } } return diff; } 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 IsVertical(CylindricalFace f) { return IsVertical(f.Axis); } /// /// Return the maximum value from an array of real numbers. /// public static double Max(double[] a) { Debug.Assert(1 == a.Rank, "expected one-dimensional array"); Debug.Assert(0 == a.GetLowerBound(0), "expected zero-based array"); Debug.Assert(0 < a.GetUpperBound(0), "expected non-empty array"); double max = a[0]; for (int i = 1; i <= a.GetUpperBound(0); ++i) { if (max < a[i]) { max = a[i]; } } return max; } #endregion // Geometrical Comparison #region Unit Handling const double _convertFootToMm = 12 * 25.4; const double _convertFootToMeter = _convertFootToMm * 0.001; const double _convertCubicFootToCubicMeter = _convertFootToMeter * _convertFootToMeter * _convertFootToMeter; /// /// Convert a given length in feet to millimetres. /// public static double FootToMm(double length) { return length * _convertFootToMm; } /// /// Convert a given length in millimetres to feet. /// public static double MmToFoot(double length) { return length / _convertFootToMm; } /// /// Convert a given volume in feet to cubic meters. /// public static double CubicFootToCubicMeter(double volume) { return volume * _convertCubicFootToCubicMeter; } #endregion // Unit Handling #region Formatting /// /// Return an English plural suffix 's' or /// nothing for the given number of items. /// public static string PluralSuffix(int n) { return 1 == n ? "" : "s"; } /// /// Return an English plural suffix 'ies' or /// 'y' for the given number of items. /// public static string PluralSuffixY(int n) { return 1 == n ? "y" : "ies"; } public static string DotOrColon(int n) { return 0 < n ? ":" : "."; } public static string RealString(double a) { return a.ToString("0.##"); } public static string AngleString(double angle) { return RealString(angle * 180 / Math.PI) + " degrees"; } public static string MmString(double length) { return RealString(FootToMm(length)) + " mm"; } public static string PointString(UV p) { return string.Format("({0},{1})", RealString(p.U), RealString(p.V)); } public static string PointString(XYZ p) { return string.Format("({0},{1},{2})", RealString(p.X), RealString(p.Y), RealString(p.Z)); } public static string PlaneString(Plane p) { return string.Format("plane origin {0}, plane normal {1}", PointString(p.Origin), PointString(p.Normal)); } 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)); } public static string PointArrayString(IList pts) { string s = string.Empty; foreach (XYZ p in pts) { if (0 < s.Length) { s += ", "; } s += PointString(p); } return s; } public static string CurveString(Curve curve) { return "curve tesselation " + PointArrayString(curve.Tessellate()); } #endregion // Formatting #region Display a message const string _caption = "DCS Tools"; public static void InfoMsg(string msg) { Debug.WriteLine(msg); WinForms.MessageBox.Show(msg, _caption, WinForms.MessageBoxButtons.OK, WinForms.MessageBoxIcon.Information); } public static void ErrorMsg(string msg) { Debug.WriteLine(msg); WinForms.MessageBox.Show(msg, _caption, WinForms.MessageBoxButtons.OK, WinForms.MessageBoxIcon.Error); } public static string ElementDescription(Element e) { if (null == e) { return ""; } // for a wall, the element name equals the // wall type name, which is equivalent to the // family name ... FamilyInstance fi = e as FamilyInstance; string fn = (null == fi) ? string.Empty : fi.Symbol.Family.Name + " "; string cn = (null == e.Category) ? e.GetType().Name : e.Category.Name; return string.Format("{0} {1}<{2} {3}>", cn, fn, e.Id.IntegerValue, e.Name); } #endregion // Display a message public static Element GetElement(Autodesk.Revit.DB.Document document, int id) { ElementId id2 = new ElementId(id); return document.GetElement(id2); } public static Element GetElement(ExternalCommandData commandData, int id) { ElementId id2 = new ElementId(id); return commandData.Application.ActiveUIDocument.Document.GetElement(id2); } public static XYZ GetCurveNormal(Curve curve) { IList pts = curve.Tessellate(); int n = pts.Count; Debug.Assert(1 < n, "expected at least two points " + "from curve tessellation"); XYZ p = pts[0]; XYZ q = pts[n - 1]; XYZ v = q - p; XYZ w, normal = null; if (2 == n) { Debug.Assert(curve is Line, "expected non-line element to have " + "more than two tessellation points"); // for non-vertical lines, use Z axis to // span the plane, otherwise Y axis: double dxy = Math.Abs(v.X) + Math.Abs(v.Y); w = (dxy > Util.TolPointOnPlane) ? XYZ.BasisZ : XYZ.BasisY; normal = v.CrossProduct(w).Normalize(); } else { int i = 0; while (++i < n - 1) { w = pts[i] - p; normal = v.CrossProduct(w); if (!normal.IsZeroLength()) { normal = normal.Normalize(); break; } } #if DEBUG { XYZ normal2; while (++i < n - 1) { w = pts[i] - p; normal2 = v.CrossProduct(w); Debug.Assert(normal2.IsZeroLength() || Util.IsZero(normal2.AngleTo(normal)), "expected all points of curve to " + "lie in same plane"); } } #endif // DEBUG } return normal; } public static Element SelectSingleElement( UIDocument doc, string description) { Selection sel = doc.Selection; Reference r = null; try { r = sel.PickObject(ObjectType.Element, description); } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { r = null; } return null == r ? null : doc.Document.GetElement(r); } static bool HasRequestedType( Element e, Type t, bool acceptDerivedClass) { return (null != e) && (acceptDerivedClass ? e.GetType().IsSubclassOf(t) : e.GetType().Equals(t)); } public static string GetFileName(string fileName, string subFolder, bool deleteIfExist) { string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\" + "DCS.CO.KR" + @"\" + "CO-ME4Revit" + @"\" + subFolder; 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 str3 = path + @"\" + fileName; if (File.Exists(str3) && deleteIfExist) { File.Delete(str3); } return str3; } public static double GetSignedPolygonArea(List p) { int n = p.Count; int j = 0; double sum = 0; for (int i = 0; i < n ; i++) { j = (i + 1) % n; sum += (p[i].U * p[j].V - p[j].U * p[i].V); } return 0.5 * sum; } public static UV GetSignedPolygonCenter(List p) { int n = p.Count; int j = 0; double centerx = 0; double centery = 0; for (int i = 0; i < n ; i++) { j = (i + 1) % n; centerx += ((p[i].U + p[j].U) * ((p[i].U * p[j].V) - (p[j].U * p[i].V))); centery += ((p[i].V + p[j].V) * ((p[i].U * p[j].V) - (p[j].U * p[i].V))); } UV center = new UV(centerx, centery); return center; } 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) { } catch { } return bRC; } /// /// 주어진 점들로 이루어진 폴리곤의 면적을 넘겨준다. /// /// 폴리곤 점들 /// 표시 단위 /// public static double GetArea(List pts, DisplayUnitType dut) { List lstUV = new List(); foreach (XYZ curPt in pts) { lstUV.Add(new UV(curPt.X, curPt.Y)); } lstUV.Add(new UV(pts[0].X, pts[1].Y)); // dut = DisplayUnitType.DUT_SQUARE_METERS double area = Unit.CovertFromAPI(dut, Util.GetSignedPolygonArea(lstUV)); return area; } } }