/// <summary> /// Return polygon loops representing the size /// and location of given sheet and all the /// viewports it contains, regardless of type. /// </summary> static JtLoops GetSheetViewportLoops( SheetModelCollections modelCollections, ViewSheet sheet) { Document doc = sheet.Document; List <Viewport> viewports = sheet .GetAllViewports() .Select <ElementId, Viewport>( id => doc.GetElement(id) as Viewport) .ToList <Viewport>(); int n = viewports.Count; modelCollections.ViewsInSheet[sheet.Id] = new List <ViewData>(n); JtLoops sheetViewportLoops = new JtLoops(n + 1); // sheet.get_BoundingBox( null ) returns (-100,-100),(100,100) BoundingBoxUV bb = sheet.Outline; // model coordinates (0,0), (2.76,1.95) JtBoundingBox2dInt ibb = new JtBoundingBox2dInt(); // millimeters (0,0),(840,...) ibb.ExpandToContain(new Point2dInt(bb.Min)); ibb.ExpandToContain(new Point2dInt(bb.Max)); JtLoop loop = new JtLoop(ibb.Corners); sheetViewportLoops.Add(loop); foreach (Viewport vp in viewports) { XYZ center = vp.GetBoxCenter(); // not used Outline outline = vp.GetBoxOutline(); ibb.Init(); ibb.ExpandToContain( new Point2dInt(outline.MinimumPoint)); ibb.ExpandToContain( new Point2dInt(outline.MaximumPoint)); loop = new JtLoop(ibb.Corners); sheetViewportLoops.Add(loop); ViewData d = new ViewData(); d.Id = vp.ViewId; d.ViewportBoundingBox = loop.BoundingBox; modelCollections.ViewsInSheet[sheet.Id].Add( d); } return(sheetViewportLoops); }
/// <summary> /// Retrieve the room plan view boundary /// polygon loops and convert to 2D integer-based. /// For optimisation and consistency reasons, /// convert all coordinates to integer values in /// millimetres. Revit precision is limited to /// 1/16 of an inch, which is abaut 1.2 mm, anyway. /// </summary> static JtLoops GetRoomLoops(Room room) { SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center; // loops closed //SpatialElementBoundaryLocation.Finish; // loops not closed IList <IList <BoundarySegment> > loops = room. GetBoundarySegments(opt); int nLoops = loops.Count; JtLoops jtloops = new JtLoops(nLoops); foreach (IList <BoundarySegment> loop in loops) { int nSegments = loop.Count; JtLoop jtloop = new JtLoop(nSegments); XYZ p0 = null; // loop start point XYZ p; // segment start point XYZ q = null; // segment end point foreach (BoundarySegment seg in loop) { // Todo: handle non-linear curve. // Especially: if two long lines have a // short arc in between them, skip the arc // and extend both lines. p = seg.Curve.GetEndPoint(0); jtloop.Add(new Point2dInt(p)); Debug.Assert(null == q || q.IsAlmostEqualTo(p), "expected last endpoint to equal current start point"); q = seg.Curve.GetEndPoint(1); if (_debug_output) { Debug.Print("{0} --> {1}", Util.PointString(p), Util.PointString(q)); } if (null == p0) { p0 = p; // save loop start point } } Debug.Assert(q.IsAlmostEqualTo(p0), "expected last endpoint to equal loop start point"); jtloops.Add(jtloop); } return(jtloops); }
/// <summary> /// Add all plan view boundary loops from /// given solid to the list of loops. /// The creation application argument is used to /// reverse the extrusion analyser output curves /// in case they are badly oriented. /// </summary> /// <returns>Number of loops added</returns> static int AddLoops( Autodesk.Revit.Creation.Application creapp, JtLoops loops, GeometryObject obj, ref int nExtrusionAnalysisFailures) { int nAdded = 0; Solid solid = obj as Solid; if (null != solid && 0 < solid.Faces.Size) { //Plane plane = new Plane(XYZ.BasisX, // XYZ.BasisY, XYZ.Zero); // 2016 Plane plane = Plane.CreateByOriginAndBasis( XYZ.Zero, XYZ.BasisX, XYZ.BasisY); // 2017 ExtrusionAnalyzer extrusionAnalyzer = null; try { extrusionAnalyzer = ExtrusionAnalyzer.Create( solid, plane, XYZ.BasisZ); } catch (Autodesk.Revit.Exceptions .InvalidOperationException) { ++nExtrusionAnalysisFailures; return(nAdded); } Face face = extrusionAnalyzer .GetExtrusionBase(); loops.Add(GetLoop(creapp, face)); ++nAdded; } return(nAdded); }
/// <summary> /// Retrieve all plan view boundary loops from /// all solids of given element united together. /// If the element is a family instance, transform /// its loops from the instance placement /// coordinate system back to the symbol /// definition one. /// If no geometry can be determined, use the /// bounding box instead. /// </summary> static JtLoops GetPlanViewBoundaryLoops( Element e, ref int nFailures) { Autodesk.Revit.Creation.Application creapp = e.Document.Application.Create; JtLoops loops = null; Options opt = new Options(); GeometryElement geo = e.get_Geometry(opt); if (null != geo) { Document doc = e.Document; if (e is FamilyInstance) { // Retrieve family instance geometry // transformed back to symbol definition // coordinate space by inverting the // family instance placement transformation LocationPoint lp = e.Location as LocationPoint; Transform t = Transform.CreateTranslation( -lp.Point); Transform r = Transform.CreateRotationAtPoint( XYZ.BasisZ, -lp.Rotation, lp.Point); geo = geo.GetTransformed(t * r); } loops = GetPlanViewBoundaryLoopsGeo( creapp, geo, ref nFailures); } if (null == loops || 0 == loops.Count) { Debug.Print( "Unable to determine geometry for " + Util.ElementDescription(e) + "; using bounding box instead."); BoundingBoxXYZ bb; if (e is FamilyInstance) { bb = (e as FamilyInstance).Symbol .get_BoundingBox(null); } else { bb = e.get_BoundingBox(null); } JtLoop loop = new JtLoop(4); loop.Add(new Point2dInt(bb.Min)); loop.Add(new Point2dInt(bb.Max.X, bb.Min.Y)); loop.Add(new Point2dInt(bb.Max)); loop.Add(new Point2dInt(bb.Min.X, bb.Max.Y)); loops.Add(loop); } return(loops); }