// // (C) Copyright 2003-2023 by Autodesk, Inc. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted, // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. // namespace Revit.SDK.Samples.CreateComplexAreaRein.CS { using System; using System.Collections.Generic; using Autodesk.Revit.DB; using GeoElement = Autodesk.Revit.DB.GeometryElement; using GeoSolid = Autodesk.Revit.DB.Solid; using Element = Autodesk.Revit.DB.Element; /// /// provide some common geometry judgement and calculate method /// class GeomUtil { const double PRECISION = 0.00001; //precision when judge whether two doubles are equal /// /// get all faces that compose the geometry solid of given element /// /// element to be calculated /// all faces public static FaceArray GetFaces(Element elem) { List faces = new List(); Autodesk.Revit.DB.Options geoOptions = Command.CommandData.Application.Application.Create.NewGeometryOptions(); geoOptions.ComputeReferences = true; GeoElement geoElem = elem.get_Geometry(geoOptions); //GeometryObjectArray geoElems = geoElem.Objects; IEnumerator Objects = geoElem.GetEnumerator(); //foreach (object o in geoElems) while (Objects.MoveNext()) { object o = Objects.Current; GeoSolid geoSolid = o as GeoSolid; if (null == geoSolid) { continue; } return geoSolid.Faces; } return null; } /// /// get all points proximate to the given face /// /// face to be calculated /// public static List GetPoints(Face face) { List points = new List(); List XYZs = face.Triangulate().Vertices as List; foreach (Autodesk.Revit.DB.XYZ point in XYZs) { points.Add(point); } return points; } /// /// judge whether the given face is horizontal /// /// face to be judged /// is horizontal public static bool IsHorizontalFace(Face face) { List points = GetPoints(face); double z1 = points[0].Z; double z2 = points[1].Z; double z3 = points[2].Z; double z4 = points[3].Z; bool flag = IsEqual(z1, z2); flag = flag && IsEqual(z2, z3); flag = flag && IsEqual(z3, z4); flag = flag && IsEqual(z4, z1); return flag; } /// /// judge whether a face and a line are parallel /// /// /// /// public static bool IsParallel(Face face, Line line) { List points = GetPoints(face); Autodesk.Revit.DB.XYZ vector1 = SubXYZ(points[0], points[1]); Autodesk.Revit.DB.XYZ vector2 = SubXYZ(points[1], points[2]); Autodesk.Revit.DB.XYZ refer = SubXYZ(line.GetEndPoint(0), line.GetEndPoint(1)); Autodesk.Revit.DB.XYZ cross = CrossMatrix(vector1, vector2); double result = DotMatrix(cross, refer); if (result < PRECISION) { return true; } return false; } /// /// judge whether given 4 lines can form a rectangular /// /// /// is rectangular public static bool IsRectangular(IList curves) { //make sure the CurveArray contains 4 line if (curves.Count != 4) { return false; } Line[] lines = new Line[4]; for (int i = 0; i < 4; i++) { lines[i] = curves[i] as Line; if (null == lines[i]) { return false; } } //make sure the first line is vertical to 2 lines and parallel to another line Line iniLine = lines[0]; Line[] verticalLines = new Line[2]; Line paraLine = null; int index = 0; for (int i = 1; i < 4; i++) { if (IsVertical(lines[0], lines[i])) { verticalLines[index] = lines[i]; index++; } else { paraLine = lines[i]; } } if (index != 2) { return false; } bool flag = IsVertical(paraLine, verticalLines[0]); return flag; } /// /// get the length of the given line /// /// /// length public static double GetLength(Line line) { Autodesk.Revit.DB.XYZ sub = SubXYZ(line.GetEndPoint(0), line.GetEndPoint(1)); double length = Math.Sqrt(sub.X * sub.X + sub.Y * sub.Y + sub.Z * sub.Z); return length; } /// /// get parallel line with give distance with given line in XY plane /// /// given line /// distance from given line /// paralleled line public static Line GetXYParallelLine(Line inLine, double distance) { Autodesk.Revit.DB.XYZ direct = SubXYZ(inLine.GetEndPoint(1), inLine.GetEndPoint(0)); double length = Math.Sqrt((-direct.Y) * (-direct.Y) + direct.X * direct.X); double temp = distance / length; Autodesk.Revit.DB.XYZ dPerp = new XYZ(-direct.Y * temp, direct.X * temp, 0.0); Autodesk.Revit.DB.XYZ startPoint = AddXYZ(inLine.GetEndPoint(0), dPerp); Autodesk.Revit.DB.XYZ endPoint = AddXYZ(inLine.GetEndPoint(1), dPerp); Line outLine = Line.CreateBound(startPoint, endPoint); //Line outLine = new Line(ref startPoint, ref endPoint); return outLine; } /// /// Get scaled line which has both the same center and direction with give line /// /// given line /// scale value /// scaled line public static Line GetScaledLine(Line inLine, double scale) { Autodesk.Revit.DB.XYZ startPoint = inLine.GetEndPoint(0); Autodesk.Revit.DB.XYZ endPoint = inLine.GetEndPoint(1); Autodesk.Revit.DB.XYZ temp1 = SubXYZ(endPoint, startPoint); Autodesk.Revit.DB.XYZ temp2 = MultiXYZ(temp1, (scale - 1) / 2); Autodesk.Revit.DB.XYZ startPoint2 = SubXYZ(startPoint, temp2); Autodesk.Revit.DB.XYZ endPoint2 = AddXYZ(endPoint, temp2); Line outLine = Line.CreateBound(startPoint2, endPoint2); //Line outLine = new Line(ref startPoint2, ref endPoint2); return outLine; } /// /// judge whether two lines are vertical /// /// /// /// private static bool IsVertical(Line line1, Line line2) { Autodesk.Revit.DB.XYZ vector1 = SubXYZ(line1.GetEndPoint(0), line1.GetEndPoint(1)); Autodesk.Revit.DB.XYZ vector2 = SubXYZ(line2.GetEndPoint(0), line2.GetEndPoint(1)); double result = DotMatrix(vector1, vector2); if (Math.Abs(result) < PRECISION) { return true; } return false; } /// /// subtraction of two Autodesk.Revit.DB.XYZ as Matrix /// /// /// /// private static Autodesk.Revit.DB.XYZ SubXYZ(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { double x = p1.X - p2.X; double y = p1.Y - p2.Y; double z = p1.Z - p2.Z; Autodesk.Revit.DB.XYZ result = new Autodesk.Revit.DB.XYZ(x, y, z); return result; } /// /// add two XYZ /// /// /// /// private static Autodesk.Revit.DB.XYZ AddXYZ(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { double x = p1.X + p2.X; double y = p1.Y + p2.Y; double z = p1.Z + p2.Z; Autodesk.Revit.DB.XYZ result = new Autodesk.Revit.DB.XYZ(x, y, z); return result; } /// /// multiply Autodesk.Revit.DB.XYZ with a double /// /// /// /// private static Autodesk.Revit.DB.XYZ MultiXYZ(Autodesk.Revit.DB.XYZ p1, double para) { double x = p1.X * para; double y = p1.Y * para; double z = p1.Z * para; Autodesk.Revit.DB.XYZ result = new Autodesk.Revit.DB.XYZ(x, y, z); return result; } /// /// multiplication cross of two Autodesk.Revit.DB.XYZ as Matrix /// /// /// /// private static Autodesk.Revit.DB.XYZ CrossMatrix(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { double v1 = p1.X; double v2 = p1.Y; double v3 = p1.Z; double u1 = p2.X; double u2 = p2.Y; double u3 = p2.Z; double x = v3 * u2 - v2 * u3; double y = -v3 * u1 + v1 * u3; double z = v2 * u1 - v1 * u2; Autodesk.Revit.DB.XYZ point = new Autodesk.Revit.DB.XYZ(x, y, z); return point; } /// /// dot product of two Autodesk.Revit.DB.XYZ as Matrix /// /// /// /// private static double DotMatrix(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { double v1 = p1.X; double v2 = p1.Y; double v3 = p1.Z; double u1 = p2.X; double u2 = p2.Y; double u3 = p2.Z; double result = v1 * u1 + v2 * u2 + v3 * u3; return result; } /// /// judge whether the subtraction of two doubles is less than the internal decided precision /// /// /// /// private static bool IsEqual(double d1, double d2) { double diff = Math.Abs(d1 - d2); if (diff < PRECISION) { return true; } return false; } } }