[TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class cmdAddAlignment : IExternalCommand { // 创建对齐,把一个面对齐到参考面。 void AddAlignment_ReferencePlane(Application app, Document doc, Extrusion pSolid, XYZ normal, string nameRefPlane) { View pViewPlan = Util.findElement(doc, typeof(ViewPlan), " Lower Ref. Level ") as View; ReferencePlane refPlane = Util.findElement(doc, typeof(ReferencePlane), nameRefPlane) as ReferencePlane; PlanarFace pFace = findFace(app, pSolid, normal, refPlane); doc.FamilyCreate.NewAlignment(pViewPlan, refPlane.Reference, pFace.Reference); } // 对齐到楼层 void AddAlignment_Level(Document doc, Extrusion pSolid, XYZ normal, string nameLevel) { View pView = Util.findElement(doc, typeof(View), " Front ") as View; Level pLevel = Util.findElement(doc, typeof(Level), nameLevel) as Level; PlanarFace pFace = Util.findFace(pSolid, normal); doc.FamilyCreate.NewAlignment(pView, pLevel.PlaneReference, pFace.Reference); } void AddAlignments(Application app, Document doc, Extrusion pSolid) { AddAlignment_Level(doc, pSolid, new XYZ( 0.0, 0.0, 1.0), " Upper Ref Level "); AddAlignment_Level(doc, pSolid, new XYZ( 0.0, 0.0, - 1.0), " Lower Ref. Level "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ( 1.0, 0.0, 0.0), " Right "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ(- 1.0, 0.0, 0.0), " Left "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ( 0.0, - 1.0, 0.0), " Front "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ( 0.0, 1.0, 0.0), " Back "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ( 1.0, 0.0, 0.0), " OffsetV "); AddAlignment_ReferencePlane(app, doc, pSolid, new XYZ( 0.0, 1.0, 0.0), " OffsetH "); } // =============================================================== // helper function: given a solid, find a planar // Extrusion实体,给一个实体,给一个方向,找到与此方向一致的面。 // face with the given normal (version 2) // this is a slightly enhaced version of the previous // version and checks if the face is on the given reference plane. // =============================================================== PlanarFace findFace(Application app, Extrusion pBox, XYZ normal, ReferencePlane refPlane) { // get the geometry object of the given element // Options op = new Options(); op.ComputeReferences = true; GeometryObjectArray geomObjs = pBox.get_Geometry(op).Objects; // loop through the array and find a face with the given normal // foreach (GeometryObject geomObj in geomObjs) { if (geomObj is Solid) // solid is what we are interested in. { Solid pSolid = geomObj as Solid; FaceArray faces = pSolid.Faces; foreach (Face pFace in faces) { PlanarFace pPlanarFace = (PlanarFace)pFace; // check to see if they have same normal // face.Normal是面的向量。IsAlmostEqualTo(); if ((pPlanarFace != null) && pPlanarFace.Normal.IsAlmostEqualTo(normal)) { // additionally, we want to check if the face is on the reference plane // 还要判断面是否在参考平面上。 XYZ p0 = refPlane.BubbleEnd; // 终点? XYZ p1 = refPlane.FreeEnd; // 起点? Line pCurve = app.Create.NewLineBound(p0, p1); if (pPlanarFace.Intersect(pCurve) == SetComparisonResult.Subset) // 子集 { return pPlanarFace; // we found the face } } } } // will come back later as needed. // // else if (geomObj is Instance) // { // } // else if (geomObj is Curve) // { // } // else if (geomObj is Mesh) // { // } } // if we come here, we did not find any. return null; } public Result Execute(ExternalCommandData commandData, ref string messages, ElementSet elements) { UIApplication app = commandData.Application; Document doc = app.ActiveUIDocument.Document; Transaction ts = new Transaction(doc, " http://revit.5d6d.com "); ts.Start(); // Extrusion pSolid = CreateSolid(app.Application, doc); AddAlignments(app.Application, doc, pSolid); ts.Commit(); return Result.Succeeded; } // 创建封闭曲线 CurveArrArray createProfileLShape(Application _rvtApp) { // // define a simple L-shape profile // // 5 tw 4 // +-+ // | | 3 h = height // d | +---+ 2 // +-----+ td // 0 1 // 6 w // // sizes (hard coded for simplicity) // note: these need to match reference plane. otherwise, alignment won't work. // as an exercise, try changing those values and see how it behaves. // double w = Util.mmToFeet( 600.0); // those are hard coded for simplicity here. in practice, you may want to find out from the references) double d = Util.mmToFeet( 600.0); double tw = Util.mmToFeet( 150.0); // thickness added for Lab2 double td = Util.mmToFeet( 150.0); // define vertices // const int nVerts = 6; // the number of vertices XYZ[] pts = new XYZ[] { new XYZ(-w / 2.0, -d / 2.0, 0.0), new XYZ(w / 2.0, -d / 2.0, 0.0), new XYZ(w / 2.0, (-d / 2.0) + td, 0.0), new XYZ((-w / 2.0) + tw, (-d / 2.0) + td, 0.0), new XYZ((-w / 2.0) + tw, d / 2.0, 0.0), new XYZ(-w / 2.0, d / 2.0, 0.0), new XYZ(-w / 2.0, -d / 2.0, 0.0) }; // the last one is to make the loop simple // define a loop. define individual edges and put them in a curveArray // CurveArray pLoop = _rvtApp.Create.NewCurveArray(); for ( int i = 0; i < nVerts; ++i) { Line line = _rvtApp.Create.NewLineBound(pts[i], pts[i + 1]); pLoop.Append(line); } // then, put the loop in the curveArrArray as a profile // CurveArrArray pProfile = _rvtApp.Create.NewCurveArrArray(); pProfile.Append(pLoop); // if we come here, we have a profile now. return pProfile; } Extrusion CreateSolid(Application app, Document doc) { CurveArrArray pProfile = createProfileLShape(app); // 这个参考平面模板中没有,可以切换到Front立面,自己画一个。 ReferencePlane pRefPlane = Util.findElement(doc, typeof(ReferencePlane), " Reference Plane ") as ReferencePlane; SketchPlane pSketchPlane = doc.FamilyCreate.NewSketchPlane(pRefPlane.Plane); double dHeight = Util.mmToFeet( 4000); bool bIsSolid = true; Extrusion pSolid = doc.FamilyCreate.NewExtrusion(bIsSolid, pProfile, pSketchPlane, dHeight); return pSolid; } } public class Util { // Revit内部单位feet转化为mm即毫米 public static double mmToFeet( double val) { return val / 304.8; } public static double feetToMm( double val) { return val * 304.8; } // 通过类型与名称找Element public static Element findElement(Document _rvtDoc, Type targetType, string targetName) { // get the elements of the given type // FilteredElementCollector collector = new FilteredElementCollector(_rvtDoc); collector.WherePasses( new ElementClassFilter(targetType)); // parse the collection for the given name // using LINQ query here. // var targetElems = from element in collector where element.Name.Equals(targetName) select element; List<Element> elems = targetElems.ToList<Element>(); if (elems.Count > 0) { // we should have only one with the given name. return elems[ 0]; } // cannot find it. return null; } // ============================================================= // helper function: find a planar face with the given normal // ============================================================= public static PlanarFace findFace(Extrusion pBox, XYZ normal) { // get the geometry object of the given element // Options op = new Options(); op.ComputeReferences = true; GeometryObjectArray geomObjs = pBox.get_Geometry(op).Objects; // loop through the array and find a face with the given normal // foreach (GeometryObject geomObj in geomObjs) { if (geomObj is Solid) // solid is what we are interested in. { Solid pSolid = geomObj as Solid; FaceArray faces = pSolid.Faces; foreach (Face pFace in faces) { PlanarFace pPlanarFace = (PlanarFace)pFace; if ((pPlanarFace != null) && pPlanarFace.Normal.IsAlmostEqualTo(normal)) // we found the face { return pPlanarFace; } } } // will come back later as needed. // // else if (geomObj is Instance) // { // } // else if (geomObj is Curve) // { // } // else if (geomObj is Mesh) // { // } } // if we come here, we did not find any. return null; } #region Formatting and message handlers public const string Caption = " Revit Family API Labs "; /// <summary> /// MessageBox wrapper for informational message. /// </summary> public static void InfoMsg( string msg) { System.Diagnostics.Debug.WriteLine(msg); WinForm.MessageBox.Show(msg, Caption, WinForm.MessageBoxButtons.OK, WinForm.MessageBoxIcon.Information); } /// <summary> /// MessageBox wrapper for error message. /// </summary> public static void ErrorMsg( string msg) { WinForm.MessageBox.Show(msg, Caption, WinForm.MessageBoxButtons.OK, WinForm.MessageBoxIcon.Error); } #endregion // Formatting and message handlers }