private void CreateBoxShape(IFCImportShapeEditScope shapeEditScope, Transform scaledLcs) { using (IFCImportShapeEditScope.IFCContainingRepresentationSetter repSetter = new IFCImportShapeEditScope.IFCContainingRepresentationSetter(shapeEditScope, this)) { // Get the material and graphics style based in the "Box" sub-category of Generic Models. // We will create the sub-category if this is our first time trying to use it. // Note that all bounding boxes are controlled by a sub-category of Generic Models. We may revisit that decision later. // Note that we hard-wire the identifier to "Box" because older files may have bounding box items in an obsolete representation. SolidOptions solidOptions = null; Category bboxCategory = IFCCategoryUtil.GetSubCategoryForRepresentation(shapeEditScope.Document, Id, IFCRepresentationIdentifier.Box); if (bboxCategory != null) { ElementId materialId = (bboxCategory.Material == null) ? ElementId.InvalidElementId : bboxCategory.Material.Id; GraphicsStyle graphicsStyle = bboxCategory.GetGraphicsStyle(GraphicsStyleType.Projection); ElementId gstyleId = (graphicsStyle == null) ? ElementId.InvalidElementId : graphicsStyle.Id; solidOptions = new SolidOptions(materialId, gstyleId); } Solid bboxSolid = IFCGeometryUtil.CreateSolidFromBoundingBox(scaledLcs, BoundingBox, solidOptions); if (bboxSolid != null) { IFCSolidInfo bboxSolidInfo = IFCSolidInfo.Create(Id, bboxSolid); shapeEditScope.AddGeometry(bboxSolidInfo); } } return; }
public static void CreateSphereDirectShape(Document doc, XYZ center, float radius, string name) { List <Curve> profile = new List <Curve>(); // first create sphere with 2' radius XYZ profile00 = center; XYZ profilePlus = center + new XYZ(0, radius, 0); XYZ profileMinus = center - new XYZ(0, radius, 0); profile.Add(Line.CreateBound(profilePlus, profileMinus)); profile.Add(Arc.Create(profileMinus, profilePlus, center + new XYZ(radius, 0, 0))); CurveLoop curveLoop = CurveLoop.Create(profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); Frame frame = new Frame(center, XYZ.BasisX, -XYZ.BasisZ, XYZ.BasisY); Solid sphere = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curveLoop }, 0, 2 * Math.PI, options); using (Transaction t = new Transaction(doc, "Create sphere direct shape")) { t.Start(); DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.SetShape(new GeometryObject[] { sphere }); ds.Name = name; t.Commit(); } }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="unscaledLcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>Zero or more created geometries.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs, Transform scaledLcs, string guid) { Transform unscaledSweptDiskPosition = (unscaledLcs == null) ? Transform.Identity : unscaledLcs; Transform scaledSweptDiskPosition = (scaledLcs == null) ? Transform.Identity : scaledLcs; CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(Id, Directrix, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } CurveLoop trimmedDirectrixInWCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, Id, unscaledSweptDiskPosition, scaledSweptDiskPosition); // Create the disk. Curve firstCurve = null; foreach (Curve curve in trimmedDirectrixInWCS) { firstCurve = curve; break; } double startParam = 0.0; IList <CurveLoop> profileCurveLoops = CreateProfileCurveLoopsForDirectrix(firstCurve, out startParam); if (profileCurveLoops == null) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); try { Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInWCS, 0, startParam, profileCurveLoops, solidOptions); if (sweptDiskSolid != null) { myObjs.Add(sweptDiskSolid); } } catch (Exception ex) { // If we can't create a solid, we will attempt to split the Solid into valid pieces (that will likely have some overlap). if (ex.Message.Contains("self-intersections")) { Importer.TheLog.LogWarning(Id, "The IfcSweptDiskSolid definition does not define a valid solid, likely due to self-intersections or other such problems; the profile probably extends too far toward the inner curvature of the sweep path. Creating the minimum number of solids possible to represent the geometry.", false); myObjs = SplitSweptDiskIntoValidPieces(trimmedDirectrixInWCS, profileCurveLoops, solidOptions); } else { throw ex; } } return(myObjs); }
/// <summary> /// creates a DirectShape instance of which shape is Sphere. /// Sphere is defined by its center and radius. /// </summary> /// <param name="document">The Revit document where the instance to be drawn</param> /// <param name="name">The name of this instance</param> /// <param name="center">Position of the center</param> /// <param name="radius">Radius of the circle</param> /// <param name="line_color">Outline color of Circle</param> /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param> public DirectSphere(Document document, string name, XYZ center, double radius, Color line_color, int surface_transparency) : base(document, name) { m_shape_type = ShapeTypes.Sphere; Center = center; Radius = radius; XYZ top = center + radius * XYZ.BasisZ; XYZ bottom = center - radius * XYZ.BasisZ; XYZ right = center + radius * XYZ.BasisX; Frame frame = new Frame(center, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); List <Curve> profile = new List <Curve>(); profile.Add(Line.CreateBound(top, bottom)); profile.Add(Arc.Create(bottom, top, right)); CurveLoop curve_loop = CurveLoop.Create(profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); if (Frame.CanDefineRevitGeometry(frame) == true) { Solid sphere = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curve_loop }, 0, 2 * Math.PI, options); using (Transaction t = new Transaction(document, "Create sphere direct shape.")) { t.Start(); DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel)); shape.SetShape(new GeometryObject[] { sphere }); shape.SetName(name); m_element_id = shape.Id; document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency)); t.Commit(); } } }
// Create a DirectShape Sphere static public void CreateSphereDirectShape(Document doc) { List <Curve> profile = new List <Curve>(); // first create sphere with 2' radius XYZ center = XYZ.Zero; double radius = 2.0; //XYZ profile00 = center; XYZ profilePlus = center + new XYZ(0, radius, 0); XYZ profileMinus = center - new XYZ(0, radius, 0); profile.Add(Line.CreateBound(profilePlus, profileMinus)); profile.Add(Arc.Create(profileMinus, profilePlus, center + new XYZ(radius, 0, 0))); CurveLoop curveLoop = CurveLoop.Create(profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); Frame frame = new Frame(center, XYZ.BasisX, -XYZ.BasisZ, XYZ.BasisY); if (Frame.CanDefineRevitGeometry(frame) == true) { Solid sphere = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curveLoop }, 0, 2 * Math.PI, options); using (Transaction t = new Transaction(doc, "Create sphere direct shape")) { t.Start(); // create direct shape and assign the sphere shape DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.ApplicationId = "Application id"; ds.ApplicationDataId = "Geometry object id"; ds.SetShape(new GeometryObject[] { sphere }); t.Commit(); } } }
/// <summary> /// Create and return a rectangular prism of the /// given side lengths centered at the given point. /// </summary> static Solid CreateRectangularPrism( XYZ center, double d1, double d2, double d3) { List <Curve> profile = new List <Curve>(); XYZ profile00 = new XYZ(-d1 / 2, -d2 / 2, -d3 / 2); XYZ profile01 = new XYZ(-d1 / 2, d2 / 2, -d3 / 2); XYZ profile11 = new XYZ(d1 / 2, d2 / 2, -d3 / 2); XYZ profile10 = new XYZ(d1 / 2, -d2 / 2, -d3 / 2); profile.Add(Line.CreateBound(profile00, profile01)); profile.Add(Line.CreateBound(profile01, profile11)); profile.Add(Line.CreateBound(profile11, profile10)); profile.Add(Line.CreateBound(profile10, profile00)); CurveLoop curveLoop = CurveLoop.Create(profile); SolidOptions options = new SolidOptions( ElementId.InvalidElementId, ElementId.InvalidElementId); return(GeometryCreationUtilities .CreateExtrusionGeometry( new CurveLoop[] { curveLoop }, XYZ.BasisZ, d3, options)); }
/// <summary> /// Creates a new DirectShape. /// </summary> /// <param name="doc"></param> /// <param name="parm"></param> /// <param name="opt"></param> /// <returns></returns> public static DirectShape CreateDirectShape(this Document doc, DirectShapeParameter parm, SolidOptions opt = null) { if (doc == null) { throw new ArgumentNullException(nameof(doc)); } if (parm == null) { throw new ArgumentNullException(nameof(parm)); } var solid = CreateExtrusionGeometry(parm.Profile.ToList(), parm.Direction, parm.Distance); if (opt != null) { solid = CreateExtrusionGeometry(parm.Profile.ToList(), parm.Direction, parm.Distance, opt); } var result = DirectShape.CreateElement(doc, new ElementId(parm.Category)); result?.AppendShape(new List <GeometryObject> { solid }); return(result); }
/// <summary> /// creates a DirectShape instance of which shape is a part of a torus (like elbow joint pipe). /// Torus is defined by center, axis, tube radius, and mean radius (the distance between center and tube center). /// The tube_begin and tube_end defines the angle between the two edges of the piece. /// </summary> /// <param name="document">The Revit document where the instance to be drawn</param> /// <param name="name">The name of this instance</param> /// <param name="center">Position of center of the torus' hole</param> /// <param name="axis">Vector passing through the center</param> /// <param name="mean_radius">The distance between torus center and its tube center</param> /// <param name="tube_radius">Radius of tube</param> /// <param name="tube_begin">The vector pointing to one of the torus' edge from its center</param> /// <param name="torus_angle">The angle between the tube begin and end</param> /// <param name="line_color">Outline color of the torus</param> /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param> public DirectTorus(Document document, string name, XYZ center, XYZ axis, double mean_radius, double tube_radius, XYZ tube_begin, double torus_angle, Color line_color, int surface_transparency) : base(document, name) { m_shape_type = ShapeTypes.Torus; Center = center; Axis = axis; MeanRadius = mean_radius; TubeRadius = tube_radius; HasAnElbow = true; TubeBegin = tube_begin; TubeAngle = torus_angle; XYZ tilting_axis = XYZ.BasisZ.CrossProduct(axis); double tilting_angle = FindSurfaceRevitPluginUtils.GetPositiveAngleBetween(XYZ.BasisZ, axis, tilting_axis); bool no_need_to_tilt = tilting_axis.IsAlmostEqualTo(XYZ.Zero); Transform tilting_torus = no_need_to_tilt ? Transform.Identity : Transform.CreateRotation(tilting_axis, tilting_angle); XYZ tilted_basis_x = tilting_torus.OfVector(XYZ.BasisX); // model space coordinates Frame frame = new Frame(XYZ.Zero, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); XYZ model_tube_center = XYZ.BasisX * mean_radius; XYZ model_tube_top = model_tube_center + tube_radius * XYZ.BasisZ; XYZ model_tube_bottom = model_tube_center - tube_radius * XYZ.BasisZ; XYZ model_tube_outer = model_tube_center + tube_radius * XYZ.BasisX; XYZ model_tube_inner = model_tube_center - tube_radius * XYZ.BasisX; List <Curve> tube_circle = new List <Curve>(); tube_circle.Add(Arc.Create(model_tube_top, model_tube_bottom, model_tube_inner)); tube_circle.Add(Arc.Create(model_tube_bottom, model_tube_top, model_tube_outer)); CurveLoop curve_loop = CurveLoop.Create(tube_circle); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); if (Frame.CanDefineRevitGeometry(frame)) { Solid torus = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curve_loop }, 0, torus_angle, options); using (Transaction t = new Transaction(document, "Create torus direct shape.")) { t.Start(); DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel)); shape.SetShape(new GeometryObject[] { torus }); shape.SetName(name); m_element_id = shape.Id; if (no_need_to_tilt == false) { shape.Location.Rotate(Line.CreateUnbound(XYZ.Zero, tilting_axis), tilting_angle); } shape.Location.Rotate(Line.CreateUnbound(XYZ.Zero, axis), FindSurfaceRevitPluginUtils.GetPositiveAngleBetween(tilted_basis_x, tube_begin, axis)); shape.Location.Move(center); document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency)); t.Commit(); } } }
protected List <GeometryObject> CreateConformalGeometryIfPossible( IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs) { Transform unscaledSweptDiskPosition = (unscaledLcs == null) ? Transform.Identity : unscaledLcs; IList <CurveLoop> trimmedDirectrices = IFCGeometryUtil.TrimCurveLoops(Id, Directrix, StartParameter, EndParameter); if (trimmedDirectrices == null) { return(null); } List <GeometryObject> myObjs = null; bool isIdentity = unscaledSweptDiskPosition.IsIdentity; foreach (CurveLoop trimmedDirectrix in trimmedDirectrices) { // Create the disk. Curve firstCurve = null; foreach (Curve curve in trimmedDirectrix) { firstCurve = curve; break; } double startParam = 0.0; IList <CurveLoop> profileCurveLoops = CreateProfileCurveLoopsForDirectrix(firstCurve, out startParam); if (profileCurveLoops == null) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); myObjs = new List <GeometryObject>(); try { Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrix, 0, startParam, profileCurveLoops, solidOptions); if (!isIdentity) { sweptDiskSolid = SolidUtils.CreateTransformed(sweptDiskSolid, unscaledSweptDiskPosition); } if (sweptDiskSolid != null) { myObjs.Add(sweptDiskSolid); } } catch { return(null); } } return(myObjs); }
/// <summary> /// creates a DirectShape instance of which shape is Plane. /// Plane is defined by four vertices (top-left, top-right, bottom-left, bottom-right) on the plane. /// (Actually, it is a rectangle as you already know.) /// </summary> /// <remarks>The Plane has very small thickness (0.0039) since there is no way to create a plane with no thickness using DirectShape.</remarks> /// <param name="document">The Revit document where the instance to be drawn</param> /// <param name="name">The name of this instance</param> /// <param name="top_left">Position of the top-left vertex</param> /// <param name="top_right">Position of the top-right vertex</param> /// <param name="bottom_left">Position of the bottom-left vertex</param> /// <param name="bottom_right">Position of the bottom-right vertex</param> /// <param name="line_color">Outline color of Plane</param> /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param> public DirectPlane(Document document, string name, XYZ top_left, XYZ top_right, XYZ bottom_left, XYZ bottom_right, Color line_color, int surface_transparency) : base(document, name) { m_shape_type = ShapeTypes.Plane; TopLeft = top_left; TopRight = top_right; BottomLeft = bottom_left; BottomRight = bottom_right; XYZ rotation_axis, translation_offset; double rotation_angle; XYZ tl, tr; XYZ bl, br; // We'll rotates and translates the plane transformed to be axis-aligned, because GeometryCreationUtilities.CreateSweptGeometry may fail to define a plane due to the precision issue. GetAxisAlignedPlane( top_left, top_right, bottom_left, bottom_right, out tl, out tr, out bl, out br, out rotation_axis, out rotation_angle, out translation_offset); Frame frame = new Frame(XYZ.Zero, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ); List <Curve> profile = new List <Curve>(); profile.Add(Line.CreateBound(tl, bl)); profile.Add(Line.CreateBound(bl, br)); profile.Add(Line.CreateBound(br, tr)); profile.Add(Line.CreateBound(tr, tl)); List <Curve> swept_profile = new List <Curve>(); swept_profile.Add(Line.CreateBound(XYZ.Zero, 0.0039 * XYZ.BasisZ)); CurveLoop curve_loop = CurveLoop.Create(profile); CurveLoop sweep_path = CurveLoop.Create(swept_profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); if (Frame.CanDefineRevitGeometry(frame) == true) { Solid thin_box = GeometryCreationUtilities.CreateSweptGeometry(sweep_path, 0, 0, new CurveLoop[] { curve_loop }, options); using (Transaction t = new Transaction(document, "Create plane direct shape")) { t.Start(); DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel)); shape.SetShape(new GeometryObject[] { thin_box }); shape.SetName(name); m_element_id = shape.Id; shape.Location.Rotate(Line.CreateUnbound(XYZ.Zero, rotation_axis), -rotation_angle); shape.Location.Move(-translation_offset); document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency)); t.Commit(); } } }
private bool CreateRoomMassByBoundingBox(Room room) { try { var bb = room.get_BoundingBox(null); var eid = new ElementId(BuiltInCategory.OST_Mass); if (bb == null) { return(false); } #if REVIT2019 || REVIT2018 || REVIT2017 || REVIT2020 || REVIT2021 DirectShape roomShape = DirectShape.CreateElement(doc, eid); #else DirectShape roomShape = DirectShape.CreateElement(doc, eid, "A", "B"); #endif var curves = new List <Curve>(); var bl = new XYZ(bb.Min.X, bb.Min.Y, bb.Min.Z); var br = new XYZ(bb.Max.X, bb.Min.Y, bb.Min.Z); var tr = new XYZ(bb.Max.X, bb.Max.Y, bb.Min.Z); var tl = new XYZ(bb.Min.X, bb.Max.Y, bb.Min.Z); var height = bb.Max.Z - bb.Min.Z; curves.Add(Line.CreateBound(bl, br)); curves.Add(Line.CreateBound(br, tr)); curves.Add(Line.CreateBound(tr, tl)); curves.Add(Line.CreateBound(tl, bl)); var loop = CurveLoop.Create(curves); var options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); var roomSolid = GeometryCreationUtilities.CreateExtrusionGeometry(new[] { loop }, new XYZ(0, 0, 1), height, options); if (roomSolid != null) { var geomObj = new GeometryObject[] { roomSolid }; if (geomObj.Length > 0) { roomShape.SetShape(geomObj); CopyAllRoomParametersToMasses(room, roomShape); return(true); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } return(false); }
/// <summary> /// creates a DirectShape instance of which shape is Torus. /// Torus is defined by center, axis, tube radius, and mean radius (the distance between center and tube center). /// </summary> /// <param name="document">The Revit document where the instance to be drawn</param> /// <param name="name">The name of this instance</param> /// <param name="center">Position of center of the torus' hole</param> /// <param name="axis">Vector passing through the center</param> /// <param name="mean_radius">The distance between the center and tube center</param> /// <param name="tube_radius">Radius of tube</param> /// <param name="line_color">Outline color</param> /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param> public DirectTorus(Document document, string name, XYZ center, XYZ axis, double mean_radius, double tube_radius, Color line_color, int surface_transparency) : base(document, name) { m_shape_type = ShapeTypes.Torus; Center = center; Axis = axis; MeanRadius = mean_radius; TubeRadius = tube_radius; HasAnElbow = false; TubeBegin = new XYZ(); TubeAngle = 0.0; XYZ axis_norm = axis.Normalize(); XYZ minor_center = ((XYZ.BasisX.CrossProduct(axis_norm).GetLength() < Double.Epsilon) ? XYZ.BasisY : XYZ.BasisX).CrossProduct(axis_norm); minor_center = center + minor_center.Normalize() * mean_radius; XYZ basis_z = axis.Normalize(); XYZ basis_x = (minor_center - center).Normalize(); XYZ basis_y = basis_z.CrossProduct(basis_x).Normalize(); Frame frame = new Frame(center, basis_x, basis_y, basis_z); // model space coordinates XYZ near = minor_center - tube_radius * basis_x; XYZ far = minor_center + tube_radius * basis_x; XYZ back = minor_center + tube_radius * basis_z; XYZ front = minor_center - tube_radius * basis_z; List <Curve> profile = new List <Curve>(); profile.Add(Arc.Create(near, far, front)); profile.Add(Arc.Create(far, near, back)); CurveLoop curve_loop = CurveLoop.Create(profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); if (Frame.CanDefineRevitGeometry(frame) == true) { Solid torus = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curve_loop }, 0, 2 * Math.PI, options); using (Transaction t = new Transaction(document, "Create torus direct shape")) { t.Start(); DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel)); shape.SetShape(new GeometryObject[] { torus }); shape.SetName(name); document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency)); t.Commit(); } } }
/// <summary> /// creates a DirectShape instance of which shape is Cylinder. /// Cylinder is defined by two circles (top, bottom) with the same radius. /// </summary> /// <param name="document">The Revit document where the instance to be drawn</param> /// <param name="name">The name of this instance</param> /// <param name="doc">The Revit document where the instance to be drawn</param> /// <param name="top">Position of center of the top circle</param> /// <param name="bottom">Position of center of the bottom circle</param> /// <param name="radius">Radius of the circles</param> /// <param name="line_color">Outline color of Cylinder</param> /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param> public DirectCylinder(Document document, string name, XYZ top, XYZ bottom, double radius, Color line_color, int surface_transparency) : base(document, name) { m_shape_type = ShapeTypes.Cylinder; Top = top; Bottom = bottom; Radius = radius; // defines a reference frame of which origin is at the center of the cylinder and z-axis is passing through the centers of its top and bottom. XYZ center = (top + bottom) / 2; XYZ basis_z = (top - bottom).Normalize(); XYZ basis_x = XYZ.BasisY.CrossProduct(basis_z).Normalize(); XYZ basis_y = basis_z.CrossProduct(basis_x).Normalize(); Frame frame = new Frame(center, basis_x, basis_y, basis_z); XYZ bottom_left = bottom - radius * basis_x; XYZ bottom_right = bottom + radius * basis_x; XYZ bottom_front = bottom - radius * basis_y; XYZ bottom_back = bottom + radius * basis_y; // creates a profile that is a cross section of a circle (the cylinder will be made by sweeping through the z-axis). List <Curve> profile = new List <Curve>(); profile.Add(Arc.Create(bottom_left, bottom_right, bottom_back)); profile.Add(Arc.Create(bottom_right, bottom_left, bottom_front)); List <Curve> swept_profile = new List <Curve>(); swept_profile.Add(Line.CreateBound(bottom, top)); CurveLoop curve_loop = CurveLoop.Create(profile); CurveLoop sweep_path = CurveLoop.Create(swept_profile); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); if (Frame.CanDefineRevitGeometry(frame) == true) { Solid cylinder = GeometryCreationUtilities.CreateSweptGeometry(sweep_path, 0, 0, new CurveLoop[] { curve_loop }, options); using (Transaction t = new Transaction(document, "Create cylinder direct shape")) { t.Start(); DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel)); shape.SetShape(new GeometryObject[] { cylinder }); shape.SetName(name); m_element_id = shape.Id; document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency)); t.Commit(); } } }
public static Solid CreateRectangularPrism(XYZ center, double d1, double d2, double d3) { List<Curve> list = new List<Curve>(); XYZ xYZ = new XYZ((0.0 - d1) / 2.0, (0.0 - d2) / 2.0, (0.0 - d3) / 2.0); XYZ xYZ2 = new XYZ((0.0 - d1) / 2.0, d2 / 2.0, (0.0 - d3) / 2.0); XYZ xYZ3 = new XYZ(d1 / 2.0, d2 / 2.0, (0.0 - d3) / 2.0); XYZ xYZ4 = new XYZ(d1 / 2.0, (0.0 - d2) / 2.0, (0.0 - d3) / 2.0); list.Add(Line.CreateBound(xYZ, xYZ2)); list.Add(Line.CreateBound(xYZ2, xYZ3)); list.Add(Line.CreateBound(xYZ3, xYZ4)); list.Add(Line.CreateBound(xYZ4, xYZ)); CurveLoop curveLoop = CurveLoop.Create(list); SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); return GeometryCreationUtilities.CreateExtrusionGeometry(new CurveLoop[1] { curveLoop }, XYZ.BasisZ, d3, solidOptions); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>One or more created Solids.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform origLCS = (lcs == null) ? Transform.Identity : lcs; Transform unscaledRevolvePosition = (Position == null) ? origLCS : origLCS.Multiply(Position); Transform scaledOrigLCS = (scaledLcs == null) ? Transform.Identity : scaledLcs; Transform scaledRevolvePosition = (Position == null) ? scaledOrigLCS : scaledOrigLCS.Multiply(Position); ISet <IList <CurveLoop> > disjointLoops = GetTransformedCurveLoops(unscaledRevolvePosition, scaledRevolvePosition); if (disjointLoops == null || disjointLoops.Count() == 0) { return(null); } XYZ frameOrigin = scaledRevolvePosition.OfPoint(Axis.Origin); XYZ frameZVec = scaledRevolvePosition.OfVector(Axis.BasisZ); SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in disjointLoops) { XYZ frameXVec = null; frameXVec = GetValidXVectorFromLoop(loops[0], frameZVec, frameOrigin); if (frameXVec == null) { Importer.TheLog.LogError(Id, "Couldn't generate valid frame for IfcRevolvedAreaSolid.", false); return(null); } XYZ frameYVec = frameZVec.CrossProduct(frameXVec); Frame coordinateFrame = new Frame(frameOrigin, frameXVec, frameYVec, frameZVec); GeometryObject myObj = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, loops, 0, Angle, solidOptions); if (myObj != null) { myObjs.Add(myObj); } } return(myObjs); }
private bool CreateSimpleRoomMassByExtrusion(Room room) { try { var height = room.LookupParameter("Limit Offset"); var curves = new List <CurveLoop>(); var spatialBoundaryOptions = new SpatialElementBoundaryOptions { StoreFreeBoundaryFaces = true }; var loop = new CurveLoop(); var boundarySegments = room.GetBoundarySegments(spatialBoundaryOptions); var biggestList = boundarySegments.OrderByDescending(item => item.Count).First(); foreach (var seg in biggestList) { loop.Append(seg.GetCurve()); } curves.Add(loop); var options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); var roomSolid = GeometryCreationUtilities.CreateExtrusionGeometry(curves, new XYZ(0, 0, 1), height.AsDouble(), options); if (roomSolid == null) { return(false); } var eid = new ElementId(BuiltInCategory.OST_Mass); #if REVIT2019 || REVIT2018 || REVIT2017 || REVIT2020 || REVIT2021 DirectShape roomShape = DirectShape.CreateElement(doc, eid); #else DirectShape roomShape = DirectShape.CreateElement(doc, eid, "A", "B"); #endif roomShape.SetShape(new GeometryObject[] { roomSolid }); CopyAllRoomParametersToMasses(room, roomShape); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return(false); } return(true); }
private static Solid CreateWallEndClippedWallGeometry(Wall wallElement, IList<IList<IFCConnectedWallData>> connectedWalls, Curve baseCurve, double unscaledWidth, double scaledDepth) { CurveLoop newLoop = SafeCreateViaThicken(baseCurve, unscaledWidth); if (newLoop == null) return null; IList<CurveLoop> boundaryLoops = new List<CurveLoop>(); boundaryLoops.Add(newLoop); XYZ normal = XYZ.BasisZ; SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); double unscaledDepth = UnitUtil.UnscaleLength(scaledDepth); Solid baseSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boundaryLoops, normal, scaledDepth, solidOptions); if (!GetDifferenceFromWallJoins(wallElement.Document, wallElement.Id, baseSolid, connectedWalls)) return null; return baseSolid; }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="unscaledLcs">The unscaled local coordinate system for the geometry, if the scaled version isn't supported downstream.</param> /// <param name="scaledLcs">The scaled (true) local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>The created geometry.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs, Transform scaledLcs, string guid) { Transform unscaledObjectPosition = (unscaledLcs == null) ? Position : unscaledLcs.Multiply(Position); Transform scaledObjectPosition = (scaledLcs == null) ? Position : scaledLcs.Multiply(Position); CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) { return(null); } CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(Id, baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. Transform originTrf0 = null; Curve firstCurve0 = trimmedDirectrix.First(); if (firstCurve0.IsBound) { startParam = firstCurve0.GetEndParameter(0); } originTrf0 = firstCurve0.ComputeDerivatives(startParam, false); if (originTrf0 == null) { return(null); } // Note: the computation of the reference Surface Local Transform must be done before the directrix is transform to LCS (because the ref surface isn't) // and therefore the origin is at the start of the curve should be the start of the directrix that lies on the surface. // This is needed to transform the swept area that must be perpendicular to the start of the directrix curve Transform referenceSurfaceLocalTransform = ReferenceSurface.GetTransformAtPoint(originTrf0.Origin); CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, Id, unscaledObjectPosition, scaledObjectPosition); // Create the sweep. Transform originTrf = null; Curve firstCurve = trimmedDirectrixInLCS.First(); //if (firstCurve.IsBound) // startParam = firstCurve.GetEndParameter(0); originTrf = firstCurve.ComputeDerivatives(startParam, false); Transform unscaledReferenceSurfaceTransform = unscaledObjectPosition.Multiply(referenceSurfaceLocalTransform); Transform scaledReferenceSurfaceTransform = scaledObjectPosition.Multiply(referenceSurfaceLocalTransform); Transform profileCurveLoopsTransform = Transform.CreateTranslation(originTrf.Origin); profileCurveLoopsTransform.BasisX = scaledReferenceSurfaceTransform.BasisZ; profileCurveLoopsTransform.BasisZ = originTrf.BasisX.Normalize(); profileCurveLoopsTransform.BasisY = profileCurveLoopsTransform.BasisZ.CrossProduct(profileCurveLoopsTransform.BasisX); ISet <IList <CurveLoop> > profileCurveLoops = GetTransformedCurveLoops(profileCurveLoopsTransform, profileCurveLoopsTransform); if (profileCurveLoops == null || profileCurveLoops.Count == 0) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in profileCurveLoops) { GeometryObject myObj = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, loops, solidOptions); if (myObj != null) { myObjs.Add(myObj); } } return(myObjs); }
/// <summary> /// Return a solid corresponding to the volume represented by boundingBoxXYZ. /// </summary> /// <param name="lcs">The local coordinate system of the bounding box; if null, assume the Identity transform.</param> /// <param name="boundingBoxXYZ">The bounding box.</param> /// <param name="solidOptions">The options for creating the solid. Allow null to mean default.</param> /// <returns>A solid of the same size and orientation as boundingBoxXYZ, or null if boundingBoxXYZ is invalid or null.</returns> /// <remarks>We don't do any checking on the input transform, which could have non-uniform scaling and/or mirroring. /// This could potentially lead to unexpected results, which we can examine if and when such cases arise.</remarks> public static Solid CreateSolidFromBoundingBox(Transform lcs, BoundingBoxXYZ boundingBoxXYZ, SolidOptions solidOptions) { // Check that the bounding box is valid. if (boundingBoxXYZ == null || !boundingBoxXYZ.Enabled) { return(null); } try { // Create a transform based on the incoming local coordinate system and the bounding box coordinate system. Transform bboxTransform = (lcs == null) ? boundingBoxXYZ.Transform : lcs.Multiply(boundingBoxXYZ.Transform); XYZ[] profilePts = new XYZ[4]; profilePts[0] = bboxTransform.OfPoint(boundingBoxXYZ.Min); profilePts[1] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Min.Z)); profilePts[2] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); profilePts[3] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); XYZ upperRightXYZ = bboxTransform.OfPoint(boundingBoxXYZ.Max); // If we assumed that the transforms had no scaling, // then we could simply take boundingBoxXYZ.Max.Z - boundingBoxXYZ.Min.Z. // This code removes that assumption. XYZ origExtrusionVector = new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Max.Z) - boundingBoxXYZ.Min; XYZ extrusionVector = bboxTransform.OfVector(origExtrusionVector); double extrusionDistance = extrusionVector.GetLength(); XYZ extrusionDirection = extrusionVector.Normalize(); CurveLoop baseLoop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { baseLoop.Append(Line.CreateBound(profilePts[ii], profilePts[(ii + 1) % 4])); } IList <CurveLoop> baseLoops = new List <CurveLoop>(); baseLoops.Add(baseLoop); if (solidOptions == null) { return(GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance)); } else { return(GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance, solidOptions)); } } catch { return(null); } }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>Zero or more created geometries.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform sweptDiskPosition = (lcs == null) ? Transform.Identity : lcs; CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) { return(null); } CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, sweptDiskPosition); // Create the disk. Transform originTrf = null; double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. foreach (Curve curve in trimmedDirectrixInLCS) { if (curve.IsBound) { startParam = curve.GetEndParameter(0); } originTrf = curve.ComputeDerivatives(startParam, false); break; } if (originTrf == null) { return(null); } // The X-dir of the transform of the start of the directrix will form the normal of the disk. Plane diskPlane = new Plane(originTrf.BasisX, originTrf.Origin); IList <CurveLoop> profileCurveLoops = new List <CurveLoop>(); CurveLoop diskOuterCurveLoop = new CurveLoop(); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, 0, Math.PI)); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskOuterCurveLoop); if (InnerRadius.HasValue) { CurveLoop diskInnerCurveLoop = new CurveLoop(); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, 0, Math.PI)); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskInnerCurveLoop); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, profileCurveLoops, solidOptions); IList <GeometryObject> myObjs = new List <GeometryObject>(); if (sweptDiskSolid != null) { myObjs.Add(sweptDiskSolid); } return(myObjs); }
private void CreateBoxShape(IFCImportShapeEditScope shapeEditScope, Transform scaledLcs) { using (IFCImportShapeEditScope.IFCContainingRepresentationSetter repSetter = new IFCImportShapeEditScope.IFCContainingRepresentationSetter(shapeEditScope, this)) { // Get the material and graphics style based in the "Box" sub-category of Generic Models. // We will create the sub-category if this is our first time trying to use it. // Note that all bounding boxes are controlled by a sub-category of Generic Models. We may revisit that decision later. SolidOptions solidOptions = null; Category bboxCategory = IFCCategoryUtil.GetSubCategoryForRepresentation(shapeEditScope.Document, Id, Identifier); if (bboxCategory != null) { ElementId materialId = (bboxCategory.Material == null) ? ElementId.InvalidElementId : bboxCategory.Material.Id; GraphicsStyle graphicsStyle = bboxCategory.GetGraphicsStyle(GraphicsStyleType.Projection); ElementId gstyleId = (graphicsStyle == null) ? ElementId.InvalidElementId : graphicsStyle.Id; solidOptions = new SolidOptions(materialId, gstyleId); } Solid bboxSolid = IFCGeometryUtil.CreateSolidFromBoundingBox(scaledLcs, BoundingBox, solidOptions); if (bboxSolid != null) { IFCSolidInfo bboxSolidInfo = IFCSolidInfo.Create(Id, bboxSolid); shapeEditScope.AddGeometry(bboxSolidInfo); } } return; }
/// <summary> /// Create geometry for an IfcHalfSpaceSolid. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>A list containing one geometry for the IfcHalfSpaceSolid.</returns> protected virtual IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { IFCPlane ifcPlane = BaseSurface as IFCPlane; Plane plane = ifcPlane.Plane; XYZ origin = plane.Origin; XYZ xVec = plane.XVec; XYZ yVec = plane.YVec; // Set some huge boundaries for now. const double largeCoordinateValue = 100000; XYZ[] corners = new XYZ[4] { lcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), lcs.OfPoint((xVec * largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), lcs.OfPoint((xVec * largeCoordinateValue) + (yVec * largeCoordinateValue) + origin), lcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * largeCoordinateValue) + origin) }; IList<CurveLoop> loops = new List<CurveLoop>(); CurveLoop loop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { if (AgreementFlag) loop.Append(Line.CreateBound(corners[(5 - ii) % 4], corners[(4 - ii) % 4])); else loop.Append(Line.CreateBound(corners[ii], corners[(ii + 1) % 4])); } loops.Add(loop); XYZ normal = lcs.OfVector(AgreementFlag ? -plane.Normal : plane.Normal); SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid baseSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, normal, largeCoordinateValue, solidOptions); if (BaseBoundingCurve != null) { CurveLoop polygonalBoundary = BaseBoundingCurve.CurveLoop; Transform totalTransform = lcs.Multiply(BaseBoundingCurveTransform); // Make sure this bounding polygon extends below base of half-space soild. Transform moveBaseTransform = Transform.Identity; moveBaseTransform.Origin = new XYZ(0, 0, -largeCoordinateValue); totalTransform = totalTransform.Multiply(moveBaseTransform); CurveLoop transformedPolygonalBoundary = IFCGeometryUtil.CreateTransformed(polygonalBoundary, totalTransform); IList<CurveLoop> boundingLoops = new List<CurveLoop>(); boundingLoops.Add(transformedPolygonalBoundary); Solid boundingSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boundingLoops, totalTransform.BasisZ, 2.0 * largeCoordinateValue, solidOptions); baseSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, BaseBoundingCurve.Id, baseSolid, boundingSolid, BooleanOperationsType.Intersect, null); } IList<GeometryObject> returnList = new List<GeometryObject>(); returnList.Add(baseSolid); return returnList; }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>One or more created geometries.</returns> /// <remarks>The scaledLcs is only partially supported in this routine; it allows scaling the depth of the extrusion, /// which is commonly found in ACA files.</remarks> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { if (Direction == null) { Importer.TheLog.LogError(Id, "Error processing IfcExtrudedAreaSolid, can't create geometry.", false); return null; } Transform origLCS = (lcs == null) ? Transform.Identity : lcs; Transform origScaledLCS = (scaledLcs == null) ? Transform.Identity : scaledLcs; Transform extrusionPosition = (Position == null) ? origLCS : origLCS.Multiply(Position); Transform scaledExtrusionPosition = (Position == null) ? origScaledLCS : origScaledLCS.Multiply(Position); XYZ extrusionDirection = extrusionPosition.OfVector(Direction); ISet<IList<CurveLoop>> disjointLoops = GetTransformedCurveLoops(extrusionPosition); if (disjointLoops == null || disjointLoops.Count() == 0) return null; IList<GeometryObject> extrusions = new List<GeometryObject>(); foreach (IList<CurveLoop> loops in disjointLoops) { SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); XYZ scaledDirection = scaledExtrusionPosition.OfVector(Direction); double currDepth = Depth * scaledDirection.GetLength(); GeometryObject extrusionObject = null; try { // We may try to create separate extrusions, one per layer here. bool shouldWarn = false; ElementId overrideMaterialId = ElementId.InvalidElementId; IList<GeometryObject> extrusionLayers = CreateGeometryFromMaterialLayerUsage(shapeEditScope, extrusionPosition, loops, extrusionDirection, currDepth, out overrideMaterialId, out shouldWarn); if (extrusionLayers == null || extrusionLayers.Count == 0) { if (shouldWarn) Importer.TheLog.LogWarning(Id, "Couldn't process associated IfcMaterialLayerSetUsage, using body geometry instead.", false); if (overrideMaterialId != ElementId.InvalidElementId) solidOptions.MaterialId = overrideMaterialId; extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, extrusionDirection, currDepth, solidOptions); } else { foreach (GeometryObject extrusionLayer in extrusionLayers) extrusions.Add(extrusionLayer); } } catch (Exception ex) { if (shapeEditScope.MustCreateSolid()) throw ex; Importer.TheLog.LogError(Id, "Extrusion has an invalid definition for a solid; reverting to mesh.", false); MeshFromGeometryOperationResult meshResult = TessellatedShapeBuilder.CreateMeshByExtrusion( loops, extrusionDirection, currDepth, GetMaterialElementId(shapeEditScope)); // will throw if mesh is not available extrusionObject = meshResult.GetMesh(); } if (extrusionObject != null) extrusions.Add(extrusionObject); } return extrusions; }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>One or more created Solids.</returns> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform origLCS = (lcs == null) ? Transform.Identity : lcs; Transform revolvePosition = (Position == null) ? origLCS : origLCS.Multiply(Position); ISet<IList<CurveLoop>> disjointLoops = GetTransformedCurveLoops(revolvePosition); if (disjointLoops == null || disjointLoops.Count() == 0) return null; XYZ frameOrigin = revolvePosition.OfPoint(Axis.Origin); XYZ frameZVec = revolvePosition.OfVector(Axis.BasisZ); SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList<GeometryObject> myObjs = new List<GeometryObject>(); foreach (IList<CurveLoop> loops in disjointLoops) { XYZ frameXVec = null; frameXVec = GetValidXVectorFromLoop(loops[0], frameZVec, frameOrigin); if (frameXVec == null) { Importer.TheLog.LogError(Id, "Couldn't generate valid frame for IfcRevolvedAreaSolid.", false); return null; } XYZ frameYVec = frameZVec.CrossProduct(frameXVec); Frame coordinateFrame = new Frame(frameOrigin, frameXVec, frameYVec, frameZVec); GeometryObject myObj = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, loops, 0, Angle, solidOptions); if (myObj != null) myObjs.Add(myObj); } return myObjs; }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { Transform lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity; // 2016+ only. Point point = Point.Create(lcs.Origin, GraphicsStyleId); // 2015+: create cone(s) for the direction of flow. CurveLoop rightTrangle = new CurveLoop(); const double radius = 0.5 / 12.0; const double height = 1.5 / 12.0; SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, GraphicsStyleId); Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ); // The origin is at the base of the cone for everything but source - then it is at the top of the cone. XYZ pt1 = FlowDirection == IFCFlowDirection.Source ? lcs.Origin - height * lcs.BasisZ : lcs.Origin; XYZ pt2 = pt1 + radius * lcs.BasisX; XYZ pt3 = pt1 + height * lcs.BasisZ; rightTrangle.Append(Line.CreateBound(pt1, pt2)); rightTrangle.Append(Line.CreateBound(pt2, pt3)); rightTrangle.Append(Line.CreateBound(pt3, pt1)); IList <CurveLoop> curveLoops = new List <CurveLoop>(); curveLoops.Add(rightTrangle); Solid portArrow = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, curveLoops, 0.0, Math.PI * 2.0, solidOptions); Solid oppositePortArrow = null; if (FlowDirection == IFCFlowDirection.SourceAndSink) { Frame oppositeCoordinateFrame = new Frame(lcs.Origin, -lcs.BasisX, lcs.BasisY, -lcs.BasisZ); CurveLoop oppositeRightTrangle = new CurveLoop(); XYZ oppPt2 = pt1 - radius * lcs.BasisX; XYZ oppPt3 = pt1 - height * lcs.BasisZ; oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2)); oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3)); oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1)); IList <CurveLoop> oppositeCurveLoops = new List <CurveLoop>(); oppositeCurveLoops.Add(oppositeRightTrangle); oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions); } if (portArrow != null) { IList <GeometryObject> geomObjs = new List <GeometryObject>(); if (point != null) { geomObjs.Add(point); } geomObjs.Add(portArrow); if (oppositePortArrow != null) { geomObjs.Add(oppositePortArrow); } DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs, Id); if (directShape != null) { CreatedGeometry = geomObjs; CreatedElementId = directShape.Id; } else { Importer.TheLog.LogCreationError(this, null, false); } } }
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; //EDGE PATH Reference edgeBack = uidoc.Selection.PickObject(ObjectType.Edge, "Select long edge"); //EDGE DIRECTION Reference edgeDirRef = uidoc.Selection.PickObject(ObjectType.Edge, "Select edge for direction"); //EDGE Element edgeBackElement = doc.GetElement(edgeBack); GeometryObject edgeBackObject = edgeBackElement.GetGeometryObjectFromReference(edgeBack); Edge elemEdge = edgeBackObject as Edge; Curve edgeBackCurve = elemEdge.AsCurve(); XYZ edgeBackDir = edgeBackCurve.GetEndPoint(1) - edgeBackCurve.GetEndPoint(0); //POINT ORDER: 1-5 back edge - extrusion path, 0-1 walkway width /* * 3 | 2 | | | | | | 5 | 0 | | 1 */ XYZ pt5 = edgeBackCurve.GetEndPoint(0); //pt5 should be the lowest Z point if (pt5.Z > edgeBackCurve.GetEndPoint(1).Z) { pt5 = edgeBackCurve.GetEndPoint(1); } //EDGE DIRECTION Element edgeDirElement = doc.GetElement(edgeDirRef); GeometryObject edgeDirObject = edgeDirElement.GetGeometryObjectFromReference(edgeDirRef); Edge edgeDirEdge = edgeDirObject as Edge; Curve edgeDirCurve = edgeDirEdge.AsCurve(); XYZ edgeDirDir = edgeDirCurve.GetEndPoint(1) - edgeDirCurve.GetEndPoint(0); double scale = 304.8; double offset = 1030 / scale; //distance from back edge to baseplate double width = 850 / scale; //egress width //PROFILE XYZ pt0 = edgeDirCurve.GetEndPoint(0); //towards tunnel XYZ pt1 = edgeBackCurve.GetEndPoint(0); //towards earth //XYZ pt2 = new XYZ(pt1.X, pt1.Y, pt1.Z+(2100/scale)); if (edgeDirCurve.GetEndPoint(0).DistanceTo(edgeBackCurve.GetEndPoint(0)) < edgeDirCurve.GetEndPoint(1).DistanceTo(edgeBackCurve.GetEndPoint(0))) { pt1 = edgeDirCurve.GetEndPoint(0); pt0 = edgeDirCurve.GetEndPoint(1); } else { pt1 = edgeDirCurve.GetEndPoint(1); pt0 = edgeDirCurve.GetEndPoint(0); } //XYZ perpVector = edgeDirDir.CrossProduct(edgeBackDir).Normalize(); //XYZ perpVector = (pt5 - pt1).CrossProduct(pt0 - pt1).Normalize(); //XYZ BASE Z XYZ perpVector = (new XYZ(pt1.X, pt1.Y, pt1.Z + 1) - pt1).Normalize(); pt1 = pt1 + (pt0 - pt1).Normalize() * (offset - width); pt0 = pt1 + (pt0 - pt1).Normalize() * width; XYZ pt2 = pt1 + perpVector * 2100 / scale; //XYZ pt3 = new XYZ(pt0.X, pt0.Y, pt0.Z+(2100/scale)); XYZ pt3 = pt0 + perpVector * 2100 / scale; //TOP FACE PLANE //Plane topPlane = Plane.CreateByThreePoints(pt0, pt1, pt5); CurveLoop path = CurveLoop.Create(new List <Curve> { edgeBackCurve }); //START CURVELOOP Line crv0 = Line.CreateBound(pt1, pt0); Line crv1 = Line.CreateBound(pt0, pt3); Line crv2 = Line.CreateBound(pt3, pt2); Line crv3 = Line.CreateBound(pt2, pt1); CurveLoop profileLoop = CurveLoop.Create(new List <Curve> { crv0, crv1, crv2, crv3 }); //PrintPoint(pt0, 1); //PrintPoint(pt1, 1); //PrintPoint(pt2, 1); //VERTICAL PLANE Plane p = Plane.CreateByThreePoints(pt0, pt1, pt2); //END CURVE LOOP Transform tf = Transform.CreateTranslation(edgeBackDir); Curve crv0tr = crv0.CreateTransformed(tf); Curve crv1tr = crv1.CreateTransformed(tf); Curve crv2tr = crv2.CreateTransformed(tf); Curve crv3tr = crv3.CreateTransformed(tf); CurveLoop profileLoopEnd = CurveLoop.Create(new List <Curve> { crv0tr, crv1tr, crv2tr, crv3tr }); Plane pEnd = Plane.CreateByThreePoints(crv0tr.GetEndPoint(0), crv0tr.GetEndPoint(1), crv1tr.GetEndPoint(1)); // WireframeBuilder builder = new WireframeBuilder(); // // builder.AddCurve(edgeBackCurve); ElementId categoryId = new ElementId(BuiltInCategory.OST_GenericModel); SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); using (Transaction t = new Transaction(doc, "Create model curves")) { t.Start(); try { //Solid sweep = GeometryCreationUtilities.CreateSweptGeometry(path, 0, edgeBackCurve.ComputeRawParameter(0.5), new List<CurveLoop> { profileLoop }); Solid loop = GeometryCreationUtilities.CreateLoftGeometry(new List <CurveLoop> { profileLoop, profileLoopEnd }, options); DirectShape ds = DirectShape.CreateElement(doc, categoryId); //ds.SetShape(builder); ds.SetShape(new GeometryObject[] { loop }); } catch (Exception ex) { TaskDialog.Show("Error", ex.Message); } //SketchPlane sp = SketchPlane.Create(doc, p); //SketchPlane spTop = SketchPlane.Create(doc, topPlane); //SketchPlane spEnd = SketchPlane.Create(doc, pEnd); //doc.Create.NewModelCurve(edgeBackCurve, spTop); // doc.Create.NewModelCurve(crv0, sp); // doc.Create.NewModelCurve(crv1, sp); // doc.Create.NewModelCurve(crv2, sp); // doc.Create.NewModelCurve(crv3, sp); //doc.Create.NewModelCurve(crv0tr, spEnd); //doc.Create.NewModelCurve(crv1tr, spEnd); //doc.Create.NewModelCurve(crv2tr, spEnd); //doc.Create.NewModelCurve(crv3tr, spEnd); t.Commit(); } TaskDialog.Show("R", PrintPoint(edgeBackCurve.GetEndPoint(0), scale) + ";\n" + PrintPoint(edgeBackCurve.GetEndPoint(1), scale) + ";\n" + PrintPoint(edgeDirCurve.GetEndPoint(0), scale)); return(Result.Succeeded); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>The created geometry.</returns> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform objectPosition = (lcs == null) ? Position : lcs.Multiply(Position); CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) return null; CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) return null; CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, objectPosition); // Create the sweep. double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. Transform originTrf = null; Curve firstCurve = trimmedDirectrixInLCS.First(); if (firstCurve.IsBound) startParam = firstCurve.GetEndParameter(0); originTrf = firstCurve.ComputeDerivatives(startParam, false); if (originTrf == null) return null; Transform referenceSurfaceLocalTransform = ReferenceSurface.GetTransformAtPoint(originTrf.Origin); Transform referenceSurfaceTransform = objectPosition.Multiply(referenceSurfaceLocalTransform); Transform profileCurveLoopsTransform = Transform.CreateTranslation(originTrf.Origin); profileCurveLoopsTransform.BasisX = referenceSurfaceTransform.BasisZ; profileCurveLoopsTransform.BasisZ = originTrf.BasisX.Normalize(); profileCurveLoopsTransform.BasisY = profileCurveLoopsTransform.BasisZ.CrossProduct(profileCurveLoopsTransform.BasisX); ISet<IList<CurveLoop>> profileCurveLoops = GetTransformedCurveLoops(profileCurveLoopsTransform); if (profileCurveLoops == null || profileCurveLoops.Count == 0) return null; SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList<GeometryObject> myObjs = new List<GeometryObject>(); foreach (IList<CurveLoop> loops in profileCurveLoops) { GeometryObject myObj = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, loops, solidOptions); if (myObj != null) myObjs.Add(myObj); } return myObjs; }
private GeometryObject CreateGeometryFromMateriaProfile(IFCImportShapeEditScope shapeEditScope, IList <CurveLoop> loops, XYZ extrusionDirection, double currDepth, SolidOptions solidOptions, out bool shouldWarn) { GeometryObject extrusionSolid = null; try { shouldWarn = true; // invalid input IIFCMaterialSelect materialSelect = shapeEditScope.Creator.MaterialSelect; if (materialSelect == null) { return(null); } IFCMaterialProfileSetUsage matProfSetUsage = materialSelect as IFCMaterialProfileSetUsage; if (matProfSetUsage == null) { return(null); } IFCMaterialProfileSet matProfSet = matProfSetUsage.ForProfileSet; if (matProfSet == null) { return(null); } IList <IFCMaterialProfile> matProfList = matProfSet.MaterialProfileSet; if (matProfList.Count == 0) { return(null); } Transform transformByOffset = Transform.Identity; IList <CurveLoop> newloops = new List <CurveLoop>(); ElementId materialId = null; foreach (IFCMaterialProfile matProf in matProfList) { if (this.SweptArea.Id == matProf.Profile.Id) { // This is the same id (same profile), use the material name for creation of this geometry IFCMaterial theMaterial = matProf.Material; if (theMaterial != null) { materialId = theMaterial.GetMaterialElementId(); solidOptions.MaterialId = materialId; // Override the original option if the profile has a specific material id } // Here we will handle special case if the Material Profile has Offset if (matProf is IFCMaterialProfileWithOffsets) { IFCMaterialProfileWithOffsets matProfOffset = matProf as IFCMaterialProfileWithOffsets; double startOffset = matProfOffset.OffsetValues[0]; double endOffset = 0; if (matProfOffset.OffsetValues.Count > 1) { endOffset = matProfOffset.OffsetValues[1]; } // To handle offset, we need to move the start point (extrusion position) to the startOffset value along the axis (extrusion direction) // For the end offset, we will have to re-calculate the extrusion currDepth = currDepth - startOffset + endOffset; transformByOffset.Origin += startOffset * extrusionDirection; foreach (CurveLoop loop in loops) { CurveLoop newLoop = CurveLoop.CreateViaTransform(loop, transformByOffset); newloops.Add(newLoop); } } break; } } if (newloops.Count == 0) { extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, extrusionDirection, currDepth, solidOptions); } else { extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(newloops, extrusionDirection, currDepth, solidOptions); } } catch { // Ignore the specific exception, but let the user know there was a problem processing the IfcMaterialLayerSetUsage. shouldWarn = true; return(null); } return(extrusionSolid); }
private IList<GeometryObject> SplitSweptDiskIntoValidPieces(CurveLoop trimmedDirectrixInWCS, IList<CurveLoop> profileCurveLoops, SolidOptions solidOptions) { // If we have 0 or 1 curves, there is nothing we can do here. int numCurves = trimmedDirectrixInWCS.Count(); if (numCurves < 2) return null; // We will attempt to represent the original description in as few pieces as possible. IList<Curve> directrixCurves = new List<Curve>(); foreach (Curve directrixCurve in trimmedDirectrixInWCS) { if (directrixCurve == null) { numCurves--; if (numCurves < 2) return null; continue; } directrixCurves.Add(directrixCurve); } IList<GeometryObject> sweptDiskPieces = new List<GeometryObject>(); // We will march along the directrix one curve at a time, trying to build a bigger piece of the sweep. At the point that we throw an exception, // we will take the last biggest piece and start over. CurveLoop currentCurveLoop = new CurveLoop(); Solid bestSolidSoFar = null; double pathAttachmentParam = directrixCurves[0].GetEndParameter(0); for (int ii = 0; ii < numCurves; ii++) { currentCurveLoop.Append(directrixCurves[ii]); try { Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; } catch { if (bestSolidSoFar != null) { sweptDiskPieces.Add(bestSolidSoFar); bestSolidSoFar = null; } } // This should only happen as a result of the catch loop above. We want to protect against the case where one or more pieces of the sweep // are completely invalid. while (bestSolidSoFar == null && (ii < numCurves)) { try { currentCurveLoop = new CurveLoop(); currentCurveLoop.Append(directrixCurves[ii]); profileCurveLoops = CreateProfileCurveLoopsForDirectrix(directrixCurves[ii], out pathAttachmentParam); Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; break; } catch { ii++; } } } return sweptDiskPieces; }
// This routine may return null geometry for one of three reasons: // 1. Invalid input. // 2. No IfcMaterialLayerUsage. // 3. The IfcMaterialLayerUsage isn't handled. // If the reason is #1 or #3, we want to warn the user. If it is #2, we don't. Pass back shouldWarn to let the caller know. private IList <GeometryObject> CreateGeometryFromMaterialLayerUsage(IFCImportShapeEditScope shapeEditScope, Transform extrusionPosition, IList <CurveLoop> loops, XYZ extrusionDirection, double currDepth, out ElementId materialId, out bool shouldWarn) { IList <GeometryObject> extrusionSolids = null; materialId = ElementId.InvalidElementId; try { shouldWarn = true; // Invalid input. // Check for valid input. if (shapeEditScope == null || extrusionPosition == null || loops == null || loops.Count() == 0 || extrusionDirection == null || !Application.IsValidThickness(currDepth)) { return(null); } IFCProduct creator = shapeEditScope.Creator; if (creator == null) { return(null); } shouldWarn = false; // Missing, empty, or optimized out IfcMaterialLayerSetUsage - valid reason to stop. IIFCMaterialSelect materialSelect = creator.MaterialSelect; if (materialSelect == null) { return(null); } IFCMaterialLayerSetUsage materialLayerSetUsage = materialSelect as IFCMaterialLayerSetUsage; if (materialLayerSetUsage == null) { return(null); } IFCMaterialLayerSet materialLayerSet = materialLayerSetUsage.MaterialLayerSet; if (materialLayerSet == null) { return(null); } IList <IFCMaterialLayer> materialLayers = materialLayerSet.MaterialLayers; if (materialLayers == null || materialLayers.Count == 0) { return(null); } // Optimization: if there is only one layer, use the standard method, with possibly an overloaded material. ElementId baseMaterialId = GetMaterialElementId(shapeEditScope); if (materialLayers.Count == 1) { IFCMaterial oneMaterial = materialLayers[0].Material; if (oneMaterial == null) { return(null); } materialId = oneMaterial.GetMaterialElementId(); if (materialId != ElementId.InvalidElementId) { // We will not override the material of the element if the layer material has no color. if (Importer.TheCache.MaterialsWithNoColor.Contains(materialId)) { materialId = ElementId.InvalidElementId; } } return(null); } // Anything below here is something we should report to the user, with the exception of the total thickness // not matching the extrusion thickness. This would require more analysis to determine that it is actually // an error condition. shouldWarn = true; IList <IFCMaterialLayer> realMaterialLayers = new List <IFCMaterialLayer>(); double totalThickness = 0.0; foreach (IFCMaterialLayer materialLayer in materialLayers) { double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) { continue; } if (depth < 0.0) { return(null); } realMaterialLayers.Add(materialLayer); totalThickness += depth; } // Axis3 means that the material layers are stacked in the Z direction. This is common for floor slabs. bool isAxis3 = (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis3); // For elements extruded in the Z direction, if the extrusion layers don't have the same thickness as the extrusion, // this could be one of two reasons: // 1. There is a discrepancy between the extrusion depth and the material layer set usage calculated depth. // 2. There are multiple extrusions in the body definition. // In either case, we will use the extrusion geometry over the calculated material layer set usage geometry. // In the future, we may decide to allow for case #1 by passing in a flag to allow for this. if (isAxis3 && !MathUtil.IsAlmostEqual(totalThickness, currDepth)) { shouldWarn = false; return(null); } int numLayers = realMaterialLayers.Count(); if (numLayers == 0) { return(null); } // We'll use this initial value for the Axis2 case, so read it here. double baseOffsetForLayer = materialLayerSetUsage.Offset; // Needed for Axis2 case only. The axisCurve is the curve defined in the product representation representing // a base curve (an axis) for the footprint of the element. Curve axisCurve = null; // The oriented cuve list represents the 4 curves of supported Axis2 footprint in the following order: // 1. curve along length of object closest to the first material layer with the orientation of the axis curve // 2. connecting end curve // 3. curve along length of object closest to the last material layer with the orientation opposite of the axis curve // 4. connecting end curve. IList <Curve> orientedCurveList = null; if (!isAxis3) { // Axis2 means that the material layers are stacked inthe Y direction. This is by definition for IfcWallStandardCase, // which has a local coordinate system whose Y direction is orthogonal to the length of the wall. if (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis2) { axisCurve = GetAxisCurve(creator, extrusionPosition); if (axisCurve == null) { return(null); } orientedCurveList = GetOrientedCurveList(loops, axisCurve, extrusionPosition.BasisZ, baseOffsetForLayer, totalThickness); if (orientedCurveList == null) { return(null); } } else { return(null); // Not handled. } } extrusionSolids = new List <GeometryObject>(); bool positiveOrientation = (materialLayerSetUsage.DirectionSense == IFCDirectionSense.Positive); // Always extrude in the positive direction for Axis2. XYZ materialExtrusionDirection = (positiveOrientation || !isAxis3) ? extrusionDirection : -extrusionDirection; // Axis2 repeated values. // The IFC concept of offset direction is reversed from Revit's. XYZ normalDirectionForAxis2 = positiveOrientation ? -extrusionPosition.BasisZ : extrusionPosition.BasisZ; bool axisIsCyclic = (axisCurve == null) ? false : axisCurve.IsCyclic; double axisCurvePeriod = axisIsCyclic ? axisCurve.Period : 0.0; Transform curveLoopTransform = Transform.Identity; IList <CurveLoop> currLoops = null; double depthSoFar = 0.0; for (int ii = 0; ii < numLayers; ii++) { IFCMaterialLayer materialLayer = materialLayers[ii]; // Ignore 0 thickness layers. No need to warn. double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) { continue; } // If the thickness is non-zero but invalid, fail. if (!Application.IsValidThickness(depth)) { return(null); } double extrusionDistance = 0.0; if (isAxis3) { // Offset the curve loops if necessary, using the base extrusionDirection, regardless of the direction sense // of the MaterialLayerSetUsage. double offsetForLayer = positiveOrientation ? baseOffsetForLayer + depthSoFar : baseOffsetForLayer - depthSoFar; if (!MathUtil.IsAlmostZero(offsetForLayer)) { curveLoopTransform.Origin = offsetForLayer * extrusionDirection; currLoops = new List <CurveLoop>(); foreach (CurveLoop loop in loops) { CurveLoop newLoop = CurveLoop.CreateViaTransform(loop, curveLoopTransform); if (newLoop == null) { return(null); } currLoops.Add(newLoop); } } else { currLoops = loops; } extrusionDistance = depth; } else { // startClipCurve, firstEndCapCurve, endClipCurve, secondEndCapCurve. Curve[] outline = new Curve[4]; double[][] endParameters = new double[4][]; double startClip = depthSoFar; double endClip = depthSoFar + depth; outline[0] = orientedCurveList[0].CreateOffset(startClip, normalDirectionForAxis2); outline[1] = orientedCurveList[1].Clone(); outline[2] = orientedCurveList[2].CreateOffset(totalThickness - endClip, normalDirectionForAxis2); outline[3] = orientedCurveList[3].Clone(); for (int jj = 0; jj < 4; jj++) { outline[jj].MakeUnbound(); endParameters[jj] = new double[2]; endParameters[jj][0] = 0.0; endParameters[jj][1] = 0.0; } // Trim/Extend the curves so that they make a closed loop. for (int jj = 0; jj < 4; jj++) { IntersectionResultArray resultArray = null; outline[jj].Intersect(outline[(jj + 1) % 4], out resultArray); if (resultArray == null || resultArray.Size == 0) { return(null); } int numResults = resultArray.Size; if ((numResults > 1 && !axisIsCyclic) || (numResults > 2)) { return(null); } UV intersectionPoint = resultArray.get_Item(0).UVPoint; endParameters[jj][1] = intersectionPoint.U; endParameters[(jj + 1) % 4][0] = intersectionPoint.V; if (numResults == 2) { // If the current result is closer to the end of the curve, keep it. UV newIntersectionPoint = resultArray.get_Item(1).UVPoint; int endParamIndex = (jj % 2); double newParamToCheck = newIntersectionPoint[endParamIndex]; double oldParamToCheck = (endParamIndex == 0) ? endParameters[jj][1] : endParameters[(jj + 1) % 4][0]; double currentEndPoint = (endParamIndex == 0) ? orientedCurveList[jj].GetEndParameter(1) : orientedCurveList[(jj + 1) % 4].GetEndParameter(0); // Put in range of [-Period/2, Period/2]. double newDist = (currentEndPoint - newParamToCheck) % axisCurvePeriod; if (newDist < -axisCurvePeriod / 2.0) { newDist += axisCurvePeriod; } if (newDist > axisCurvePeriod / 2.0) { newDist -= axisCurvePeriod; } double oldDist = (currentEndPoint - oldParamToCheck) % axisCurvePeriod; if (oldDist < -axisCurvePeriod / 2.0) { oldDist += axisCurvePeriod; } if (oldDist > axisCurvePeriod / 2.0) { oldDist -= axisCurvePeriod; } if (Math.Abs(newDist) < Math.Abs(oldDist)) { endParameters[jj][1] = newIntersectionPoint.U; endParameters[(jj + 1) % 4][0] = newIntersectionPoint.V; } } } CurveLoop newCurveLoop = new CurveLoop(); for (int jj = 0; jj < 4; jj++) { if (endParameters[jj][1] < endParameters[jj][0]) { if (!outline[jj].IsCyclic) { return(null); } endParameters[jj][1] += Math.Floor(endParameters[jj][0] / axisCurvePeriod + 1.0) * axisCurvePeriod; } outline[jj].MakeBound(endParameters[jj][0], endParameters[jj][1]); newCurveLoop.Append(outline[jj]); } currLoops = new List <CurveLoop>(); currLoops.Add(newCurveLoop); extrusionDistance = currDepth; } // Determine the material id. IFCMaterial material = materialLayer.Material; ElementId layerMaterialId = (material == null) ? ElementId.InvalidElementId : material.GetMaterialElementId(); // The second option here is really for Referencing. Without a UI (yet) to determine whether to show the base // extusion or the layers for objects with material layer sets, we've chosen to display the base material if the layer material // has no color information. This means that the layer is assigned the "wrong" material, but looks better on screen. // We will reexamine this decision (1) for the Open case, (2) if there is UI to toggle between layers and base extrusion, or // (3) based on user feedback. if (layerMaterialId == ElementId.InvalidElementId || Importer.TheCache.MaterialsWithNoColor.Contains(layerMaterialId)) { layerMaterialId = baseMaterialId; } SolidOptions solidOptions = new SolidOptions(layerMaterialId, shapeEditScope.GraphicsStyleId); // Create the extrusion for the material layer. GeometryObject extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry( currLoops, materialExtrusionDirection, extrusionDistance, solidOptions); if (extrusionSolid == null) { return(null); } extrusionSolids.Add(extrusionSolid); depthSoFar += depth; } } catch { // Ignore the specific exception, but let the user know there was a problem processing the IfcMaterialLayerSetUsage. shouldWarn = true; return(null); } return(extrusionSolids); }
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Application app = uiapp.Application; Document doc = uidoc.Document; string id_addin = uiapp.ActiveAddInId.GetGUID() .ToString(); IEnumerable <Room> rooms = new FilteredElementCollector(doc) .WhereElementIsNotElementType() .OfClass(typeof(SpatialElement)) .Where(e => e.GetType() == typeof(Room)) .Cast <Room>(); // Collect room data for glTF export List <GltfNodeData> room_data = new List <GltfNodeData>( rooms.Count <Room>()); // Collect geometry data for glTF: a list of // vertex coordinates in millimetres, and a list // of triangle vertex indices into the coord list. List <IntPoint3d> gltf_coords = new List <IntPoint3d>(); List <TriangleIndices> gltf_indices = new List <TriangleIndices>(); using (Transaction tx = new Transaction(doc)) { tx.Start("Generate Direct Shape Elements " + "Representing Room Volumes"); foreach (Room r in rooms) { Debug.Print("Processing " + r.Name + "..."); // Collect data for current room GltfNodeData rd = new GltfNodeData(r); GeometryElement geo = r.ClosedShell; Debug.Assert( geo.First <GeometryObject>() is Solid, "expected a solid for room closed shell"); Solid solid = geo.First <GeometryObject>() as Solid; #region Fix the shape #if FIX_THE_SHAPE_SOMEHOW // Create IList step by step Solid solid = geo.First <GeometryObject>() as Solid; // The room closed shell solid faces have a // non-null graphics style id: // Interior Fill 106074 // The sphere faces' graphics style id is null. // Maybe this graphics style does something // weird in the Forge viewer? // Let's create a copy of the room solid and // see whether that resets the graphics style. solid = SolidUtils.CreateTransformed( solid, Transform.Identity); shape = new GeometryObject[] { solid }; // Create a sphere var center = XYZ.Zero; double radius = 2.0; var p = center + radius * XYZ.BasisY; var q = center - radius * XYZ.BasisY; var profile = new List <Curve>(); profile.Add(Line.CreateBound(p, q)); profile.Add(Arc.Create(q, p, center + radius * XYZ.BasisX)); var curveLoop = CurveLoop.Create(profile); var options = new SolidOptions( ElementId.InvalidElementId, // material ElementId.InvalidElementId); // graphics style var frame = new Frame(center, XYZ.BasisX, -XYZ.BasisZ, XYZ.BasisY); var sphere = GeometryCreationUtilities .CreateRevolvedGeometry(frame, new CurveLoop[] { curveLoop }, 0, 2 * Math.PI, options); shape = new GeometryObject[] { solid, sphere }; #endif // #if FIX_THE_SHAPE_SOMEHOW #endregion // Fix the shape IList <GeometryObject> shape = geo.ToList <GeometryObject>(); // Previous counts define offsets // to new binary data rd.CoordinatesBegin = gltf_coords.Count; rd.TriangleVertexIndicesBegin = gltf_indices.Count; // Create a new solid to use for the direct // shape from the flawed solid returned by // GetClosedShell and gather glTF facet data shape = CopyGeometry(geo, ElementId.InvalidElementId, gltf_coords, gltf_indices); rd.CoordinatesCount = gltf_coords.Count - rd.CoordinatesBegin; rd.TriangleVertexIndexCount = gltf_indices.Count - rd.TriangleVertexIndicesBegin; IEnumerable <IntPoint3d> pts = gltf_coords.Skip <IntPoint3d>( rd.CoordinatesBegin); rd.Min = new IntPoint3d( pts.Min <IntPoint3d, int>(p => p.X), pts.Min <IntPoint3d, int>(p => p.Y), pts.Min <IntPoint3d, int>(p => p.Z)); rd.Max = new IntPoint3d( pts.Max <IntPoint3d, int>(p => p.X), pts.Max <IntPoint3d, int>(p => p.Y), pts.Max <IntPoint3d, int>(p => p.Z)); Dictionary <string, string> param_values = GetParamValues(r); string json = FormatDictAsJson(param_values); DirectShape ds = DirectShape.CreateElement( doc, _id_category_for_direct_shape); ds.ApplicationId = id_addin; ds.ApplicationDataId = r.UniqueId; ds.SetShape(shape); ds.get_Parameter(_bip_properties).Set(json); ds.Name = "Room volume for " + r.Name; room_data.Add(rd); } tx.Commit(); } // Save glTF text and binary data to two files; // metadata, min, max, buffer information; // vertex coordinates and triangle indices // Path.GetTempPath() returns a weird subdirectory // created by Revit, so we will not use that here, e.g., // C:\Users\tammikj\AppData\Local\Temp\bfd59506-2dff-4b0f-bbe4-31587fcaf508 //string path = Path.GetTempPath(); string path = "C:/tmp"; path = Path.Combine(path, doc.Title + "_gltf"); using (StreamWriter s = new StreamWriter( path + ".txt")) { int n = room_data.Count; s.WriteLine("{0} room{1}", n, ((1 == n) ? "" : "s")); s.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8}", "id", // "ElementId", "uid", // "UniqueId", "name", // "RoomName", "min", "max", "coord begin", // "CoordinatesBegin", "count", // "CoordinatesCount", "indices begin", // "TriangleVertexIndicesBegin", "count"); // "TriangleVertexIndexCount" foreach (GltfNodeData rd in room_data) { s.WriteLine(rd.ToString()); } } using (FileStream f = File.Create(path + ".bin")) { using (BinaryWriter writer = new BinaryWriter(f)) { foreach (IntPoint3d p in gltf_coords) { writer.Write((float)p.X); writer.Write((float)p.Y); writer.Write((float)p.Z); } foreach (TriangleIndices ti in gltf_indices) { foreach (int i in ti.Indices) { Debug.Assert(ushort.MaxValue > i, "expected vertex index to fit into unsigned short"); writer.Write((ushort)i); } } } } return(Result.Succeeded); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>The created geometry.</returns> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform objectPosition = (lcs == null) ? Position : lcs.Multiply(Position); CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) { return(null); } CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) { return(null); } CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, objectPosition); // Create the sweep. double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. Transform originTrf = null; Curve firstCurve = trimmedDirectrixInLCS.First(); if (firstCurve.IsBound) { startParam = firstCurve.GetEndParameter(0); } originTrf = firstCurve.ComputeDerivatives(startParam, false); if (originTrf == null) { return(null); } Transform referenceSurfaceLocalTransform = ReferenceSurface.GetTransformAtPoint(originTrf.Origin); Transform referenceSurfaceTransform = objectPosition.Multiply(referenceSurfaceLocalTransform); Transform profileCurveLoopsTransform = Transform.CreateTranslation(originTrf.Origin); profileCurveLoopsTransform.BasisX = referenceSurfaceTransform.BasisZ; profileCurveLoopsTransform.BasisZ = originTrf.BasisX.Normalize(); profileCurveLoopsTransform.BasisY = profileCurveLoopsTransform.BasisZ.CrossProduct(profileCurveLoopsTransform.BasisX); ISet <IList <CurveLoop> > profileCurveLoops = GetTransformedCurveLoops(profileCurveLoopsTransform); if (profileCurveLoops == null || profileCurveLoops.Count == 0) { return(null); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList <GeometryObject> myObjs = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in profileCurveLoops) { GeometryObject myObj = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, loops, solidOptions); if (myObj != null) { myObjs.Add(myObj); } } return(myObjs); }
/// <summary> /// Create geometry for an IfcHalfSpaceSolid. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>A list containing one geometry for the IfcHalfSpaceSolid.</returns> protected virtual IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs, Transform scaledLcs, string guid) { IFCPlane ifcPlane = BaseSurface as IFCPlane; Plane plane = ifcPlane.Plane; XYZ origin = plane.Origin; XYZ xVec = plane.XVec; XYZ yVec = plane.YVec; // Set some huge boundaries for now. const double largeCoordinateValue = 100000; XYZ[] corners = new XYZ[4] { unscaledLcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), unscaledLcs.OfPoint((xVec * largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin), unscaledLcs.OfPoint((xVec * largeCoordinateValue) + (yVec * largeCoordinateValue) + origin), unscaledLcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * largeCoordinateValue) + origin) }; IList <CurveLoop> loops = new List <CurveLoop>(); CurveLoop loop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { if (AgreementFlag) { loop.Append(Line.CreateBound(corners[(5 - ii) % 4], corners[(4 - ii) % 4])); } else { loop.Append(Line.CreateBound(corners[ii], corners[(ii + 1) % 4])); } } loops.Add(loop); XYZ normal = unscaledLcs.OfVector(AgreementFlag ? -plane.Normal : plane.Normal); SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid baseSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loops, normal, largeCoordinateValue, solidOptions); if (BaseBoundingCurve != null) { CurveLoop polygonalBoundary = BaseBoundingCurve.CurveLoop; Transform unscaledTotalTransform = unscaledLcs.Multiply(BaseBoundingCurveTransform); Transform scaledTotalTransform = scaledLcs.Multiply(BaseBoundingCurveTransform); // Make sure this bounding polygon extends below base of half-space soild. Transform moveBaseTransform = Transform.Identity; moveBaseTransform.Origin = new XYZ(0, 0, -largeCoordinateValue); unscaledTotalTransform = unscaledTotalTransform.Multiply(moveBaseTransform); scaledTotalTransform = scaledTotalTransform.Multiply(moveBaseTransform); CurveLoop transformedPolygonalBoundary = IFCGeometryUtil.CreateTransformed(polygonalBoundary, Id, unscaledTotalTransform, scaledTotalTransform); IList <CurveLoop> boundingLoops = new List <CurveLoop>(); boundingLoops.Add(transformedPolygonalBoundary); Solid boundingSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boundingLoops, unscaledTotalTransform.BasisZ, 2.0 * largeCoordinateValue, solidOptions); baseSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, BaseBoundingCurve.Id, baseSolid, boundingSolid, BooleanOperationsType.Intersect, null); } IList <GeometryObject> returnList = new List <GeometryObject>(); returnList.Add(baseSolid); return(returnList); }
public static void DoJob(DesignAutomationData data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } Application rvtApp = data.RevitApp; if (rvtApp == null) { throw new InvalidDataException(nameof(rvtApp)); } string modelPath = data.FilePath; if (String.IsNullOrWhiteSpace(modelPath)) { throw new InvalidDataException(nameof(modelPath)); } Document rvtDoc = data.RevitDoc; if (rvtDoc == null) { throw new InvalidOperationException("Could not open document!"); } //add shared parameter definition AddSetOfSharedParameters(rvtDoc); try { // Deleting existing DirectShape // might need to filter out the shapes for room only? // get ready to filter across just the elements visible in a view FilteredElementCollector coll = new FilteredElementCollector(rvtDoc); coll.OfClass(typeof(DirectShape)); IEnumerable <DirectShape> DSdelete = coll.Cast <DirectShape>(); using (Transaction tx = new Transaction(rvtDoc)) { tx.Start("Delete Direct Shape"); try { foreach (DirectShape ds in DSdelete) { ICollection <ElementId> ids = rvtDoc.Delete(ds.Id); } tx.Commit(); } catch (ArgumentException) { tx.RollBack(); throw new InvalidOperationException("Delete Direct Shape Failed!"); } } //get all rooms FilteredElementCollector m_Collector = new FilteredElementCollector(rvtDoc); m_Collector.OfCategory(BuiltInCategory.OST_Rooms); IList <Element> m_Rooms = m_Collector.ToElements(); int roomNbre = 0; ElementId roomId = null; // Iterate the list and gather a list of boundaries foreach (Room room in m_Rooms) { // Avoid unplaced rooms if (room.Area > 1) { String _family_name = "testRoom-" + room.UniqueId.ToString(); using (Transaction tr = new Transaction(rvtDoc)) { tr.Start("Create Mass"); // Found BBOX BoundingBoxXYZ bb = room.get_BoundingBox(null); XYZ pt = new XYZ((bb.Min.X + bb.Max.X) / 2, (bb.Min.Y + bb.Max.Y) / 2, bb.Min.Z); // Get the room boundary IList <IList <BoundarySegment> > boundaries = room.GetBoundarySegments(new SpatialElementBoundaryOptions()); // 2012 // a room may have a null boundary property: int n = 0; if (null != boundaries) { n = boundaries.Count; } // The array of boundary curves CurveArray m_CurveArray = new CurveArray(); // Add Direct Shape List <CurveLoop> curveLoopList = new List <CurveLoop>(); if (0 < n) { int iBoundary = 0, iSegment; foreach (IList <BoundarySegment> b in boundaries) // 2012 { List <Curve> profile = new List <Curve>(); ++iBoundary; iSegment = 0; foreach (BoundarySegment s in b) { ++iSegment; Curve curve = s.GetCurve(); // 2016 profile.Add(curve); //add shape for instant object } try { CurveLoop curveLoop = CurveLoop.Create(profile); curveLoopList.Add(curveLoop); } catch (Exception ex) { //Debug.WriteLine(ex.Message); } } } try { SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId); Frame frame = new Frame(pt, XYZ.BasisX, -XYZ.BasisZ, XYZ.BasisY); // Simple insertion point XYZ pt1 = new XYZ(0, 0, 0); // Our normal point that points the extrusion directly up XYZ ptNormal = new XYZ(0, 0, 100); // The plane to extrude the mass from Plane m_Plane = Plane.CreateByNormalAndOrigin(ptNormal, pt1); SketchPlane m_SketchPlane = SketchPlane.Create(rvtDoc, m_Plane); // 2014 Location loc = room.Location; LocationPoint lp = loc as LocationPoint; Level oBelow = getNearestBelowLevel(rvtDoc, lp.Point.Z); Level oUpper = getNearestUpperLevel(rvtDoc, lp.Point.Z); double height = oUpper.Elevation - oBelow.Elevation; Solid roomSolid; roomSolid = GeometryCreationUtilities.CreateExtrusionGeometry(curveLoopList, ptNormal, height); DirectShape ds = DirectShape.CreateElement(rvtDoc, new ElementId(BuiltInCategory.OST_GenericModel)); ds.SetShape(new GeometryObject[] { roomSolid }); roomId = ds.Id; roomNbre += 1; tr.Commit(); } catch (Exception e) { Console.WriteLine(e.Message); } } using (Transaction tx = new Transaction(rvtDoc)) { tx.Start("Change P"); Element readyDS = rvtDoc.GetElement(roomId); Parameter p = readyDS.LookupParameter("RoomNumber"); if (p != null) { p.Set(room.Number.ToString()); } tx.Commit(); } } } } catch (Exception ex) { throw new InvalidOperationException(ex.ToString()); } }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>One or more created geometries.</returns> /// <remarks>The scaledLcs is only partially supported in this routine; it allows scaling the depth of the extrusion, /// which is commonly found in ACA files.</remarks> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { if (Direction == null) { Importer.TheLog.LogError(Id, "Error processing IfcExtrudedAreaSolid, can't create geometry.", false); return(null); } Transform origLCS = (lcs == null) ? Transform.Identity : lcs; Transform origScaledLCS = (scaledLcs == null) ? Transform.Identity : scaledLcs; Transform unscaledExtrusionPosition = (Position == null) ? origLCS : origLCS.Multiply(Position); Transform scaledExtrusionPosition = (Position == null) ? origScaledLCS : origScaledLCS.Multiply(Position); XYZ scaledExtrusionDirection = scaledExtrusionPosition.OfVector(Direction); ISet <IList <CurveLoop> > disjointLoops = GetTransformedCurveLoops(unscaledExtrusionPosition, scaledExtrusionPosition); if (disjointLoops == null || disjointLoops.Count() == 0) { return(null); } IList <GeometryObject> extrusions = new List <GeometryObject>(); foreach (IList <CurveLoop> originalLoops in disjointLoops) { SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); XYZ scaledDirection = scaledExtrusionPosition.OfVector(Direction); double currDepth = Depth * scaledDirection.GetLength(); IList <CurveLoop> loops = new List <CurveLoop>(); foreach (CurveLoop originalLoop in originalLoops) { if (!originalLoop.IsOpen()) { loops.Add(originalLoop); continue; } if (originalLoop.Count() > 0) { try { // We will attempt to close the loop to make it usable. XYZ startPoint = originalLoop.First().GetEndPoint(0); XYZ endPoint = originalLoop.Last().GetEndPoint(1); Line closingLine = Line.CreateBound(endPoint, startPoint); CurveLoop healedCurveLoop = CurveLoop.CreateViaCopy(originalLoop); healedCurveLoop.Append(closingLine); loops.Add(healedCurveLoop); Importer.TheLog.LogWarning(Id, "Extrusion has an open profile loop, fixing.", false); continue; } catch { } } Importer.TheLog.LogError(Id, "Extrusion has an open profile loop, ignoring.", false); } if (loops.Count == 0) { continue; } GeometryObject extrusionObject = null; try { // We may try to create separate extrusions, one per layer here. bool shouldWarn = false; ElementId overrideMaterialId = ElementId.InvalidElementId; if (shapeEditScope.Creator.MaterialSelect != null) { if (shapeEditScope.Creator.MaterialSelect is IFCMaterialLayerSetUsage) { IList <GeometryObject> extrusionLayers = CreateGeometryFromMaterialLayerUsage(shapeEditScope, scaledExtrusionPosition, loops, scaledExtrusionDirection, currDepth, out overrideMaterialId, out shouldWarn); if (extrusionLayers == null || extrusionLayers.Count == 0) { if (shouldWarn) { Importer.TheLog.LogWarning(Id, "Couldn't process associated IfcMaterialLayerSetUsage, using body geometry instead.", false); } if (overrideMaterialId != ElementId.InvalidElementId) { solidOptions.MaterialId = overrideMaterialId; } extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, scaledExtrusionDirection, currDepth, solidOptions); } else { foreach (GeometryObject extrusionLayer in extrusionLayers) { extrusions.Add(extrusionLayer); } } } else if (shapeEditScope.Creator.MaterialSelect is IFCMaterialProfileSetUsage) { extrusionObject = CreateGeometryFromMaterialProfile(shapeEditScope, loops, scaledExtrusionDirection, currDepth, solidOptions, out shouldWarn); if (extrusionObject == null) { extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, scaledExtrusionDirection, currDepth, solidOptions); } } else { extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, scaledExtrusionDirection, currDepth, solidOptions); } } else { extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, scaledExtrusionDirection, currDepth, solidOptions); } } catch (Exception ex) { extrusionObject = GetMeshBackup(shapeEditScope, loops, scaledExtrusionDirection, currDepth); if (extrusionObject == null) { throw ex; } } if (extrusionObject != null) { if (!(extrusionObject is Solid) || IFCGeometryUtil.ValidateGeometry(extrusionObject as Solid)) { extrusions.Add(extrusionObject); } else { Mesh meshBackup = GetMeshBackup(shapeEditScope, loops, scaledExtrusionDirection, currDepth); if (meshBackup != null) { extrusions.Add(meshBackup); } } } } return(extrusions); }
// This routine may return null geometry for one of three reasons: // 1. Invalid input. // 2. No IfcMaterialLayerUsage. // 3. The IfcMaterialLayerUsage isn't handled. // If the reason is #1 or #3, we want to warn the user. If it is #2, we don't. Pass back shouldWarn to let the caller know. private IList<GeometryObject> CreateGeometryFromMaterialLayerUsage(IFCImportShapeEditScope shapeEditScope, Transform extrusionPosition, IList<CurveLoop> loops, XYZ extrusionDirection, double currDepth, out ElementId materialId, out bool shouldWarn) { IList<GeometryObject> extrusionSolids = null; materialId = ElementId.InvalidElementId; try { shouldWarn = true; // Invalid input. // Check for valid input. if (shapeEditScope == null || extrusionPosition == null || loops == null || loops.Count() == 0 || extrusionDirection == null || !Application.IsValidThickness(currDepth)) return null; IFCProduct creator = shapeEditScope.Creator; if (creator == null) return null; shouldWarn = false; // Missing, empty, or optimized out IfcMaterialLayerSetUsage - valid reason to stop. IIFCMaterialSelect materialSelect = creator.MaterialSelect; if (materialSelect == null) return null; IFCMaterialLayerSetUsage materialLayerSetUsage = materialSelect as IFCMaterialLayerSetUsage; if (materialLayerSetUsage == null) return null; IFCMaterialLayerSet materialLayerSet = materialLayerSetUsage.MaterialLayerSet; if (materialLayerSet == null) return null; IList<IFCMaterialLayer> materialLayers = materialLayerSet.MaterialLayers; if (materialLayers == null || materialLayers.Count == 0) return null; // Optimization: if there is only one layer, use the standard method, with possibly an overloaded material. ElementId baseMaterialId = GetMaterialElementId(shapeEditScope); if (materialLayers.Count == 1) { IFCMaterial oneMaterial = materialLayers[0].Material; if (oneMaterial == null) return null; materialId = oneMaterial.GetMaterialElementId(); if (materialId != ElementId.InvalidElementId) { // We will not override the material of the element if the layer material has no color. if (Importer.TheCache.MaterialsWithNoColor.Contains(materialId)) materialId = ElementId.InvalidElementId; } return null; } // Anything below here is something we should report to the user, with the exception of the total thickness // not matching the extrusion thickness. This would require more analysis to determine that it is actually // an error condition. shouldWarn = true; IList<IFCMaterialLayer> realMaterialLayers = new List<IFCMaterialLayer>(); double totalThickness = 0.0; foreach (IFCMaterialLayer materialLayer in materialLayers) { double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) continue; if (depth < 0.0) return null; realMaterialLayers.Add(materialLayer); totalThickness += depth; } // Axis3 means that the material layers are stacked in the Z direction. This is common for floor slabs. bool isAxis3 = (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis3); // For elements extruded in the Z direction, if the extrusion layers don't have the same thickness as the extrusion, // this could be one of two reasons: // 1. There is a discrepancy between the extrusion depth and the material layer set usage calculated depth. // 2. There are multiple extrusions in the body definition. // In either case, we will use the extrusion geometry over the calculated material layer set usage geometry. // In the future, we may decide to allow for case #1 by passing in a flag to allow for this. if (isAxis3 && !MathUtil.IsAlmostEqual(totalThickness, currDepth)) { shouldWarn = false; return null; } int numLayers = realMaterialLayers.Count(); if (numLayers == 0) return null; // We'll use this initial value for the Axis2 case, so read it here. double baseOffsetForLayer = materialLayerSetUsage.Offset; // Needed for Axis2 case only. The axisCurve is the curve defined in the product representation representing // a base curve (an axis) for the footprint of the element. Curve axisCurve = null; // The oriented cuve list represents the 4 curves of supported Axis2 footprint in the following order: // 1. curve along length of object closest to the first material layer with the orientation of the axis curve // 2. connecting end curve // 3. curve along length of object closest to the last material layer with the orientation opposite of the axis curve // 4. connecting end curve. IList<Curve> orientedCurveList = null; if (!isAxis3) { // Axis2 means that the material layers are stacked inthe Y direction. This is by definition for IfcWallStandardCase, // which has a local coordinate system whose Y direction is orthogonal to the length of the wall. if (materialLayerSetUsage.Direction == IFCLayerSetDirection.Axis2) { axisCurve = GetAxisCurve(creator, extrusionPosition); if (axisCurve == null) return null; orientedCurveList = GetOrientedCurveList(loops, axisCurve, extrusionPosition.BasisZ, baseOffsetForLayer, totalThickness); if (orientedCurveList == null) return null; } else return null; // Not handled. } extrusionSolids = new List<GeometryObject>(); bool positiveOrientation = (materialLayerSetUsage.DirectionSense == IFCDirectionSense.Positive); // Always extrude in the positive direction for Axis2. XYZ materialExtrusionDirection = (positiveOrientation || !isAxis3) ? extrusionDirection : -extrusionDirection; // Axis2 repeated values. // The IFC concept of offset direction is reversed from Revit's. XYZ normalDirectionForAxis2 = positiveOrientation ? -extrusionPosition.BasisZ : extrusionPosition.BasisZ; bool axisIsCyclic = (axisCurve == null) ? false : axisCurve.IsCyclic; double axisCurvePeriod = axisIsCyclic ? axisCurve.Period : 0.0; Transform curveLoopTransform = Transform.Identity; IList<CurveLoop> currLoops = null; double depthSoFar = 0.0; for (int ii = 0; ii < numLayers; ii++) { IFCMaterialLayer materialLayer = materialLayers[ii]; // Ignore 0 thickness layers. No need to warn. double depth = materialLayer.LayerThickness; if (MathUtil.IsAlmostZero(depth)) continue; // If the thickness is non-zero but invalid, fail. if (!Application.IsValidThickness(depth)) return null; double extrusionDistance = 0.0; if (isAxis3) { // Offset the curve loops if necessary, using the base extrusionDirection, regardless of the direction sense // of the MaterialLayerSetUsage. double offsetForLayer = positiveOrientation ? baseOffsetForLayer + depthSoFar : baseOffsetForLayer - depthSoFar; if (!MathUtil.IsAlmostZero(offsetForLayer)) { curveLoopTransform.Origin = offsetForLayer * extrusionDirection; currLoops = new List<CurveLoop>(); foreach (CurveLoop loop in loops) { CurveLoop newLoop = CurveLoop.CreateViaTransform(loop, curveLoopTransform); if (newLoop == null) return null; currLoops.Add(newLoop); } } else currLoops = loops; extrusionDistance = depth; } else { // startClipCurve, firstEndCapCurve, endClipCurve, secondEndCapCurve. Curve[] outline = new Curve[4]; double[][] endParameters = new double[4][]; double startClip = depthSoFar; double endClip = depthSoFar + depth; outline[0] = orientedCurveList[0].CreateOffset(startClip, normalDirectionForAxis2); outline[1] = orientedCurveList[1].Clone(); outline[2] = orientedCurveList[2].CreateOffset(totalThickness - endClip, normalDirectionForAxis2); outline[3] = orientedCurveList[3].Clone(); for (int jj = 0; jj < 4; jj++) { outline[jj].MakeUnbound(); endParameters[jj] = new double[2]; endParameters[jj][0] = 0.0; endParameters[jj][1] = 0.0; } // Trim/Extend the curves so that they make a closed loop. for (int jj = 0; jj < 4; jj++) { IntersectionResultArray resultArray = null; outline[jj].Intersect(outline[(jj + 1) % 4], out resultArray); if (resultArray == null || resultArray.Size == 0) return null; int numResults = resultArray.Size; if ((numResults > 1 && !axisIsCyclic) || (numResults > 2)) return null; UV intersectionPoint = resultArray.get_Item(0).UVPoint; endParameters[jj][1] = intersectionPoint.U; endParameters[(jj + 1) % 4][0] = intersectionPoint.V; if (numResults == 2) { // If the current result is closer to the end of the curve, keep it. UV newIntersectionPoint = resultArray.get_Item(1).UVPoint; int endParamIndex = (jj % 2); double newParamToCheck = newIntersectionPoint[endParamIndex]; double oldParamToCheck = (endParamIndex == 0) ? endParameters[jj][1] : endParameters[(jj + 1) % 4][0]; double currentEndPoint = (endParamIndex == 0) ? orientedCurveList[jj].GetEndParameter(1) : orientedCurveList[(jj + 1) % 4].GetEndParameter(0); // Put in range of [-Period/2, Period/2]. double newDist = (currentEndPoint - newParamToCheck) % axisCurvePeriod; if (newDist < -axisCurvePeriod / 2.0) newDist += axisCurvePeriod; if (newDist > axisCurvePeriod / 2.0) newDist -= axisCurvePeriod; double oldDist = (currentEndPoint - oldParamToCheck) % axisCurvePeriod; if (oldDist < -axisCurvePeriod / 2.0) oldDist += axisCurvePeriod; if (oldDist > axisCurvePeriod / 2.0) oldDist -= axisCurvePeriod; if (Math.Abs(newDist) < Math.Abs(oldDist)) { endParameters[jj][1] = newIntersectionPoint.U; endParameters[(jj + 1) % 4][0] = newIntersectionPoint.V; } } } CurveLoop newCurveLoop = new CurveLoop(); for (int jj = 0; jj < 4; jj++) { if (endParameters[jj][1] < endParameters[jj][0]) { if (!outline[jj].IsCyclic) return null; endParameters[jj][1] += Math.Floor(endParameters[jj][0] / axisCurvePeriod + 1.0) * axisCurvePeriod; } outline[jj].MakeBound(endParameters[jj][0], endParameters[jj][1]); newCurveLoop.Append(outline[jj]); } currLoops = new List<CurveLoop>(); currLoops.Add(newCurveLoop); extrusionDistance = currDepth; } // Determine the material id. IFCMaterial material = materialLayer.Material; ElementId layerMaterialId = (material == null) ? ElementId.InvalidElementId : material.GetMaterialElementId(); // The second option here is really for Referencing. Without a UI (yet) to determine whether to show the base // extusion or the layers for objects with material layer sets, we've chosen to display the base material if the layer material // has no color information. This means that the layer is assigned the "wrong" material, but looks better on screen. // We will reexamine this decision (1) for the Open case, (2) if there is UI to toggle between layers and base extrusion, or // (3) based on user feedback. if (layerMaterialId == ElementId.InvalidElementId || Importer.TheCache.MaterialsWithNoColor.Contains(layerMaterialId)) layerMaterialId = baseMaterialId; SolidOptions solidOptions = new SolidOptions(layerMaterialId, shapeEditScope.GraphicsStyleId); // Create the extrusion for the material layer. GeometryObject extrusionSolid = GeometryCreationUtilities.CreateExtrusionGeometry( currLoops, materialExtrusionDirection, extrusionDistance, solidOptions); if (extrusionSolid == null) return null; extrusionSolids.Add(extrusionSolid); depthSoFar += depth; } } catch { // Ignore the specific exception, but let the user know there was a problem processing the IfcMaterialLayerSetUsage. shouldWarn = true; return null; } return extrusionSolids; }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The shape edit scope.</param> /// <param name="lcs">Local coordinate system for the geometry.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>One or more created geometries.</returns> /// <remarks>The scaledLcs is only partially supported in this routine; it allows scaling the depth of the extrusion, /// which is commonly found in ACA files.</remarks> protected override IList <GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { if (Direction == null) { Importer.TheLog.LogError(Id, "Error processing IfcExtrudedAreaSolid, can't create geometry.", false); return(null); } Transform origLCS = (lcs == null) ? Transform.Identity : lcs; Transform origScaledLCS = (scaledLcs == null) ? Transform.Identity : scaledLcs; Transform extrusionPosition = (Position == null) ? origLCS : origLCS.Multiply(Position); Transform scaledExtrusionPosition = (Position == null) ? origScaledLCS : origScaledLCS.Multiply(Position); XYZ extrusionDirection = extrusionPosition.OfVector(Direction); ISet <IList <CurveLoop> > disjointLoops = GetTransformedCurveLoops(extrusionPosition); if (disjointLoops == null || disjointLoops.Count() == 0) { return(null); } IList <GeometryObject> extrusions = new List <GeometryObject>(); foreach (IList <CurveLoop> loops in disjointLoops) { SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); XYZ scaledDirection = scaledExtrusionPosition.OfVector(Direction); double currDepth = Depth * scaledDirection.GetLength(); GeometryObject extrusionObject = null; try { // We may try to create separate extrusions, one per layer here. bool shouldWarn = false; ElementId overrideMaterialId = ElementId.InvalidElementId; IList <GeometryObject> extrusionLayers = CreateGeometryFromMaterialLayerUsage(shapeEditScope, extrusionPosition, loops, extrusionDirection, currDepth, out overrideMaterialId, out shouldWarn); if (extrusionLayers == null || extrusionLayers.Count == 0) { if (shouldWarn) { Importer.TheLog.LogWarning(Id, "Couldn't process associated IfcMaterialLayerSetUsage, using body geometry instead.", false); } if (overrideMaterialId != ElementId.InvalidElementId) { solidOptions.MaterialId = overrideMaterialId; } extrusionObject = GeometryCreationUtilities.CreateExtrusionGeometry(loops, extrusionDirection, currDepth, solidOptions); } else { foreach (GeometryObject extrusionLayer in extrusionLayers) { extrusions.Add(extrusionLayer); } } } catch (Exception ex) { if (shapeEditScope.MustCreateSolid()) { throw ex; } Importer.TheLog.LogError(Id, "Extrusion has an invalid definition for a solid; reverting to mesh.", false); MeshFromGeometryOperationResult meshResult = TessellatedShapeBuilder.CreateMeshByExtrusion( loops, extrusionDirection, currDepth, GetMaterialElementId(shapeEditScope)); // will throw if mesh is not available extrusionObject = meshResult.GetMesh(); } if (extrusionObject != null) { extrusions.Add(extrusionObject); } } return(extrusions); }
private IList <GeometryObject> SplitSweptDiskIntoValidPieces(CurveLoop trimmedDirectrixInWCS, IList <CurveLoop> profileCurveLoops, SolidOptions solidOptions) { // If we have 0 or 1 curves, there is nothing we can do here. int numCurves = trimmedDirectrixInWCS.Count(); if (numCurves < 2) { return(null); } // We will attempt to represent the original description in as few pieces as possible. IList <Curve> directrixCurves = new List <Curve>(); foreach (Curve directrixCurve in trimmedDirectrixInWCS) { if (directrixCurve == null) { numCurves--; if (numCurves < 2) { return(null); } continue; } directrixCurves.Add(directrixCurve); } IList <GeometryObject> sweptDiskPieces = new List <GeometryObject>(); // We will march along the directrix one curve at a time, trying to build a bigger piece of the sweep. At the point that we throw an exception, // we will take the last biggest piece and start over. CurveLoop currentCurveLoop = new CurveLoop(); Solid bestSolidSoFar = null; double pathAttachmentParam = directrixCurves[0].GetEndParameter(0); for (int ii = 0; ii < numCurves; ii++) { currentCurveLoop.Append(directrixCurves[ii]); try { Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; } catch { if (bestSolidSoFar != null) { sweptDiskPieces.Add(bestSolidSoFar); bestSolidSoFar = null; } } // This should only happen as a result of the catch loop above. We want to protect against the case where one or more pieces of the sweep // are completely invalid. while (bestSolidSoFar == null && (ii < numCurves)) { try { currentCurveLoop = new CurveLoop(); currentCurveLoop.Append(directrixCurves[ii]); profileCurveLoops = CreateProfileCurveLoopsForDirectrix(directrixCurves[ii], out pathAttachmentParam); Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops, solidOptions); bestSolidSoFar = currentSolid; break; } catch { ii++; } } } return(sweptDiskPieces); }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>Zero or more created geometries.</returns> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform sweptDiskPosition = (lcs == null) ? Transform.Identity : lcs; CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) return null; CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) return null; CurveLoop trimmedDirectrixInWCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, sweptDiskPosition); // Create the disk. Curve firstCurve = null; foreach (Curve curve in trimmedDirectrixInWCS) { firstCurve = curve; break; } double startParam = 0.0; IList<CurveLoop> profileCurveLoops = CreateProfileCurveLoopsForDirectrix(firstCurve, out startParam); if (profileCurveLoops == null) return null; SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); IList<GeometryObject> myObjs = new List<GeometryObject>(); try { Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInWCS, 0, startParam, profileCurveLoops, solidOptions); if (sweptDiskSolid != null) myObjs.Add(sweptDiskSolid); } catch (Exception ex) { // If we can't create a solid, we will attempt to split the Solid into valid pieces (that will likely have some overlap). if (ex.Message.Contains("self-intersections")) { Importer.TheLog.LogWarning(Id, "The IfcSweptDiskSolid definition does not define a valid solid, likely due to self-intersections or other such problems; the profile probably extends too far toward the inner curvature of the sweep path. Creating the minimum number of solids possible to represent the geometry.", false); myObjs = SplitSweptDiskIntoValidPieces(trimmedDirectrixInWCS, profileCurveLoops, solidOptions); } else throw ex; } return myObjs; }
/// <summary> /// Return a solid corresponding to the volume represented by boundingBoxXYZ. /// </summary> /// <param name="lcs">The local coordinate system of the bounding box; if null, assume the Identity transform.</param> /// <param name="boundingBoxXYZ">The bounding box.</param> /// <param name="solidOptions">The options for creating the solid. Allow null to mean default.</param> /// <returns>A solid of the same size and orientation as boundingBoxXYZ, or null if boundingBoxXYZ is invalid or null.</returns> /// <remarks>We don't do any checking on the input transform, which could have non-uniform scaling and/or mirroring. /// This could potentially lead to unexpected results, which we can examine if and when such cases arise.</remarks> public static Solid CreateSolidFromBoundingBox(Transform lcs, BoundingBoxXYZ boundingBoxXYZ, SolidOptions solidOptions) { // Check that the bounding box is valid. if (boundingBoxXYZ == null || !boundingBoxXYZ.Enabled) return null; try { // Create a transform based on the incoming local coordinate system and the bounding box coordinate system. Transform bboxTransform = (lcs == null) ? boundingBoxXYZ.Transform : lcs.Multiply(boundingBoxXYZ.Transform); XYZ[] profilePts = new XYZ[4]; profilePts[0] = bboxTransform.OfPoint(boundingBoxXYZ.Min); profilePts[1] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Min.Z)); profilePts[2] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Max.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); profilePts[3] = bboxTransform.OfPoint(new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Max.Y, boundingBoxXYZ.Min.Z)); XYZ upperRightXYZ = bboxTransform.OfPoint(boundingBoxXYZ.Max); // If we assumed that the transforms had no scaling, // then we could simply take boundingBoxXYZ.Max.Z - boundingBoxXYZ.Min.Z. // This code removes that assumption. XYZ origExtrusionVector = new XYZ(boundingBoxXYZ.Min.X, boundingBoxXYZ.Min.Y, boundingBoxXYZ.Max.Z) - boundingBoxXYZ.Min; XYZ extrusionVector = bboxTransform.OfVector(origExtrusionVector); double extrusionDistance = extrusionVector.GetLength(); XYZ extrusionDirection = extrusionVector.Normalize(); CurveLoop baseLoop = new CurveLoop(); for (int ii = 0; ii < 4; ii++) { baseLoop.Append(Line.CreateBound(profilePts[ii], profilePts[(ii + 1) % 4])); } IList<CurveLoop> baseLoops = new List<CurveLoop>(); baseLoops.Add(baseLoop); if (solidOptions == null) return GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance); else return GeometryCreationUtilities.CreateExtrusionGeometry(baseLoops, extrusionDirection, extrusionDistance, solidOptions); } catch { return null; } }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { Transform lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity; // 2015+: create cone(s) for the direction of flow. CurveLoop rightTrangle = new CurveLoop(); const double radius = 0.5/12.0; const double height = 1.5/12.0; SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, GraphicsStyleId); Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ); // The origin is at the base of the cone for everything but source - then it is at the top of the cone. XYZ pt1 = FlowDirection == IFCFlowDirection.Source ? lcs.Origin - height * lcs.BasisZ : lcs.Origin; XYZ pt2 = pt1 + radius * lcs.BasisX; XYZ pt3 = pt1 + height * lcs.BasisZ; rightTrangle.Append(Line.CreateBound(pt1, pt2)); rightTrangle.Append(Line.CreateBound(pt2, pt3)); rightTrangle.Append(Line.CreateBound(pt3, pt1)); IList<CurveLoop> curveLoops = new List<CurveLoop>(); curveLoops.Add(rightTrangle); Solid portArrow = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, curveLoops, 0.0, Math.PI * 2.0, solidOptions); Solid oppositePortArrow = null; if (FlowDirection == IFCFlowDirection.SourceAndSink) { Frame oppositeCoordinateFrame = new Frame(lcs.Origin, -lcs.BasisX, lcs.BasisY, -lcs.BasisZ); CurveLoop oppositeRightTrangle = new CurveLoop(); XYZ oppPt2 = pt1 - radius * lcs.BasisX; XYZ oppPt3 = pt1 - height * lcs.BasisZ; oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2)); oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3)); oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1)); IList<CurveLoop> oppositeCurveLoops = new List<CurveLoop>(); oppositeCurveLoops.Add(oppositeRightTrangle); oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions); } if (portArrow != null) { IList<GeometryObject> geomObjs = new List<GeometryObject>(); geomObjs.Add(portArrow); if (oppositePortArrow != null) geomObjs.Add(oppositePortArrow); DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs); if (directShape != null) { CreatedGeometry = geomObjs; CreatedElementId = directShape.Id; } else Importer.TheLog.LogCreationError(this, null, false); } }
/// <summary> /// Return geometry for a particular representation item. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <param name="guid">The guid of an element for which represntation is being created.</param> /// <returns>Zero or more created geometries.</returns> protected override IList<GeometryObject> CreateGeometryInternal( IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { Transform sweptDiskPosition = (lcs == null) ? Transform.Identity : lcs; CurveLoop baseProfileCurve = Directrix.GetCurveLoop(); if (baseProfileCurve == null) return null; CurveLoop trimmedDirectrix = IFCGeometryUtil.TrimCurveLoop(baseProfileCurve, StartParameter, EndParameter); if (trimmedDirectrix == null) return null; CurveLoop trimmedDirectrixInLCS = IFCGeometryUtil.CreateTransformed(trimmedDirectrix, sweptDiskPosition); // Create the disk. Transform originTrf = null; double startParam = 0.0; // If the directrix isn't bound, this arbitrary parameter will do. foreach (Curve curve in trimmedDirectrixInLCS) { if (curve.IsBound) startParam = curve.GetEndParameter(0); originTrf = curve.ComputeDerivatives(startParam, false); break; } if (originTrf == null) return null; // The X-dir of the transform of the start of the directrix will form the normal of the disk. Plane diskPlane = new Plane(originTrf.BasisX, originTrf.Origin); IList<CurveLoop> profileCurveLoops = new List<CurveLoop>(); CurveLoop diskOuterCurveLoop = new CurveLoop(); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, 0, Math.PI)); diskOuterCurveLoop.Append(Arc.Create(diskPlane, Radius, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskOuterCurveLoop); if (InnerRadius.HasValue) { CurveLoop diskInnerCurveLoop = new CurveLoop(); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, 0, Math.PI)); diskInnerCurveLoop.Append(Arc.Create(diskPlane, InnerRadius.Value, Math.PI, 2.0 * Math.PI)); profileCurveLoops.Add(diskInnerCurveLoop); } SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId); Solid sweptDiskSolid = GeometryCreationUtilities.CreateSweptGeometry(trimmedDirectrixInLCS, 0, startParam, profileCurveLoops, solidOptions); IList<GeometryObject> myObjs = new List<GeometryObject>(); if (sweptDiskSolid != null) myObjs.Add(sweptDiskSolid); return myObjs; }