Parametric Bomb Dice Using CADQuery

Download the pdf button

I have been keen to try my hand at parametric models using CADQuery. I felt a good test would be to translate the OpenSCAD Bomb Dice into CADQuery.

CADQuery Bomb Dice in CQ-Editor Interface

What surprised me was how much more tricky it would be. OpenSCAD has some rather nice features which I make heavy use of in my designs, namely Convex Hulls. At the time of this project the latest edition of CADQuery had introduced convex hulls as a function for 2D sketches. Unfortunately there were problems trying to use it and so I had to fall back on an older edition bundled with the CQ-Editor and create the shape outlines in a more manual fashion. So no nice easy shortcuts for me.

Once I got into the swing of creating the 2D shapes it was a powerful technique and yielded excellent outputs. Because 2D shapes formed the basis of most of the model, it became a very different beast from the OpenSCAD model where I could work directly with 3D shapes.

The big advantage of CADQuery over OpenSCAD is its ability to output STEP format models. This opened it to a greater number of engineering applications, especially here in New Zealand where CNC Machinist insist on working with STEP files. Of course the other major advantage is having the scripting might of python behind it.

Bomb Dice Parameters


Setting this to yes” will output the two model files BombDiceD6v0.step and BombDiceD6v0.stl into the directory where you‘ve placed the script.

Bomb shape Parameters (refer to the diagrams below)


The radius of the little tip bit of the bomb


The overall radius of the bomb’s main shell. This is also used for the radius of the other main hemispherical surfaces


The overall length of the bomb’s main body


The radius of the rounded hemisphere on the tail end of the main bomb body


The length of the little tip bit at the top of the bomb body


The angle of the bomb body bottom end cone


The number of fins


The thickness of the fins


Outer edge of the fins. This is also used to set the radius of the tail ring


Inner edge of the fins


Distance between the bottom-most point of the fins and the bottom-most end of the main bomb body. The bottom edge of the tail ring is in line with this too.


Angle of the fin leading edge


Angle of the fin trailing edge


The length of the tail ring


The section thickness of the tail ring


Radial distance to shift the bomb units outwards

Variables for Face Ring (see diagrams below)


Outer rim diameter of the main face ring


Width of the main face ring band


Thickness of the main face ring


Height that the details segments project above the surface of the main ring


Angle covered by detail segment


Number of detail segments


Diameter of the bolt head on the detail segment


Distance of the face mid-plane out from the centre of the cube.

Text Parameters


The name of any font you have on your system that you want to use.


The size of the letter


The amount the letter is extruded by


A factor to adjust the position of the letter vertically


A factor to adjust the position of the letter horizontally


A list of the six text items you want to see on the dice faces. You can put anything in here. The default is the six numbers of a balanced dice ["1","6","3","4","2","5"]

Click on the images below for a higher resolution version.

CADQuery Bomb Dice Parameters - Bomb Details

CADQuery Bomb Dice Parameters - Other Stuff

The Code

In a shameless attempt to increase the page count for this article and potentially absorb a few more google hits, here is the listing (just mind the word wrap if copying this from the pdf). You can download the code from here:

import cadquery
from cadquery import exporters
from math import sin, cos, tan, pi, acos, atan2

RenderYN = "no"  #Render to file (yes/no)?

#Bomb shape Parameters
LittleR = 1
OuterR = 6
BLen = 40
BotR = 2
BLenLitl = 1.6
ConeAng = 30

FinNos = 4
FinThk = 1
FinOR = 8
FinIR = 1
FinBaseBelow = 4
FinLeadAng = 60
FinTrailAng = 45
TailRingDpth = 8
TailRingThk = 1

OutwardAdj = 15

#Variables for Face Ring
OuterRimD = 50
RimWdth = 8
FaceThk = 2.5
DetailHt = 0.5
DetSegAngle = 35    #Angle covered by detail segment
DetNos = 7      #Number of detail segments
BoltD = 4

FaceOutDist = 25

Bombfont = "Walshes Outline"#["MetropolitainesD", "ZapfChan Bd BT","Xtraflexidisc", "Liberation Sans:style=Italic", "Liberation Mono", "Liberation Serif"]
#"WeddingText BT","Walshes Outline","Vertigo Upright BRK","Vanilla Whale","Ubiquity BRK","Top Bond","TimeScrDBol","Stencil","StayPuft",
#"Snap ITC","Showcard Gothic","Colonna MT"

LettrSiz = 52
LetHt = 6
LetVPozAdj = 0.00  # A factor to adjust the position of the letter vertically
LetHPozAdj = -0.04

FaceTXTList = ["1","6","3","4","2","5"]

def BombSpikes():
    BombBody = (cadquery.Workplane("front")
                 .radiusArc((BotR*cos(ConeAng*pi/180),BotR*(1-sin(ConeAng*pi/180))), -BotR)
                 .radiusArc((OuterR,(OuterR-BotR)*(1+1/sin(ConeAng*pi/180))), -OuterR)
                 .radiusArc((LittleR,BLen-BLenLitl), -OuterR)
    BombFin = (cadquery.Workplane("front")
    FinMass = BombFin
    for FinNo in range (1,FinNos):
        FinMass = FinMass.union(BombFin.rotate((0,1,0),(0,-1,0),360/FinNos*FinNo))
    BombTail = (cadquery.Workplane("front")
    BombUnit = BombBody.union(FinMass).union(BombTail)
    # Eight Diagonals
    b = acos(1/3**0.5)
    c = atan2(1,1)
    Diag1 = BombUnit.translate((0,OutwardAdj,0)).rotate((1,0,0),(-1,0,0),b*180/pi).rotate((0,1,0),(0,-1,0),c*180/pi)
    Diag2 = BombUnit.translate((0,OutwardAdj,0)).rotate((1,0,0),(-1,0,0),-b*180/pi).rotate((0,1,0),(0,-1,0),c*180/pi)
    Diag3 = BombUnit.translate((0,OutwardAdj,0)).rotate((1,0,0),(-1,0,0),-b*180/pi).rotate((0,1,0),(0,-1,0),-c*180/pi)
    Diag4 = BombUnit.translate((0,OutwardAdj,0)).rotate((1,0,0),(-1,0,0),b*180/pi).rotate((0,1,0),(0,-1,0),-c*180/pi)
    DiagSide1 = Diag1.union(Diag2).union(Diag3).union(Diag4)
    DiagSide2 = DiagSide1.rotate((0,0,1),(0,0,-1),180)
    Diags = DiagSide1.union(DiagSide2)

def FacePlate():
    BombFacePlate = (cadquery.Workplane("top")

    BombFaceDetail = (cadquery.Workplane("top")

    FaceBoltDetail = (cadquery.Workplane("top")
    #Build the FacePlate up from the parts
    BombFaceDetFul = BombFaceDetail.union(FaceBoltDetail)
    BombFaceDetFulMass = BombFaceDetFul
    for DetNo in range (1,DetNos):
        BombFaceDetFulMass = BombFaceDetFulMass.union(BombFaceDetFul.rotate((0,0,1),(0,0,-1),360/DetNos*DetNo))
    FaceSingle = BombFacePlate.union(BombFaceDetFulMass)

def FaceTXT(TNum):
    BombFaceTXT = (cadquery.Workplane("front")
                   .text(TNum,LettrSiz,LetHt,combine = True,font = Bombfont,kind = "regular",halign = 'center',valign = 'center')

def ComboFace():
    Face1 = FacePlate().union(FaceTXT(FaceTXTList[0])).translate((0,0,FaceOutDist)).rotate((1,0,0),(-1,0,0),90)
    Face2 = FacePlate().union(FaceTXT(FaceTXTList[1])).translate((0,0,FaceOutDist)).rotate((-1,0,0),(1,0,0),90)
    Face3 = FacePlate().union(FaceTXT(FaceTXTList[2])).translate((0,0,FaceOutDist)).rotate((0,1,0),(0,-1,0),90)
    Face4 = FacePlate().union(FaceTXT(FaceTXTList[3])).translate((0,0,FaceOutDist)).rotate((0,-1,0),(0,1,0),90)
    Face5 = FacePlate().union(FaceTXT(FaceTXTList[4])).translate((0,0,FaceOutDist))
    Face6 = FacePlate().union(FaceTXT(FaceTXTList[5])).translate((0,0,FaceOutDist)).rotate((0,-1,0),(0,1,0),180)

    FacesCombo = Face1.union(Face2).union(Face3).union(Face4).union(Face5).union(Face6)


D6BombDice = BombSpikes().union(ComboFace())


if RenderYN.lower() == "yes":
    exporters.export(D6BombDice, 'BombDiceD6v0.step')
    exporters.export(D6BombDice, 'BombDiceD6v0.stl')


And, here’s where you can download the CADQuery file.

and the bomb dice model in an STL or STEP file formats here;


Creative Commons by-sa

This design by Hamish Trolove is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.