// // (C) Copyright 2003-2019 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. // using System; using System.Collections.Generic; using System.Text; using Autodesk.Revit; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Structure; namespace Revit.SDK.Samples.Reinforcement.CS { using GeoElement = Autodesk.Revit.DB.GeometryElement; using Element = Autodesk.Revit.DB.Element; /// /// The class which give the base geometry operation, it is a static class. /// static class GeomUtil { // Private members const double Precision = 0.00001; //precision when judge whether two doubles are equal /// /// Judge whether the two double data are equal /// /// The first double data /// The second double data /// true if two double data is equal, otherwise false public static bool IsEqual(double d1, double d2) { //get the absolute value; double diff = Math.Abs(d1 - d2); return diff < Precision; } /// /// Judge whether the two Autodesk.Revit.DB.XYZ point are equal /// /// The first Autodesk.Revit.DB.XYZ point /// The second Autodesk.Revit.DB.XYZ point /// true if two Autodesk.Revit.DB.XYZ point is equal, otherwise false public static bool IsEqual(Autodesk.Revit.DB.XYZ first, Autodesk.Revit.DB.XYZ second) { bool flag = true; flag = flag && IsEqual(first.X, second.X); flag = flag && IsEqual(first.Y, second.Y); flag = flag && IsEqual(first.Z, second.Z); return flag; } /// /// /// return true when line is perpendicular to the face /// /// Judge whether the line is perpendicular to the face /// /// the face reference /// the line reference /// the transform for the face /// the transform for the line /// true if line is perpendicular to the face, otherwise false public static bool IsVertical(Face face, Line line, Transform faceTrans, Transform lineTrans) { //get points which the face contains List points = face.Triangulate().Vertices as List; if (3 > points.Count) // face's point number should be above 2 { return false; } // get three points from the face points Autodesk.Revit.DB.XYZ first = points[0]; Autodesk.Revit.DB.XYZ second = points[1]; Autodesk.Revit.DB.XYZ third = points[2]; // get start and end point of line Autodesk.Revit.DB.XYZ lineStart = line.GetEndPoint(0); Autodesk.Revit.DB.XYZ lineEnd = line.GetEndPoint(1); // transForm the three points if necessary if (null != faceTrans) { first = TransformPoint(first, faceTrans); second = TransformPoint(second, faceTrans); third = TransformPoint(third, faceTrans); } // transform the start and end points if necessary if (null != lineTrans) { lineStart = TransformPoint(lineStart, lineTrans); lineEnd = TransformPoint(lineEnd, lineTrans); } // form two vectors from the face and a vector stand for the line // Use SubXYZ() method to get the vectors Autodesk.Revit.DB.XYZ vector1 = SubXYZ(first, second); // first vector of face Autodesk.Revit.DB.XYZ vector2 = SubXYZ(first, third); // second vector of face Autodesk.Revit.DB.XYZ vector3 = SubXYZ(lineStart, lineEnd); // line vector // get two dot products of the face vectors and line vector double result1 = DotMatrix(vector1, vector3); double result2 = DotMatrix(vector2, vector3); // if two dot products are all zero, the line is perpendicular to the face return (IsEqual(result1, 0) && IsEqual(result2, 0)); } /// /// judge whether the two vectors have the same direction /// /// the first vector /// the second vector /// true if the two vector is in same direction, otherwise false public static bool IsSameDirection(Autodesk.Revit.DB.XYZ firstVec, Autodesk.Revit.DB.XYZ secondVec) { // get the unit vector for two vectors Autodesk.Revit.DB.XYZ first = UnitVector(firstVec); Autodesk.Revit.DB.XYZ second = UnitVector(secondVec); // if the dot product of two unit vectors is equal to 1, return true double dot = DotMatrix(first, second); return (IsEqual(dot, 1)); } /// /// Judge whether the two vectors have the opposite direction /// /// the first vector /// the second vector /// true if the two vector is in opposite direction, otherwise false public static bool IsOppositeDirection(Autodesk.Revit.DB.XYZ firstVec, Autodesk.Revit.DB.XYZ secondVec) { // get the unit vector for two vectors Autodesk.Revit.DB.XYZ first = UnitVector(firstVec); Autodesk.Revit.DB.XYZ second = UnitVector(secondVec); // if the dot product of two unit vectors is equal to -1, return true double dot = DotMatrix(first, second); return (IsEqual(dot, -1)); } /// /// multiplication cross of two Autodesk.Revit.DB.XYZ as Matrix /// /// The first XYZ /// The second XYZ /// the normal vector of the face which first and secend vector lie on public static Autodesk.Revit.DB.XYZ CrossMatrix(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { //get the coordinate of the XYZ double u1 = p1.X; double u2 = p1.Y; double u3 = p1.Z; double v1 = p2.X; double v2 = p2.Y; double v3 = p2.Z; double x = v3 * u2 - v2 * u3; double y = v1 * u3 - v3 * u1; double z = v2 * u1 - v1 * u2; return new Autodesk.Revit.DB.XYZ (x, y, z); } /// /// Set the vector into unit length /// /// the input vector /// the vector in unit length public static Autodesk.Revit.DB.XYZ UnitVector(Autodesk.Revit.DB.XYZ vector) { // calculate the distance from grid origin to the XYZ double length = GetLength(vector); // changed the vector into the unit length double x = vector.X / length; double y = vector.Y / length; double z = vector.Z / length; return new Autodesk.Revit.DB.XYZ (x, y, z); } /// /// calculate the distance from grid origin to the XYZ(vector length) /// /// the input vector /// the length of the vector public static double GetLength(Autodesk.Revit.DB.XYZ vector) { double x = vector.X; double y = vector.Y; double z = vector.Z; return Math.Sqrt(x * x + y * y + z * z); } /// /// Subtraction of two points(or vectors), get a new vector /// /// the first point(vector) /// the second point(vector) /// return a new vector from point p2 to p1 public 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; return new Autodesk.Revit.DB.XYZ (x, y, z); } /// /// Add of two points(or vectors), get a new point(vector) /// /// the first point(vector) /// the first point(vector) /// a new vector(point) public 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; return new Autodesk.Revit.DB.XYZ (x, y, z); } /// /// Multiply a verctor with a number /// /// a vector /// the rate number /// public static Autodesk.Revit.DB.XYZ MultiplyVector(Autodesk.Revit.DB.XYZ vector, double rate) { double x = vector.X * rate; double y = vector.Y * rate; double z = vector.Z * rate; return new Autodesk.Revit.DB.XYZ (x, y, z); } /// /// Transform old coordinate system in the new coordinate system /// /// the Autodesk.Revit.DB.XYZ which need to be transformed /// the value of the coordinate system to be transformed /// the new Autodesk.Revit.DB.XYZ which has been transformed public static Autodesk.Revit.DB.XYZ TransformPoint(Autodesk.Revit.DB.XYZ point, Transform transform) { //get the coordinate value in X, Y, Z axis double x = point.X; double y = point.Y; double z = point.Z; //transform basis of the old coordinate system in the new coordinate system Autodesk.Revit.DB.XYZ b0 = transform.get_Basis(0); Autodesk.Revit.DB.XYZ b1 = transform.get_Basis(1); Autodesk.Revit.DB.XYZ b2 = transform.get_Basis(2); Autodesk.Revit.DB.XYZ origin = transform.Origin; //transform the origin of the old coordinate system in the new coordinate system double xTemp = x * b0.X + y * b1.X + z * b2.X + origin.X; double yTemp = x * b0.Y + y * b1.Y + z * b2.Y + origin.Y; double zTemp = x * b0.Z + y * b1.Z + z * b2.Z + origin.Z; return new Autodesk.Revit.DB.XYZ (xTemp, yTemp, zTemp); } /// /// Move a point a give offset along a given direction /// /// the point need to move /// the direction the point move to /// indicate how long to move /// the moved point public static Autodesk.Revit.DB.XYZ OffsetPoint(Autodesk.Revit.DB.XYZ point, Autodesk.Revit.DB.XYZ direction, double offset) { Autodesk.Revit.DB.XYZ directUnit = UnitVector(direction); Autodesk.Revit.DB.XYZ offsetVect = MultiplyVector(directUnit, offset); return AddXYZ(point, offsetVect); } /// /// get the orient of hook accroding to curve direction, rebar normal and hook direction /// /// the curve direction /// rebar normal direction /// the hook direction /// the orient of the hook public static RebarHookOrientation GetHookOrient(Autodesk.Revit.DB.XYZ curveVec, Autodesk.Revit.DB.XYZ normal, Autodesk.Revit.DB.XYZ hookVec) { Autodesk.Revit.DB.XYZ tempVec = normal; for (int i = 0; i < 4; i++) { tempVec = GeomUtil.CrossMatrix(tempVec, curveVec); if (GeomUtil.IsSameDirection(tempVec, hookVec)) { if (i == 0) { return RebarHookOrientation.Right; } else if (i == 2) { return RebarHookOrientation.Left; } } } throw new Exception("Can't find the hook orient according to hook direction."); } /// /// Judge the vector is in right or left direction /// /// The unit vector need to be judged its direction /// if in right dircetion return true, otherwise return false public static bool IsInRightDir(Autodesk.Revit.DB.XYZ normal) { double eps = 1.0e-8; if (Math.Abs(normal.X) <= eps) { if (normal.Y > 0) return false; else return true; } if (normal.X > 0) return true; if (normal.X < 0) return false; return true; } /// /// dot product of two Autodesk.Revit.DB.XYZ as Matrix /// /// The first XYZ /// The second XYZ /// the cosine value of the angle between vector p1 an p2 private static double DotMatrix(Autodesk.Revit.DB.XYZ p1, Autodesk.Revit.DB.XYZ p2) { //get the coordinate of the Autodesk.Revit.DB.XYZ double v1 = p1.X; double v2 = p1.Y; double v3 = p1.Z; double u1 = p2.X; double u2 = p2.Y; double u3 = p2.Z; return v1 * u1 + v2 * u2 + v3 * u3; } } }