CADability dotNET

Here you find code examples for using CADability.

Import, Analyse and Modify an existing drawing: Find all drill holes of a solid.

This example shows how to analyse a drawing or a model and recognize certain features.

Step 1: Create a new Windows Forms Application. Add a reference to CADability and with "Tools", "Choose Toolbox Items" select CADability.dll. This will create a "CADControl" item in the Toolbox.

Step 2: Drag the CADControl onto the form. In the property window set "ShowMenu" and "ShowToolbar" to "true".

Step 3: Next to the control create a button and name it "findDrillHoles" and double click the button to create an click event handler.

Step 4: Write some code for the click handler.

In the example below we expect that some drawing or model has already been loaded. . (In the file menu you can open a “step” or “iges” file, but you can also use ReadFromFile). The code first gets access to the Project and Model. Then all objects in the model are iterated. If there is a Solid, Shell or Face, it is further examinated. All cylindrical faces are collected in a list. Now the list gets further examined to combine faces that describe parts of the same hole. Finally solid cylinders are created with the same diameter and at the same location as the holes. The length of the newly created cylinders fill the holes totally. These cylinders are finally colored red and added to the model. You can select the original solid afterwards and delete it. Then you will see the holes as solid cylinders.

Source Code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CADability;
using CADability.GeoObject;
using CADability.Attribute;

namespace WindowsFormsApplication2
    public partial class Form1 : Form
        public Form1()

        /// <summary>
        /// Method which is executed when the button "Find Drill Holes" is beeing pressed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void findDrillHoles_Click(object sender, EventArgs e)
            // it is assumed the project is already loaded, but you can load the Project with a line similar to
            // cadControl.Frame.Project = Project.ReadFromFile("...some file name ...", "stp");
            Project project = cadControl.Frame.Project; // the curren Project displayed in the cadControl
            Model model = project.GetActiveModel(); // the active model in that project
            List<Face> allCylindricalFaces = new List<Face>(); // collect all cylindrical faces in the model
            foreach (IGeoObject go in model)
            {   // iterate over all geometricl objects
                // only check Solids, Shells and Faces, maybe you would like to only check Solids
                if (go is Solid) allCylindricalFaces.AddRange(checkSolid(go as Solid));
                else if (go is Shell) allCylindricalFaces.AddRange(checkShell(go as Shell));
                else if (go is Face)
                    Face face = go as Face;
                    if (face.Surface is CylindricalSurface) allCylindricalFaces.Add(face);
            // given all the faces find corresponding cylinders to "stuff" the holes
            Solid[] drillHoles = createDrillHoles(allCylindricalFaces);
            // make all cylinders red.
            ColorDef red = project.ColorList.CreateOrFind("red", Color.Red);
            for (int i = 0; i < drillHoles.Length; i++)
                drillHoles[i].ColorDef = red;
            // add the cylinders to the model

        /// <summary>
        /// Given a list of cylindrical faces, create cylinders that overlap the faces.
        /// There might be more than one face to a cylinder, which is checked here.
        /// </summary>
        /// <param name="allCylindricalFaces"></param>
        /// <returns></returns>
        private Solid[] createDrillHoles(IEnumerable<Face> allCylindricalFaces)
            List<Solid> res = new List<Solid>(); // create empty list for the result
            HashSet<Face> setOfFaces = new HashSet<Face>(allCylindricalFaces); // put faces into a set for better access
            Face face = setOfFaces.FirstOrDefault<Face>(); // start with an arbitrary face
            while (face != null)
                setOfFaces.Remove(face); // remove this face from the set
                BoundingRect extuv = face.GetUVBounds(); // get the bounds in the u/v system
                CylindricalSurface cyl1 = face.Surface as CylindricalSurface; // access the underlying cylindrical geometry
                // check whether this face is connected (at its edges) with another cylindrical face
                // with the same geometry (axis, radius). This is often the case, when the hole is modeled with
                // two half-shells
                foreach (Edge edge in face.AllEdges)
                    Face other = edge.GetBuddy(face); // the connected face
                    if (other != null)
                    {   // when it exists
                        if (other.Surface is CylindricalSurface)
                        {   // and when it also is a cylindrical face
                            CylindricalSurface cyl2 = other.Surface as CylindricalSurface; // get acces to the cylindrical geometry
                            ModOp2D secondToFirst; // matrix to convert from the second u/v system to the first
                            if (cyl2.SameGeometry(other.GetUVBounds(),cyl1,face.GetUVBounds(),Precision.eps,out secondToFirst))
                            {   // both faces describe the same cylinder, maybe with different u/v systems
                                BoundingRect ext2 = other.GetUVBounds(); // the bounds in the second u/v system
                                ext2.Modify(secondToFirst); // now in the first u/v/ system
                                extuv.MinMax(ext2); // add to the accumulated extend
                                setOfFaces.Remove(other); // remove this other face from the set
                GeoPoint startPoint = cyl1.Location+extuv.Bottom*cyl1.Axis; // startpoint of the cylinder axis
                GeoPoint endPoint = cyl1.Location+extuv.Top*cyl1.Axis; // endpoint of the cylinder axis
                res.Add(Make3D.MakeCylinder(startPoint, cyl1.XAxis, endPoint - startPoint)); // create a solid cylinder 
                // and add it to the list

                face = setOfFaces.FirstOrDefault<Face>(); // for the next loop
            return res.ToArray(); // return all cylinders

        /// <summary>
        /// Find all the cylindrical faces in the provided Solid
        /// </summary>
        /// <param name="solid"></param>
        /// <returns></returns>
        private IEnumerable<Face> checkSolid(Solid solid)
            List<Face> res = new List<Face>();
            for (int i = 0; i < solid.Shells.Length; i++)
            {   // iterate on all shells (there only a single shell in most cases)
            return res;
        private IEnumerable<Face> checkShell(Shell shell)
            List<Face> res = new List<Face>();
            for (int i = 0; i < shell.Faces.Length; i++)
            {   // iterate all the faces of the shell
                // and add it to the result if it has a cylindrical geometry
                if (shell.Faces[i].Surface is CylindricalSurface) res.Add(shell.Faces[i]);
            return res;