/// <summary> /// Creates (or gets the) child gameobject /// </summary> void CreateOrGetChildObject() { // Ensure that the camera component is set if this gets called before reset _camera = GetComponent <Camera>(); // If there is a child gameobject named CameraFixedGradientSky... if (transform.Find("CameraFixedGradientSky") != null) { // Set it as the childObject childObject = transform.Find("CameraFixedGradientSky").gameObject; } else { // Otherwise - create a new gameobject childObject = new GameObject(); // Set the name of the object - this is used when the object is destroyed so the name is important childObject.name = "CameraFixedGradientSky"; // Set the parent of the transform to the camera transform childObject.transform.parent = transform; // Reset the local rotation so it's "zero" childObject.transform.localRotation = Quaternion.identity; // Hide the child gameobject in the inspector - we don't need to see it there childObject.hideFlags = HideFlags.HideInHierarchy; // Place the gameobject just behind the near clipping plane or in front of the far clipping plane if (placeAtClippingPlane == ClippingPlane.NEAR) { childObject.transform.localPosition = new Vector3(0, 0, _camera.nearClipPlane + 0.01f); } else { childObject.transform.localPosition = new Vector3(0, 0, _camera.farClipPlane - 0.01f); } // Add MeshFilter and MeshRenderer components to the child gameobject childObject.AddComponent <MeshFilter>(); childObject.AddComponent <MeshRenderer>(); // Create a MeshRenderer for the childObject CreateMeshRenderer(childObject.transform); // Set the Material to the shader with ZWrite off and RenderQueue set to Gemetry-1000 to ensure it's always rendered as a background Material _material = new Material(Shader.Find("Custom/VertexColorCamera")); childObject.GetComponent <MeshRenderer>().sharedMaterial = _material; } // Set the cached clipping plane to the clipping plane used so we can compare if it's changed _cacheClippingPlane = placeAtClippingPlane; // Create the gradient mesh and sett it to the sharedMesh for the MeshFilter childObject.GetComponent <MeshFilter>().sharedMesh = CreateMesh(); // Set the mesh local scale to ensure it fills the camera based on its position and camera field of view and size SetMeshLocalScale(); }
private static Vertex CreateTexturedVertex(ClippingPlane plane, Vector point, int width, int height) { double yzr = Vector.DotProduct(new Vector(1, 0, 0), plane.Normal); double xzr = Vector.DotProduct(new Vector(0, 1, 0), plane.Normal); double xyr = Vector.DotProduct(new Vector(0, 0, 1), plane.Normal); double yz = Math.Abs(yzr); double xz = Math.Abs(xzr); double xy = Math.Abs(xyr); double rad = Math.PI / 180 * -plane.Texture.Rotation; double crot = Math.Cos(rad); double srot = Math.Sin(rad); double xOffset = plane.Texture.OffsetX; double yOffset = plane.Texture.OffsetY; double x; double y; if (yz >= xz && yz >= xy) { x = -point.Y; y = point.Z; } else if (xz >= xy) { x = -point.X; y = point.Z; } else { x = point.X; y = point.Y; xOffset = -xOffset; } x /= -plane.Texture.ScaleX; y /= -plane.Texture.ScaleY; x = Math.Round(x); y = Math.Round(y); double a = x; double b = y; x = (crot * a) + (srot * b); y = -(srot * a) + (crot * b); x -= xOffset; y -= yOffset; double u = x / width; double v = y / height; return(new Vertex(point.X, point.Y, point.Z, u, v)); }
private static clipping_plane GetViewpointClippingPlane(ClippingPlane GivenClippingPlane) { var ReturnObject = new clipping_plane(); ReturnObject.direction = new PointOrVector(); ReturnObject.direction.x = GivenClippingPlane.Direction.X; ReturnObject.direction.y = GivenClippingPlane.Direction.Y; ReturnObject.direction.z = GivenClippingPlane.Direction.Z; ReturnObject.location = new PointOrVector(); ReturnObject.location.x = GivenClippingPlane.Location.X; ReturnObject.location.y = GivenClippingPlane.Location.Y; ReturnObject.location.z = GivenClippingPlane.Location.Z; return(ReturnObject); }
private static Face ApplyTextures(Face face, ClippingPlane plane) { (int width, int height) = TextureFinder.FindSize(face.Texture); if (width == 0 || height == 0) { return(face); } Vector[] vectors = face.Vertices.ToArray(); Vertex v1 = CreateTexturedVertex(plane, vectors[0], width, height); Vertex v2 = CreateTexturedVertex(plane, vectors[1], width, height); Vertex v3 = CreateTexturedVertex(plane, vectors[2], width, height); return(new Face(v1, v2, v3, face.Texture)); }
/// <summary> /// Create a list of all intersection points of each set of three clipping planes. /// </summary> /// <param name="planes">The planes.</param> /// <returns>Gets all intersections of the given planes.</returns> private static IEnumerable <Vector> FindIntersections(IEnumerable <ClippingPlane> planes) { List <Vector> intersections = new List <Vector>(); // Check every unique combination of three clipping planes and see if we can find an intersection point. int i = 0; foreach (ClippingPlane planeI in planes) { int j = ++i; foreach (ClippingPlane planeJ in planes.Skip(j)) { foreach (ClippingPlane planeK in planes.Skip(++j)) { if (ClippingPlane.FindIntersection(planeI, planeJ, planeK, out Vector? intersection)) { // Checks if there does not exist a clipping plane with which we are in front. // Would result in vertices being added outside of our object. bool rightSide = true; foreach (ClippingPlane planeL in planes) { if (planeL != planeI && planeL != planeJ && planeL != planeK) { double dot = Vector.DotProduct(intersection !, planeL.Normal) - planeL.D; if (dot > 0) { rightSide = false; break; } } } if (rightSide && !intersections.Contains(intersection !)) { intersections.Add(intersection !); } } } } } return(intersections); }
/// <summary> /// Initialization function for the VolumeController. Ensures that the global variables needed by other objects are initialized first. /// </summary> private void Awake() { // 0. Create the data volume and its rendering material. This initialized the volume. currentVolume = new Volume(dataPath + volumeName + "/", "metadata.json"); controller.VolName = volumeName; // 1. Set up the transfer function int isovalueRange = currentVolume.calculateIsovalueRange(); transferFunction = new TransferFunction(isovalueRange); // 2. Set up the clipping plane clippingPlane = new ClippingPlane(new Vector3(0, 0, 0), new Vector3(1, 0, 0), false); updateClippingPlaneAll(); // 3. Set up the target for the camera controls CameraControls cameraControls = (CameraControls)mainCamera.GetComponent(typeof(CameraControls)); cameraControls.target = currentVolume.VolumeCube; //4. Initialize data packing. // Moved to update(). // 5. Unbound the framerate of this application Application.targetFrameRate = -1; // 6. Turn off v-sync QualitySettings.vSyncCount = 0; // DEBUG: Creating a wireframe bounding box cube if (drawBoundingBox) { boundingBoxLine = createBoundingBoxLineRenderer(); Debug.Log("Trying to draw bounding box" + boundingBoxLine); } }
/// <summary> /// Initialization function for the VolumeController. Ensures that the global variables needed by other objects are initialized first. /// </summary> private void Awake() { // 0. Create the data volume and its rendering material currentVolume = new Volume(dataPath, "metadata.json"); // 1. Set up the transfer function int isovalueRange = currentVolume.calculateIsovalueRange(); transferFunction = new TransferFunction(isovalueRange); // 2. Set up the clipping plane clippingPlane = new ClippingPlane(new Vector3(0, 0, 0), new Vector3(1, 0, 0), false); updateClippingPlaneAll(); // 3. Set up the target for the camera controls CameraControls cameraControls = (CameraControls)mainCamera.GetComponent(typeof(CameraControls)); cameraControls.target = currentVolume.VolumeCube; // DEBUG: Creating a wireframe bounding box cube if (drawBoundingBox) { boundingBoxLine = createBoundingBoxLineRenderer(); } // DEBUG: Create a box for the plane //clippingPlaneCube = GameObject.CreatePrimitive(PrimitiveType.Cube); //clippingPlaneCube.transform.position = clippingPlane.Position; //clippingPlaneCube.GetComponent<Renderer>().material = new Material(Shader.Find("Standard")); //clippingPlaneCube.transform.position = clippingPlane.Position; //clippingPlaneCube.transform.localScale = new Vector3(2.1f, 2.1f, 0.01f); //clippingPlaneCube.transform.rotation = Quaternion.LookRotation(clippingPlane.Normal); // Load the compute shader kernel analysisKernelID = brickAnalysisShader.FindKernel("BrickAnalysis"); }
public static ClippingPlane[] GetClippingPlanesFromBoundingBox(XYZ max, XYZ min, Transform toMdoelSpaceTransform, Document doc) { List <ClippingPlane> clippingPlanes = new List <ClippingPlane>(); // transform six normals to model coordinates and shared coordinates #if REVIT2019 ProjectPosition projectPosition = doc.ActiveProjectLocation.GetProjectPosition(XYZ.Zero); #else ProjectPosition projectPosition = doc.ActiveProjectLocation.get_ProjectPosition(XYZ.Zero); #endif Transform t1 = Transform.CreateTranslation(new XYZ(projectPosition.EastWest, projectPosition.NorthSouth, projectPosition.Elevation)); Transform t2 = Transform.CreateRotation(XYZ.BasisZ, projectPosition.Angle); XYZ xPositiveNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(1, 0, 0)))); XYZ yPositiveNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(0, 1, 0)))); XYZ zPositiveNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(0, 0, 1)))); XYZ xNegativeNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(-1, 0, 0)))); XYZ yNegativeNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(0, -1, 0)))); XYZ zNegativeNormalTransformed = t1.OfVector(t2.OfVector(toMdoelSpaceTransform.OfVector(new XYZ(0, 0, -1)))); // generate BCF clipping planes ClippingPlane xPositive = new ClippingPlane() { Direction = new Direction() { X = xPositiveNormalTransformed.X, Y = xPositiveNormalTransformed.Y, Z = xPositiveNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = max.X, Y = max.Y, Z = max.Z } }; ClippingPlane yPositive = new ClippingPlane() { Direction = new Direction() { X = yPositiveNormalTransformed.X, Y = yPositiveNormalTransformed.Y, Z = yPositiveNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = max.X, Y = max.Y, Z = max.Z } }; ClippingPlane zPositive = new ClippingPlane() { Direction = new Direction() { X = zPositiveNormalTransformed.X, Y = zPositiveNormalTransformed.Y, Z = zPositiveNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = max.X, Y = max.Y, Z = max.Z } }; ClippingPlane xNegative = new ClippingPlane() { Direction = new Direction() { X = xNegativeNormalTransformed.X, Y = xNegativeNormalTransformed.Y, Z = xNegativeNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = min.X, Y = min.Y, Z = min.Z } }; ClippingPlane yNegative = new ClippingPlane() { Direction = new Direction() { X = yNegativeNormalTransformed.X, Y = yNegativeNormalTransformed.Y, Z = yNegativeNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = min.X, Y = min.Y, Z = min.Z } }; ClippingPlane zNegative = new ClippingPlane() { Direction = new Direction() { X = zNegativeNormalTransformed.X, Y = zNegativeNormalTransformed.Y, Z = zNegativeNormalTransformed.Z }, Location = new ARUP.IssueTracker.Classes.BCF2.Point() { X = min.X, Y = min.Y, Z = min.Z } }; clippingPlanes.Add(xPositive); clippingPlanes.Add(yPositive); clippingPlanes.Add(zPositive); clippingPlanes.Add(xNegative); clippingPlanes.Add(yNegative); clippingPlanes.Add(zNegative); return(clippingPlanes.ToArray()); }
/// <summary> /// Calculate the max point and the min point of Revit section box based on BCF clipping planes /// </summary> /// <param name="clippingPlanes">clipping planes from BCF viewpoint</param> /// <returns>1: max, 2: min</returns> private Tuple <BoundingBoxXYZ, Transform> getBoundingBoxFromClippingPlanes(Document doc, ClippingPlane[] clippingPlanes) { const double tolerance = 0.0000001; if (clippingPlanes.Count() != 6) { return(null); } try { List <ClippingPlane> cPlanes = clippingPlanes.ToList(); double maxZ, minZ; // checking z direction normals List <XYZ> zPoints = new List <XYZ>(); List <ClippingPlane> xyClipppingPlanes = new List <ClippingPlane>(); foreach (ClippingPlane cp in cPlanes) { XYZ zDirection = new XYZ(0, 0, 1); XYZ normal = new XYZ(cp.Direction.X, cp.Direction.Y, cp.Direction.Z); if (normal.IsAlmostEqualTo(zDirection, tolerance) || normal.IsAlmostEqualTo(-zDirection, tolerance)) { zPoints.Add(new XYZ(cp.Location.X, cp.Location.Y, cp.Location.Z)); } else { xyClipppingPlanes.Add(cp); } } if (zPoints.Count != 2) { return(null); } else { maxZ = zPoints[0].Z > zPoints[1].Z ? zPoints[0].Z : zPoints[1].Z; minZ = zPoints[0].Z < zPoints[1].Z ? zPoints[0].Z : zPoints[1].Z; maxZ = UnitUtils.ConvertToInternalUnits(maxZ, DisplayUnitType.DUT_METERS); minZ = UnitUtils.ConvertToInternalUnits(minZ, DisplayUnitType.DUT_METERS); } // check if the remaining 4 points are on XY plane //if (!xyClipppingPlanes.TrueForAll(cp => (cp.Location.Z < tolerance && cp.Location.Z > -tolerance))) //{ // return null; //} // find out lines orthorgonal to self-normal List <Autodesk.Revit.DB.Line> linesToBeIntersected = new List <Autodesk.Revit.DB.Line>(); foreach (ClippingPlane cp in xyClipppingPlanes) { XYZ planeNormal = new XYZ(cp.Direction.X, cp.Direction.Y, cp.Direction.Z); ClippingPlane othorgonalPlane = xyClipppingPlanes.Find(c => !( new XYZ(c.Direction.X, c.Direction.Y, c.Direction.Z).IsAlmostEqualTo(planeNormal, tolerance) || new XYZ(c.Direction.X, c.Direction.Y, c.Direction.Z).IsAlmostEqualTo(-planeNormal, tolerance) )); XYZ othorgonalNormal = new XYZ(othorgonalPlane.Direction.X, othorgonalPlane.Direction.Y, othorgonalPlane.Direction.Z); XYZ planeOrigin = new XYZ(cp.Location.X, cp.Location.Y, 0); linesToBeIntersected.Add(Autodesk.Revit.DB.Line.CreateUnbound(planeOrigin, othorgonalNormal)); } // get intersection results List <XYZ> intersectedPoints = new List <XYZ>(); foreach (Autodesk.Revit.DB.Line line1 in linesToBeIntersected) { foreach (Autodesk.Revit.DB.Line line2 in linesToBeIntersected) { if (line1 != line2) { // calculate intersection points double a1 = line1.Direction.Y; double b1 = line1.Direction.X; double a2 = line2.Direction.Y; double b2 = line2.Direction.X; // if not parallel double delta = b1 * a2 - a1 * b2; if (delta > tolerance || delta < -tolerance) { double c1 = a1 * line1.Origin.X - b1 * line1.Origin.Y; double c2 = a2 * line2.Origin.X - b2 * line2.Origin.Y; double deltaX = b1 * c2 - b2 * c1; double deltaY = a1 * c2 - a2 * c1; double intersectionX = deltaX / delta; double intersectionY = deltaY / delta; intersectedPoints.Add(new XYZ(intersectionX, intersectionY, 0)); } } } } // find rightmost, leftmost, topmost, and bottommost points XYZ rightmost = intersectedPoints[0]; XYZ leftmost = intersectedPoints[0]; XYZ topmost = intersectedPoints[0]; XYZ bottommost = intersectedPoints[0]; // for non-rotated section box only if (intersectedPoints.Count < 4) { return(null); } else { foreach (XYZ p in intersectedPoints) { if (p.X > rightmost.X) { rightmost = p; } if (p.X < leftmost.X) { leftmost = p; } if (p.Y > topmost.Y) { topmost = p; } if (p.Y < bottommost.Y) { bottommost = p; } } } // change the coordinate system from Project to Shared rightmost = ConvertToInteranlAndSharedCoordinate(doc, rightmost); leftmost = ConvertToInteranlAndSharedCoordinate(doc, leftmost); topmost = ConvertToInteranlAndSharedCoordinate(doc, topmost); bottommost = ConvertToInteranlAndSharedCoordinate(doc, bottommost); // create diagonal and rotation vector XYZ horizontalBase = new XYZ(-1, 0, 0); Autodesk.Revit.DB.Line diagonal = Autodesk.Revit.DB.Line.CreateBound(rightmost, leftmost); Autodesk.Revit.DB.Line rotationBase = !rightmost.IsAlmostEqualTo(topmost, tolerance) ? Autodesk.Revit.DB.Line.CreateBound(rightmost, topmost) : Autodesk.Revit.DB.Line.CreateUnbound(new XYZ(0, 0, 0), horizontalBase); // return these two guys BoundingBoxXYZ bBox = new BoundingBoxXYZ(); Transform originalTransform = null; // compute a correct section box depending on two conditions if (rightmost.IsAlmostEqualTo(topmost, tolerance) || leftmost.IsAlmostEqualTo(bottommost, tolerance) || horizontalBase.IsAlmostEqualTo(rotationBase.Direction, tolerance) || horizontalBase.IsAlmostEqualTo(-rotationBase.Direction, tolerance)) { //non-rotated section box XYZ max = new XYZ( rightmost.X, topmost.Y, maxZ ); XYZ min = new XYZ( leftmost.X, bottommost.Y, minZ ); bBox.Max = max; bBox.Min = min; } else //rotated section box { // calculate rotation angle double angle = horizontalBase.AngleTo(rotationBase.Direction); // create transform Transform transform = Transform.CreateRotationAtPoint(new XYZ(0, 0, 1), angle, rightmost); // rotate it then get the rotated bounding box projection point (i.e., min. of rorated section box) XYZ rotatedMin = diagonal.CreateTransformed(transform).GetEndPoint(1); // create rotated section box with max and min XYZ max = new XYZ( rightmost.X, rightmost.Y, maxZ ); XYZ min = new XYZ( rotatedMin.X, rotatedMin.Y, minZ ); bBox.Max = max; bBox.Min = min; // rotate back to the original position originalTransform = Transform.CreateRotationAtPoint(new XYZ(0, 0, 1), -angle, max); } return(new Tuple <BoundingBoxXYZ, Transform>(bBox, originalTransform)); } catch (Exception ex) { MessageBox.Show(ex.ToString()); return(null); } }
private void Awake() { instance = this; matList = new List <Material>(); }
/// <summary> /// Generate Viewpoint /// </summary> private VisualizationInfo generateViewpoint() { try { // save selected elements to BCF compoments first List <Component> bcfComponents = new List <Component>(); var selectedElements = MSApp.ActiveModelReference.GetSelectedElements().BuildArrayFromContents(); if (selectedElements.Length > 0) { string originatingSystem = getBentleyProductName(); bcfComponents = new List <Component>(); foreach (Element e in selectedElements) { string ifcGuid = string.Empty; PropertyHandler handler = MSApp.CreatePropertyHandler(e); if (handler.SelectByAccessString("GUID")) { Guid guid = parseGuid(handler.GetDisplayString()); ifcGuid = IfcGuid.ToIfcGuid(guid).ToString(); } bcfComponents.Add(new Component(originatingSystem, e.ID.ToString(), ifcGuid)); } } // get current view int activeViewNum = getActiveViewNumber(); View currentView = MSApp.ActiveDesignFile.Views[activeViewNum]; double unitFactor = 1 / GetGunits(); // enable perspective camera back and forth to get correct view attributes, see the post below // https://communities.bentley.com/products/programming/microstation_programming/f/343173/t/80064 MSApp.CadInputQueue.SendKeyin("MDL KEYIN BENTLEY.VIEWATTRIBUTESDIALOG,VAD VIEWATTRIBUTESDIALOG SETATTRIBUTE 0 Camera True"); MSApp.CadInputQueue.SendKeyin("MDL KEYIN BENTLEY.VIEWATTRIBUTESDIALOG,VAD VIEWATTRIBUTESDIALOG SETATTRIBUTE 0 Camera False"); // camera direction Point3d direction = MSApp.Point3dNormalize(MSApp.Point3dSubtract(currentView.get_CameraTarget(), currentView.get_CameraPosition())); // force view center to be identical as camera target if camera direction is not along Z axis (i.e., not top view or bottom view) if (direction.X > distancePrecision || direction.Y > distancePrecision) // arbitrary precision { Point3d center = new Point3d(); center = currentView.get_Center(); Point3d extents = new Point3d(); extents = currentView.get_Extents(); Point3d translation = new Point3d(); translation = MSApp.Point3dSubtract(center, currentView.get_CameraTarget()); ViewCameraParameters vcp = new ViewCameraParametersClass(); vcp.set_CameraPosition(MSApp.Point3dAdd(currentView.get_CameraPosition(), translation)); vcp.set_CameraTarget(MSApp.Point3dAdd(currentView.get_CameraTarget(), translation)); currentView.SetCameraProperties(vcp); currentView.set_Extents(extents); currentView.set_Center(center); currentView.Redraw(); } // camera scale double h = currentView.get_Extents().Y *unitFactor; double w = currentView.get_Extents().X *unitFactor; double fov = 180 * currentView.CameraAngle / Math.PI; // camera location Point3d cameraLocation = MSApp.Point3dScale(currentView.get_CameraPosition(), unitFactor); // grab current view center point and force to top view if camera direction is along Z axis (i.e., top view or bottom view) if (direction.X < distancePrecision && direction.Y < distancePrecision) // arbitrary precision { cameraLocation = MSApp.Point3dScale(currentView.get_Center(), unitFactor); direction.Z = -1.0; } // camera up vector Point3d upVector = currentView.get_CameraUpVector(); // set up BCF viewpoint VisualizationInfo v = new VisualizationInfo(); v.Components = bcfComponents; // FIXME: ignore perspective view for now /*if (currentView.isPerspective) * { * v.PerspectiveCamera = new PerspectiveCamera(); * v.PerspectiveCamera.CameraViewPoint.X = cameraLocation.X; * v.PerspectiveCamera.CameraViewPoint.Y = cameraLocation.Y; * v.PerspectiveCamera.CameraViewPoint.Z = cameraLocation.Z; * v.PerspectiveCamera.CameraUpVector.X = upVector.X; * v.PerspectiveCamera.CameraUpVector.Y = upVector.Y; * v.PerspectiveCamera.CameraUpVector.Z = upVector.Z; * v.PerspectiveCamera.CameraDirection.X = direction.X; * v.PerspectiveCamera.CameraDirection.Y = direction.Y; * v.PerspectiveCamera.CameraDirection.Z = direction.Z; * v.PerspectiveCamera.FieldOfView = fov; * } * else * {*/ v.OrthogonalCamera = new OrthogonalCamera(); v.OrthogonalCamera.CameraViewPoint.X = cameraLocation.X; v.OrthogonalCamera.CameraViewPoint.Y = cameraLocation.Y; v.OrthogonalCamera.CameraViewPoint.Z = cameraLocation.Z; v.OrthogonalCamera.CameraUpVector.X = upVector.X; v.OrthogonalCamera.CameraUpVector.Y = upVector.Y; v.OrthogonalCamera.CameraUpVector.Z = upVector.Z; v.OrthogonalCamera.CameraDirection.X = direction.X; v.OrthogonalCamera.CameraDirection.Y = direction.Y; v.OrthogonalCamera.CameraDirection.Z = direction.Z; v.OrthogonalCamera.ViewToWorldScale = h; //} // get current clip volume and compute clipping planes ulong previousClipVolumeId = 0; try { int status = mdlView_getClipBoundaryElement(ref previousClipVolumeId, activeViewNum - 1).ToInt32(); if (status == 0) { Element previousClipVolume = MSApp.ActiveModelReference.GetElementByID((long)previousClipVolumeId); var smartSolids = MSApp.SmartSolid.ConvertToSmartSolidElement(previousClipVolume).BuildArrayFromContents(); if (smartSolids.Length > 0) { // just consider one solid for now SmartSolidElement clipVolumeSolid = smartSolids[0].AsSmartSolidElement; var surfaces = clipVolumeSolid.ExtractAllSurfaceFromSolid().BuildArrayFromContents(); List <ClippingPlane> clippingPlanes = new List <ClippingPlane>(); foreach (Element surface in surfaces) { ComplexShapeElement surfaceShape = surface.AsComplexShapeElement(); var vertices = surfaceShape.ConstructVertexList(0.1); // arbitrary tolerance for now if (vertices.Length > 0) { // produce BCF clipping planes Point3d location = MSApp.Point3dScale(MSApp.Point3dAdd(clipVolumeSolid.Origin, vertices[0]), unitFactor); ClippingPlane clippingPlane = new ClippingPlane() { Direction = new Direction() { X = surfaceShape.Normal.X, Y = surfaceShape.Normal.Y, Z = surfaceShape.Normal.Z }, Location = new Classes.BCF2.Point() { X = location.X, Y = location.Y, Z = location.Z } }; clippingPlanes.Add(clippingPlane); } } // add to BCF clipping planes v.ClippingPlanes = clippingPlanes.ToArray(); } } } catch (Exception ex) { // do nothing just for catching the exception when clip volume not found, element not found, or not being converted to smart solid } return(v); } catch (System.Exception ex1) { MessageBox.Show("exception: " + ex1, "Error!"); } return(null); }