725 lines
21 KiB
C#
725 lines
21 KiB
C#
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;
|
|
}
|
|
|
|
|
|
/// <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;
|
|
|
|
bRC = GetStartEndPoint(lc, ref startPoint, ref endPoint);
|
|
return bRC;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 커브의 시작점과 끝점을 넘겨준다.
|
|
/// </summary>
|
|
/// <param name="lc"></param>
|
|
/// <param name="startPoint"></param>
|
|
/// <param name="endPoint"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 한 점에서 평면에 가장 가까운 점을 구한다.
|
|
/// </summary>
|
|
/// <param name="plane">평면</param>
|
|
/// <param name="p">한 점</param>
|
|
/// <returns></returns>
|
|
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);
|
|
}
|
|
|
|
/// <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
|
|
const double _convertFootToMm = 12 * 25.4;
|
|
|
|
const double _convertFootToMeter
|
|
= _convertFootToMm * 0.001;
|
|
|
|
const double _convertCubicFootToCubicMeter
|
|
= _convertFootToMeter
|
|
* _convertFootToMeter
|
|
* _convertFootToMeter;
|
|
|
|
/// <summary>
|
|
/// Convert a given length in feet to millimetres.
|
|
/// </summary>
|
|
public static double FootToMm(double length)
|
|
{
|
|
return length * _convertFootToMm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a given length in millimetres to feet.
|
|
/// </summary>
|
|
public static double MmToFoot(double length)
|
|
{
|
|
return length / _convertFootToMm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a given volume in feet to cubic meters.
|
|
/// </summary>
|
|
public static double CubicFootToCubicMeter(double volume)
|
|
{
|
|
return volume * _convertCubicFootToCubicMeter;
|
|
}
|
|
#endregion // Unit Handling
|
|
|
|
#region Formatting
|
|
/// <summary>
|
|
/// Return an English plural suffix 's' or
|
|
/// nothing for the given number of items.
|
|
/// </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";
|
|
}
|
|
|
|
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<XYZ> 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 "<null>";
|
|
}
|
|
// 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<XYZ> 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<UV> 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<UV> 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;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 주어진 점들로 이루어진 폴리곤의 면적을 넘겨준다.
|
|
/// </summary>
|
|
/// <param name="pts">폴리곤 점들</param>
|
|
/// <param name="dut">표시 단위</param>
|
|
/// <returns></returns>
|
|
public static double GetArea(List<XYZ> pts, DisplayUnitType dut)
|
|
{
|
|
List<UV> lstUV = new List<UV>();
|
|
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;
|
|
}
|
|
|
|
|
|
}
|
|
}
|