top of page
  • ZackW

FreeCAD Devlog 3 - Points as a Basis for Holes

Updated: Dec 29, 2022

There is a "Hole" tool in the Part Design that can create a hole in a solid based on a sketch. It's is a neat tool, that can create things like counterbores, countersinks, threads, and whatnot.


Right now, you have to have an actual circle to base the hole off of. This is a bit silly, since you have to specify the hole diameter in the options anyway. Therefore, the circle diameter you specify in the sketch is ignored and totally useless. These days you can create points in the sketcher workbench, and use them in other workbenches. They are technically construction points by default, but that's a problem for another time.


This bit of code seems to be responsible for finding the holes in something:

Something important about this, it seems, are the TopoDS_Shape parameters. That seems key to understanding how this code works, so let's dive into it! The base class is actually in the 'opencascade' code, specifically the 'TopoDS_Shape.hxx' file. This is the comment describing the class:

Well, that's quite the mouthful. I don't think I'm going to understand this very well any time soon, but there are some interesting facts. This 'TopoDS_Shape' seems to have an orientation, for instance. It has a flag for whether or not it's closed, whether or not it's convex, it has a location and a Move method. We can also notice here, that classes that start with 'Top' seem to be in the opencascade kernel as well and are loosely related to DS_Shape.


There is actually doxygen documentation created for the opencascade kernel. This code is often referred to as OCCT, for Open CasCade Technology. One of the important bits in our 'findHoles' method is where it uses stuff called "compounds". This actually turns out to be a direct inheritor from TopoDS_Shape.

This is a useful chart! Just from this, I would guess that the draft workbench somehow relates to these wires, edges, and faces. I'm not sure what the solids and shells are for, but they probably relate to the PartDesign workbench.


After dissecting the code for a couple hours more, I have a better grasp on what's going on. It should be possible to use things like arcs, lines, rectangles, etc, in order to create holes. What's weird though, is that actual sketch points don't seem to show up as vertices when searching for them the same way we search for the circles. And, what's worse, on the first look it appears this problem arises from the way the sketch is being broken down.


The method 'TopoShape Sketch::toShape()' does include the points when creating the TopoShape. It makes a compound, adds all the edges as wires, adds all the points as vertexes, and then creates a TopoShape and returns it. I'm not convinced the part design "based on sketch" code actually uses this, though. The two references to the 'toShape' method are the SketchObject::execute() and SketchObject::restoreFinished(), apparently. PartDesign uses "getVerifiedFace", which appears to use "ProfileBased::getProfileShape()".


I did actually get a basic mock-up working, just to sort of prove I learned some stuff. The part design method 'getProfileShape' does actually seem to include all sketch components, including the vertices that represent the points. It will be an interesting challenge to separate out single vertices from vertices connected to shapes and lines, but that's for after the basics are working.


The existing implementation seems to really want to rely on faces created from sketch elements. Which should ordinarily be a totally appropriate approach, since as far as I know there is not a single other PartDesign tool that makes use of single points.

Does not work without a continuous line to generate a face. Circle serves that purpose in this image, but a rectangle works just as well.

I kept running into a null input error in trying to remove the dependence on faces. These functions alone depend on the point-flawed 'getVerifiedFace' method.

  • getThroughAllLength

  • getReversedAngle

  • getProfileNormal

What is required, I think maybe, is to totally re-write the hole feature and remove the dependence on any faces. It should be enough to use the sketch plane itself, and it's odd that we aren't doing that to begin with. Another alternative may be to just include some way to handle point lists as a way to establish a "valid face". Aka, adding a condition in 'getVerifiedFace' to return a valid face of some kind, even when just fed some points. I don't really understand how that function works yet, however, and figuring it out has proven difficult. I've attempted to just add a break-point to the code there, and step through it, but that hasn't worked as of yet.


It's sort of annoying, but the basic holes actually appear when you use the hole feature preview. The error only happens after you try to apply the changes. Trying to specify a whole depth or counterbore doesn't work, though; at least without some kind of sketch face.


I figured out the whole code breakpoint issue and learned where it was throwing the error. There is a 'TopoShape::makeWires' method that complains if it's fed a null shape. And it's getting fed that from 'getVerifiedFace', when it tries to make edges in order to make faces. At this point, it instead needs to check if there are neither edges nor faces, and if so it should check for points. If points can be found, maybe make a face out of three of them or something? I think the easiest thing to do here would be to add a 'usePoints' parameter, since we know with the hole feature to expect a bunch of points.


A potential 'usePoints' parameter should just check if there aren't any valid faces, as per normal, but instead of erroring upon failing that it should make up something valid based on the points/vertices. Making it fail is as simple as adding a check for zero edges, in addition to zero wires or faces. No edges, faces, or wires, should only leave vertices.


The first thing that occurs to me is just to grab 3 points and make a face out of them. This would require them not being in the same axis, though, which isn't impossible. Another approach is to just make a random face centered on one of the points. As a shot in the dark, I tried just returning an empty face class. This seems like even a half decent solution until a better solution is discovered!

It might just be my debug build, but it seems like thread building is unnecessarily slow. Maybe a project for another time. It takes a minute or two just to make 3 threaded holes. This might also be an artifact of my changes, I'll have to look into it. If it's generating an extremely long helix for example, that could cause that issue.


158 views0 comments

Recent Posts

See All
bottom of page