Free CAD software by Makers for Makers.
Read more about MakerCAD and why I made it on my blog
Status updates are posted on discord
Build a software based CAD suite that provides:
- Relative geometry construction (build features relative to what you've already built)
- Parametric modeling (model based on modifiable parameters)
- Collaboration on modeling (git pull requests)
- Version control (also via git)
Long term goals:
- Build a code editor UI (a la OpenSCAD)
- Build a UI for non-coders
You can seek out help on our Discord server.
Find API documentation at pkg.go.dev
See our Contribution Guide
- OpenCascade CAD Kernel - Installing a binary package is recommended (compiling takes hours).
- occwrapper OpenCascade C wrapper to help make using OpenCascade with Go easier.
An extension for VSCode exists to help visualizing what you build:
The extension does require exporting model(s) to stl format (does not preclude exporting to other formats).
If this project is important to you, help:
- Encourage me by sharing what you have made with it (hashtag #makercad)
- Encourage others by sharing MakerCAD with the community
- Help monetarily buy me a coffee
- Share MakerCAD with the community
- Show off what you've built tagging #makercad
- Raise an issue for a problem you have encountered
- Submit a pull request for additions / changes / fixes you have worked on
Start a go project
mkdir myproject && go mod init [module-path]Add makercad dependency
go get github.com/marcuswu/makercadStart designing!
Start by creating an instance of MakerCad:
cad := makercad.NewMakerCad()Planes can be used for creating sketches or placing primitives
MyTopPlane := sketcher.NewPlaneParametersFromVectors(
sketcher.NewVectorFromValues(0, 0, 0), // Location (origin for the plane)
sketcher.NewVectorFromValues(0, 0, 1), // Normal (Z) direction vector
sketcher.NewVectorFromValues(1, 0, 0), // X Direction vector
)A plane can also be created from a face of a model
sketcher.NewPlaneParametersFromCoordinateSystem(aFace.Plane())There are also some origin planes predefined in MakerCAD:
type MakerCad struct {
sketches []*Sketch
FrontPlane *sketcher.PlaneParameters
BackPlane *sketcher.PlaneParameters
TopPlane *sketcher.PlaneParameters
BottomPlane *sketcher.PlaneParameters
LeftPlane *sketcher.PlaneParameters
RightPlane *sketcher.PlaneParameters
}Provide a plane to locate and orient the shape, its dimensions, and whether to center it on the location Specific global coordinates can be specified by altering the plane
block := cad.MakeBox(cad.TopPlane, width, depth, height, true | false)Provide a plane to locate and orient the shape and its radius and height. Cylinders are always centered on the plane origin
cylinder := cad.MakeCylinder(cad.TopPlane, radius, height)Boolean operations allow combining shapes to create more complex features on your model. These operations return a CadOperation from which the resulting shape can be retrieved.
op, err = cad.Combine(targetShape, makercad.ListOfShape{tools...})op, err = cad.Remove(targetShape, makercad.ListOfShape{tools...})Sketching allows for creation of more complex 3D shapes by drawing a 2D shape, optionally adding constraints and solving them, then extruding or revolving them to 3D shapes
A sketch may be created on a plane or a face of a shape:
sketch := cad.Sketch(plane | face)Lines are defined by start and end points
l1 := sketch.Line(startX, startY, endX, endY)Arcs are defined clockwise around a center point
arc1 := sketch.Arc(centerX, centerY, startX, startY, endX, endY)Circles are defined by a center point and a diameter (does not define a constraint)
circ1 := sketch.Circle(centerX, centerY, diameter)Sometimes it is not easy to determine the exact geometry when defining a sketch. In these cases, let the computer do the work. Define geometry close to what you need and specify constraints to define how the final geometry should relate.
| Method | Description |
|---|---|
| Coincident(Entity, Entity) | Ensure one entity lies on another entity (eg a point on a line) |
| PointVerticalDistance(*Point, Entity, float64) | Ensures a point is a specific distance along the Y axis from the specified entity |
| PointHorizontalDistance(*Point, Entity, float64) | Ensures a point is a specific distance along the X axis from the specified entity |
| PointProjectedDistance(*Point, Entity, float64) | Ensures that a point's projected distance along the normal of Entity is a specific distance |
| LineMidpoint(*Line, Entity) | Ensures entity is coincident with Line and halfway between its start and end points |
| LineAngle(*Line, *Line, float64) | Ensures the angle between two lines is the specified angle (in radians) |
| ArcLineTangent(*Arc, *Line) | Ensures the specified arc and line are tangent to one another |
| Distance(Entity, Entity, float64) | Ensures the two entities are the specified distance from each other |
| HorizontalLine(*Line) | Ensures the specified line is parallel with the X axis |
| HorizontalPoints(*Point, *Point) | Ensures the imaginary line segment between the two points specified is parallel with the X axis |
| VerticalLine(*Line) | Ensures the specified line is parallel with the X axis |
| VerticalPoints(*Point, *Point) | Ensures the imaginary line segment between the two points specified is parallel with the X axis |
| LineLength(*Line, float64) | Ensures the specified line has the indicated length |
| Equal(Entity, Entity) | Ensures the two entities are equal (lines the same length, circles the same diameter, etc) |
| CurveDiameter(Entity, float64) | Ensures the arc or circle specified has the indicated diameter |
Many of these constraints also have convenience functions on an entity. For instance to set a line's length:
line1.Length(10)Most of these convenience functions return the entity so they can be chained:
line1.Length(10).Horizontal()Runs the constraint solver algorithm. Returns an error should it be unable to solve.
err = sketch.Solve()Sketches can be overconstrained or underconstrained. The OverConstrained method returns a list of constraints that overdefine the problem:
fmt.PrintLn("Over constrained constraints: ", sketch.OverConstrained())An underconstrained sketch will have multiple solutions (often infinite).
A sketch can be converted to an SVG image:
sketch.LogDebug("sketch.svg")The constraint solver uses a graph based approach to simplifying the system of equations that are necessary to solve a sketch. If there is an issue with a sketch, logging the graph can be helpful in determining why:
sketch.ExportImage("sketch.dot")These .dot files can be visualized via GraphViz:
dot -Tsvg clustered.dot -o clustered.svgFirst, convert the sketch into a Face:
face1 := makercad.NewFace(sketch)Then it can be extruded or revolved
operation, err := face1.Extrude(distance)operation, err := face1.Revolve(axis, angleInRadians)With either of these, if combining via a boolean operation with an existing shape, it can be done in one step:
operation1, err := face1.ExtrudeMerging(distance, MergeType, makercad.ListOfShape{someOp.Shape()})
operation2, err := face2.ExtrudeMerging(distance, MergeType, makercad.ListOfShape{someOp.Shape()})A Shape can return its list of Faces:
shape1.Faces()A Face or list of Faces can return its list of Edges:
face1.Edges()
shape1.Faces().Edges()A list of Faces or Edges can be filtered and sorted:
someOperation.Shape().Faces().Edges().
IsCircle().
Matching(func(e *sketcher.Edge) bool {
return e.CircleRadius() == 5.8/2.
})Connecting the pieces:
block := cad.MakeBox(cad.TopPlane, blockWidth, blockWidth, blockHeight, true)
// Find the top face aligned with Z positive
faces := block.Faces().AlignedWith(cad.TopPlane)
faces.SortByZ(true)
topFace := faces[0]
sketch := cad.Sketch(topFace)
circle := sketch.Circle(0, 0, 5)
circle.Diameter(5)
circle.Center.Coincident(sketch.Origin())
err := sketch.Solve()
if err != nil {
// do something
}
face1 := makercad.NewFace(sketch)
newBlock, err = face1.ExtrudeMerging(-2, makercad.MergeTypeRemove, makercad.ListOfShape{block})MakerCAD can export to STL or STEP:
exports := makercad.ListOfShape{block}
cad.ExportStl("my-model.stl", exports, makercad.QualityHigh)
cad.ExportStep("my-model.step", exports)