CAD, From Scratch: MakerCAD

It’s likely that many of you use some form of CAD package, but how many of you have decided you didn’t like the software on offer? [Marcus Wu] did, and instead of griping, he wrote his own CAD software. It’s called MakerCAD, it’s published under an MIT licence, and you can try it yourself.

It’s written in Go, and it’s superficially similar to OpenSCAD in that the interface is through code. The similarity is skin deep though, as it provides the user with constraint solving as described in the video below the break.

As it stands it’s by no means feature complete, but it is now at a point at which it can be evaluated. Simple models can be created and exported as STEP files, so it can be used as a real-world CAD tool.

Whether it will flourish is down to the path it takes and how its community guides it. But we’re pleased to see any new open source projects in this space, which remains overly dominated by proprietary packages. If you try it, write up your experiences, we’d love to see how this develops.

29 thoughts on “CAD, From Scratch: MakerCAD

  1. Nice to see some normal design goals. Still insufficient for me and OpenCASCADE is a road to hell :)
    That’s why I’m working on my own code CAD based on SymPy and Manifold3D.
    Pros:
    – You can have free variables and use expression everywhere, not just in constraints. Constraints are just specific form of equations with prepared helpers/ctors.
    – Manifold3D library is infinitely times more robust than OpenCASCADE.
    – Model parts do not have to constitute DAG and are built at once (if there is exactly one solution) unless you want to reference some part of drawn geometry i.e. of result and use it for more computations/drawings, see below in cons:
    Cons:
    – No geometric primitives in result, no faces, lines, just mesh. But I’ll be giving it an ability to look for such features when you can’t provide their analytical model because it’s hard or because it is imported as mesh in a first place… Think “measuring tool” in modern slicers. This breaks models into multiple individual drawings which need to constitute DAG and each such drawing needs to have exactly one solution for free variables used there. This it the most interesting part of me and it is quite working on simple examples.

    1. Sounds like an interesting approach- quite curious to see how doing things symbolically work out in this context. I feel like it might fit the way may brain works.

      Don’t suppose you can share where you’ve got to with it?

    1. As the creator of MakerCAD, I agree and I have plans to keep it expressive while reducing the verbosity. I also intend to build a UI in the future which will provide a traditional interactive CAD producing the code behind the scenes, but without requiring the user to write it.

        1. It’s pretty hard to create a point & click interface that would output in human-readable code unless you perform the pointing and clicking operations exactly right in a proper order.

          There’s a general point in UI/UX design that you should not be able to effect the same thing in two completely different ways (e.g. by GUI and CLI) at the same time, because one messes up the other. In other words, you can write code that performs something impossible for the graphical interface, which breaks the latter because attempting to touch the same feature with your mouse cursor can then break your code.

          1. That’s exactly correct. The UI will generate code, but modify that code and the UI will not reflect those changes. I plan on using some annotations to allow the UI to be able to edit things it had generated in a previous session, but stray from that and you will have to continue editing code directly.

          2. Does it HAVE to be human readable?

            I mean, don’t get me wrong. If you could make a tool that generated perfect, human readable code and could also react gracefully to poorly written hand-written code allowing the user to go back and forth that would be great. It would probably also be unrealistic.

            But what if you dropped that requirement for perfection.

            Using the GUI you could design a part. It would spit out spaghetti that you could then drop into a module/function/method (whatever you call it in your language). That could then be part of a larger project made of handwritten code.

            Maybe the GUI could even allow for somewhat parameterized designs. The code it would spit out would be a module with the parameters.

          1. GUI driven CAD programs don’t work by procedural modeling (i.e. code) but by parametric/direct feature editing on the model itself.

            In other words, you, the user, performs the function of the code in creating and defining the list of basic features and their order of operations. Your actions in the GUI do not generate code, but the model hierarchy (or polygon faces etc.) directly.

            If you want the GUI to generate the code to generate the model hierarchy, you’re working across multiple levels of abstraction backwards and forwards. That’s a hard problem to solve, which is why the feature editing CAD programs only have a handful of basic operations you can perform.

          2. It seems like it should be possible to isolate direct code changes into a codeblock object in the edit list, and preserve the other UI-driven code changes in that edit list.

          3. The intent is to avoid / simplify the problem you describe. Instead of the hard problem of generating code for the user’s actions and then later interpreting that code to back to steps in CAD, it will only go one direction: From the interface’s direct feature editing to the code. The generated code will not be interpreted back into the UI steps. Instead, along with generating code, the UI generates some meta that describes the steps the user took in the interface. If the user leaves and comes back, when the model / code is loaded next, the UI displays the steps the metadata describes instead of interpreting the code. Think of the metadata as the native file format that most CAD software saves as.

            That pattern does put us in a situation where the code could be manually edited so that the metadata is not in sync with the code. To prevent that from being an issue, the metadata will include a marker (think checksum) that would indicate the code has been edited outside of the interface. In that case a warning would be displayed indicating that desync and that further edits may lose manual edits.

    2. ” way too much programming language like….”

      To each their own. I’ve been using OpenSCAD and the limitations it imposes in order to avoid being more programming language like really get under my skin sometimes. It just doesn’t do some of the things I want it to do.

      I have my own thoughts about moving away to something more programming language like but it is going to take me a while to get there.

  2. I agree with you about OpenCascade. It’s an API maze, a documenration desert, a performance hog, a legacy painful debt, and a compilation circus.
    That said it has LOTS of features, can handle complex geometric operations, and, most important: it evolves and improves !

    1. All of those things about OpenCascade. It is one of the most evolved open source brep CAD kernels right now, though. I have a roadmap for MakerCAD that will take me quite some time to complete. If no other CAD kernel exists in Go before I reach a point MakerCAD’s roadmap requires it, I may consider writing one to replace OpenCascade in MakerCAD.

      That’s exactly how dlineate came to be (the 2D constraint solver that MakerCAD uses). I used a different constraint solver until the project outgrew it and then wrote my own.

  3. neat! i love openscad because it’s a scripting language but i have complaints about its language and its implementation so i am always looking for alternatives. otoh, by this point i’ve gotten good enough at openscad that familiarity is its own cage :)

    using planes for orientation instead of prefixing each object with a nested sequence of translate/rotate/multmatrix is definitely thought-inspiring. i’m not sure if it’s six of one vs half a dozen of another or if it really allows more expression? i’m not clear how it interacts with everything else… the openscad orientation operators seem like a single mechanism while it seems like to replicate their functionality, planes will soak up some of that but some of it will still need a separate mechanism?

    i don’t know Go, but the examples give the impression that this isn’t so much a scripting language as a library that lets you define shapes in Go…the syntax itself is Go, right? pluses and minuses to that. it really constrains your possibilities for changing the implementation in the future, though. like if you want to parallelize it (as openscad has), then you will be struggling with that…though for all i know that particular struggle is solved for you by Go?

    constraints are definitely neat to think about! if i understand correctly, they might obviate a problem i solve fairly often in openscad — for example having the wall of a cube meet a cylinder tangent to its sides. of course, that one is trivial…having a cone meet a sphere is a little more difficult. i’m not sure if constraints would truly make this easy for me or if it would just replace one challenge (a bit of trig and algebra) with another (imaginative use of constraints).

    kind of neat that shapes are returned values instead of side-effects. and i bet it doesn’t have openscad’s awkward variables vs constants distinction, because it’s a real language. i’m not sure if it matters but if i was starting from 0 i’d probably go in makercad’s direction on this one!

    i’m kind of disappointed that it isn’t really “from scratch” — it’s “just” a wrapper for OpenCASCADE. i don’t have any attachment to the purity of “from scratch”, it’s just that if you look at openscad i think a lot of its downsides are inherited from OpenCSG. especially its abysmal performance. there was another CAD within a scripting language project a while back that interested me a lot more because it really was from scratch, so it used a novel representation of geometry that made it very different from what came before (and it solved the problem i’ll describe in the next paragraph) (but it was incomplete from my perspective so i didn’t use it either).

    the biggest thing that made me imagine abandoning openscad a few years ago is that there’s some shapes it just can’t really represent. what i really want is an operator like multmatrix, but that isn’t linear (isn’t a matrix of coefficients). i want to be able to specify arbitrary algebra to apply to the points of one of the primitives. in fact, i’d like to apply algebra to each point along a line, not just to its endpoints. i’m not convinced MakerCAD improves at all for this struggle?

    but since then, i’ve become a lot better at openscad and i don’t mind making a shape that openscad doesn’t know natively by breaking it into a bunch of smaller pieces that are each one of openscad’s primitives. like specifying a compound curve using a for loop iterating over rectangular prisms. so that pretty much removed my incentive to learn something new :)

    anyways, best of luck to you!

    1. Planes are one way to go, but you can also use a face of an existing shape to create a sketch or primitive from.

      You’re absolutely correct about Go and MakerCAD’s relationship. The language and syntax is Go and MakerCAD is a library / package for doing CAD work. Yes, parallelization would be handled through Go’s mechanisms. I am not sure how much of that is necessary, but as others and I build more complex things with MakerCAD perhaps it will become so.

      Yes, constraints are definitely there to solve math issues that are harder to by hand. In the miwa vise block example (https://github.com/marcuswu/miwa-vise-block) I create a sketch where I want to cut a channel within a circular cut, so the walls are basically cords across the circular shape including arcs that are subsets of the larger circle. Calculating the points for those cords and arcs could be done by hand or with formulas in the Go code, but instead I can simply define my intent to the sketcher and let it solve it for me.

      Yeah, OpenCascade was kind of a leg up for the project. It was one of the few open source brep based cad kernels I could find. Perhaps I will eventually reach a point with this that I take the hit to write my own cad kernel in Go.

      Are you talking about mathematically defining splines? Currently MakerCAD does not have spline support, but it is definitely a feature I would plan to add.

      It sounds like you are doing some very cool things with OpenSCAD. I’d love to see what you might come up with using MakerCAD. If you try it out and find specific things you want added, I’d love to hear about them.

      Finally, thank you for such a thought out and insightful comment!

      1. yeah splines are one of the uses. i’ve actually been struggling in my head since writing that comment to put my finger on how to explain the transform that i feel is missing. i’ve had specific needs in the past but they’ve passed out of my mind. but basically what i want is like to twist…

        like multmatrix in openscad can do rotations, roughly:

        x' = cos(theta)*x + sin(theta)*y
        y' = -sin(theta)*x + cos(theta)*y
        

        sin/cos are just linear coefficients in the matrix. but what if they depended also on z, but not linearly? a twist:

        x' = cos(theta*z)*x + sin(theta*z)*y
        y' = -sin(theta*z)*x + cos(theta*z)*y
        

        it has two parts that dramatically exceed openscad’s capability…first, the non-linearity (z isn’t just multiplied by a coefficient and added). and the second one is even harder…like if you transform a cube, it just has the 8 points at its corners, so the lines don’t get twisted in between those points. in fact, a 360 degree twist over the whole depth of the cube would be a no-op, it would become a square cube again.

        when i first came across this need, i threw up my hands in failure. today, i would just

        for (i = [0:layer_height:depth]) {
        translate([0,0,i]) rotate([0,0,(i/depth)*theta]) cube([width,height,layer_height+0.01]);
        }
        

        a big hack :)

        an oddball requirement, for sure. i don’t mean to discourage you that you didn’t solve it but it’s still something i’m looking for

        fwiw, the tool i found that seemed like it would do an operation like that used a totally bizarre representation. an object wasn’t defined by its vertices or faces but rather by a formula, and if the formula’s value is less than 1, then you are inside the object. more than 1 and you are outside of it. an r=1 sphere is really easy:

        formula(x,y,z) = x^2+y^2+z^2
        

        a cube is easy too but i can’t do it off the top of my head. it’s not at all obvious how to use it — steep learning curve — but once you master the basic idioms of it, there’s really no limit :)

        1. It sounds like some of this could be done with a sweep along a spline — define your shape, define your 3D spline, and sweep that shape along the spline into a 3D shape. It’s another piece of functionality I would like to bring to MakerCAD. I will probably work on an interface first, but sweep operations are on the list.

          1. yeah! sweep! (i had to look it up) that’s the typical cad operator that would do the twist, at least. i like to think geometrically rather than “cad style”, or in other words, CSG instead of BREP. so i want something more generic and probably clunkier to actually use. but yeah sweep is how real cad guys do it :)

  4. Nice to see the program come to life. I was also quite surprised to see it was for a Miwa lock, and guessed you wanted it to aid lockpicking. It didn’t take much to find the details, as we move in similar circles. It’s a curious tool, but to use it you first need to learn CAD, and understand what features do before you apply them. It’d be nicer to have the features in OpenSCAD, though. Or as the Close caption says, ‘open S cat’.

    1. I really just got into locksport at the beginning of the year — my brother gave me a lock pick set for Christmas and I have been digging deeper and deeper. I have seemed to plateau a little bit at purple belt, but I’m not sure I have great locks for brown belt.

      OpenSCAD uses an entirely different internal representation for modeling called CSG whereas MakerCAD uses OpenCascade which uses Brep (boundary representation). Doing what MakerCAD does through OpenSCAD would require internal conversion from CSG to Brep which is non-trivial. This is one of the (many) reasons I ultimately ended up writing my own.

      1. I’m far from a skilled programmer, and wouldn’t know where to start with building a CAD program. :) I’m, however, quite deep into lockpicking, and have hundreds of designs in OpenSCAD to assist me. I’ve pinged you in the #3d printing in one of the servers we share.

Leave a Reply to marcuswu2Cancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.