// // (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.DB; using Autodesk.Revit.UI; using Autodesk.Revit.DB.Structure; using Autodesk.Revit; using System.Drawing; using Point = System.Drawing.Point; namespace Revit.SDK.Samples.NewOpenings.CS { /// /// Base class of ProfileFloor and ProfileWall /// contain the profile information and can make matrix to transform point to 2D plane /// public abstract class Profile { #region members /// ///Wall or Floor element /// protected Autodesk.Revit.DB.Element m_dataProfile; /// /// geometry object [face] /// protected List m_face; /// /// command data /// protected Autodesk.Revit.UI.ExternalCommandData m_commandData; /// /// Application creator /// protected Autodesk.Revit.Creation.Application m_appCreator; /// /// Document creator /// protected Autodesk.Revit.Creation.Document m_docCreator; #endregion /// /// Abstract method to create Opening /// public abstract void DrawOpening(List points, ToolType type); /// /// Draw profile of wall or floor in 2D /// /// form graphic /// pen use to draw line in pictureBox /// matrix used to transform points between 3d and 2d.> public void Draw2D(Graphics graphics, Pen pen, Matrix4 matrix4) { foreach (Edge edge in m_face) { List points = edge.Tessellate() as List; for (int i = 0; i < points.Count - 1; i++) { Autodesk.Revit.DB.XYZ point1 = points[i]; Autodesk.Revit.DB.XYZ point2 = points[i + 1]; Vector4 v1 = new Vector4(point1); Vector4 v2 = new Vector4(point2); v1 = matrix4.TransForm(v1); v2 = matrix4.TransForm(v2); graphics.DrawLine(pen, new Point((int)v1.X, (int)v1.Y), new Point((int)v2.X, (int)v2.Y)); } } } /// /// Constructor /// /// Selected element /// ExternalCommandData public Profile(Autodesk.Revit.DB.Element elem, ExternalCommandData commandData) { m_dataProfile = elem; m_commandData = commandData; m_appCreator = m_commandData.Application.Application.Create; m_docCreator = m_commandData.Application.ActiveUIDocument.Document.Create; List> faces = GetFaces(m_dataProfile); m_face = GetNeedFace(faces); } /// /// Get edges of element's profile /// /// Selected element public List> GetFaces(Autodesk.Revit.DB.Element elem) { List> faceEdges = new List>(); Options options = m_appCreator.NewGeometryOptions(); options.DetailLevel = ViewDetailLevel.Medium; options.ComputeReferences = true; Autodesk.Revit.DB.GeometryElement geoElem = elem.get_Geometry(options); //GeometryObjectArray gObjects = geoElem.Objects; IEnumerator Objects = geoElem.GetEnumerator(); //foreach (GeometryObject geo in gObjects) while (Objects.MoveNext()) { GeometryObject geo = Objects.Current; Solid solid = geo as Solid; if (solid != null) { EdgeArray edges = solid.Edges; FaceArray faces = solid.Faces; foreach (Face face in faces) { EdgeArrayArray edgeArrarr = face.EdgeLoops; foreach (EdgeArray edgeArr in edgeArrarr) { List edgesList = new List(); foreach (Edge edge in edgeArr) { edgesList.Add(edge); } faceEdges.Add(edgesList); } } } } return faceEdges; } /// /// Get Face Normal /// /// Edges in a face private Vector4 GetFaceNormal(List face) { Edge eg0 = face[0]; Edge eg1 = face[1]; List points = eg0.Tessellate() as List; Autodesk.Revit.DB.XYZ start = points[0]; Autodesk.Revit.DB.XYZ end = points[1]; Vector4 vStart = new Vector4((float)start.X, (float)start.Y, (float)start.Z); Vector4 vEnd = new Vector4((float)end.X, (float)end.Y, (float)end.Z); Vector4 vSub = vEnd - vStart; points = eg1.Tessellate() as List; start = points[0]; end = points[1]; vStart = new Vector4((float)start.X, (float)start.Y, (float)start.Z); vEnd = new Vector4((float)end.X, (float)end.Y, (float)end.Z); Vector4 vSub2 = vEnd - vStart; Vector4 result = vSub.CrossProduct(vSub2); result.Normalize(); return result; } /// /// Get First Face /// /// edges in all faces private List GetNeedFace(List> faces) { if (m_dataProfile is Wall) { return GetWallFace(faces); } return faces[0]; } /// /// Get a matrix which can transform points to 2D /// public Matrix4 To2DMatrix() { if (m_dataProfile is Wall) { return WallMatrix(); } List eg0 = m_face[0].Tessellate() as List; List eg1 = m_face[1].Tessellate() as List; Vector4 v1 = new Vector4((float)eg0[0].X, (float)eg0[0].Y, (float)eg0[0].Z); Vector4 v2 = new Vector4((float)eg0[1].X, (float)eg0[1].Y, (float)eg0[1].Z); Vector4 v21 = v1 - v2; v21.Normalize(); Vector4 v3 = new Vector4((float)eg1[0].X, (float)eg1[0].Y, (float)eg1[0].Z); Vector4 v4 = new Vector4((float)eg1[1].X, (float)eg1[1].Y, (float)eg1[1].Z); Vector4 v43 = v4 - v3; v43.Normalize(); Vector4 vZAxis = Vector4.CrossProduct(v43, v21); Vector4 vYAxis = Vector4.CrossProduct(vZAxis, v43); vYAxis.Normalize(); vZAxis.Normalize(); Vector4 vOrigin = (v4 + v1) / 2; Matrix4 result = new Matrix4(v43, vYAxis, vZAxis, vOrigin); return result; } /// /// Wall matrix /// /// public Matrix4 WallMatrix() { //get the location curve LocationCurve location = m_dataProfile.Location as LocationCurve; Vector4 xAxis = new Vector4(1, 0, 0); Vector4 yAxis = new Vector4(0, 1, 0); Vector4 zAxis = new Vector4(0, 0, 1); Vector4 origin = new Vector4(0, 0, 0); if (location != null) { Curve curve = location.Curve; Autodesk.Revit.DB.XYZ start = curve.GetEndPoint(0); Autodesk.Revit.DB.XYZ end = curve.GetEndPoint(1); xAxis = new Vector4((float)(end.X - start.X), (float)(end.Y - start.Y), (float)(end.Z - start.Z)); xAxis.Normalize(); yAxis = new Vector4(0, 0, 1); zAxis = Vector4.CrossProduct(xAxis, yAxis); zAxis.Normalize(); origin = new Vector4((float)(end.X + start.X) / 2, (float)(end.Y + start.Y) / 2, (float)(end.Z + start.Z) / 2); } return new Matrix4(xAxis, yAxis, zAxis, origin); } /// /// Get wall face /// /// /// private List GetWallFace(List> faces) { LocationCurve location = m_dataProfile.Location as LocationCurve; Curve curve = location.Curve; List xyzs = curve.Tessellate() as List; Vector4 zAxis = new Vector4(0, 0, 1); if (xyzs.Count == 2) { return faces[0]; } foreach (List face in faces) { foreach (Edge edge in face) { List edgexyzs = edge.Tessellate() as List; if (xyzs.Count == edgexyzs.Count) { Vector4 normal = GetFaceNormal(face); Vector4 cross = Vector4.CrossProduct(zAxis, normal); cross.Normalize(); if (cross.Length() == 1) { return face; } } } } return faces[0]; } /// /// Get a matrix which can move points to origin /// public Matrix4 ToCenterMatrix() { //translate the origin to bound center PointF[] bounds = GetFaceBounds(); PointF min = bounds[0]; PointF max = bounds[1]; PointF center = new PointF((min.X + max.X) / 2, (min.Y + max.Y) / 2); return new Matrix4(new Vector4(center.X, center.Y, 0)); } /// /// Get Face Bounds /// public PointF[] GetFaceBounds() { Matrix4 matrix = To2DMatrix(); Matrix4 inverseMatrix = matrix.Inverse(); float minX = 0, maxX = 0, minY = 0, maxY = 0; bool bFirstPoint = true; foreach (Edge edge in m_face) { List points = edge.Tessellate() as List; foreach (Autodesk.Revit.DB.XYZ point in points) { Vector4 v = new Vector4(point); Vector4 v1 = inverseMatrix.TransForm(v); if (bFirstPoint) { minX = maxX = v1.X; minY = maxY = v1.Y; bFirstPoint = false; } else { if (v1.X < minX) { minX = v1.X; } else if (v1.X > maxX) { maxX = v1.X; } if (v1.Y < minY) { minY = v1.Y; } else if (v1.Y > maxY) { maxY = v1.Y; } } } } PointF[] resultPoints = new PointF[2] { new PointF(minX, minY), new PointF(maxX, maxY) }; return resultPoints; } } }